diff options
author | Andrew Stitcher <astitcher@apache.org> | 2009-12-15 18:24:02 +0000 |
---|---|---|
committer | Andrew Stitcher <astitcher@apache.org> | 2009-12-15 18:24:02 +0000 |
commit | 6ef9706fc3d447768b4d0d2b0cee8bea828677bd (patch) | |
tree | 40d7fac865993be7c3eedf78eb1c2de39d4bcb08 | |
parent | 631669149ac891c8551040185326f58fbbc2a3cf (diff) | |
download | qpid-python-6ef9706fc3d447768b4d0d2b0cee8bea828677bd.tar.gz |
QPID-1951: Removed need for Windows versions of ssize_t and pid_t
- Trivially removed Windows uses of ssize_t
- Rearchitected how the Windows port finds an existing qpidd to stop it
- Split Posix Lockfile functionality using pids into a new PidFile class
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@890929 13f79535-47bb-0310-9956-ffa450edef68
-rwxr-xr-x | qpid/cpp/include/qpid/sys/windows/IntegerTypes.h | 4 | ||||
-rw-r--r-- | qpid/cpp/src/Makefile.am | 1 | ||||
-rw-r--r-- | qpid/cpp/src/qpid/DataDir.cpp | 1 | ||||
-rw-r--r-- | qpid/cpp/src/qpid/DataDir.h | 5 | ||||
-rw-r--r-- | qpid/cpp/src/qpid/broker/Daemon.cpp | 14 | ||||
-rw-r--r-- | qpid/cpp/src/qpid/sys/LockFile.h | 29 | ||||
-rwxr-xr-x | qpid/cpp/src/qpid/sys/posix/LockFile.cpp | 42 | ||||
-rw-r--r-- | qpid/cpp/src/qpid/sys/posix/PidFile.h | 62 | ||||
-rwxr-xr-x | qpid/cpp/src/qpid/sys/windows/LockFile.cpp | 25 | ||||
-rw-r--r-- | qpid/cpp/src/tests/SocketProxy.h | 4 | ||||
-rw-r--r-- | qpid/cpp/src/windows/QpiddBroker.cpp | 191 |
11 files changed, 235 insertions, 143 deletions
diff --git a/qpid/cpp/include/qpid/sys/windows/IntegerTypes.h b/qpid/cpp/include/qpid/sys/windows/IntegerTypes.h index 7b2c57ad8e..ece1a618e9 100755 --- a/qpid/cpp/include/qpid/sys/windows/IntegerTypes.h +++ b/qpid/cpp/include/qpid/sys/windows/IntegerTypes.h @@ -21,8 +21,6 @@ * */ -#include <BaseTsd.h> /* Windows system types */ - typedef unsigned char uint8_t; typedef char int8_t; typedef unsigned short uint16_t; @@ -33,8 +31,6 @@ typedef unsigned __int64 uint64_t; typedef __int64 int64_t; // Visual Studio doesn't define other common types, so set them up here too. -typedef int pid_t; -typedef SSIZE_T ssize_t; typedef unsigned int uint; #endif /*!QPID_SYS_WINDOWS_INTEGERTYPES_H*/ diff --git a/qpid/cpp/src/Makefile.am b/qpid/cpp/src/Makefile.am index 9adbbb6bf6..4979aaf926 100644 --- a/qpid/cpp/src/Makefile.am +++ b/qpid/cpp/src/Makefile.am @@ -154,6 +154,7 @@ libqpidcommon_la_SOURCES += \ qpid/sys/posix/Fork.cpp \ qpid/sys/posix/StrError.cpp \ qpid/sys/posix/PollableCondition.cpp \ + qpid/sys/posix/PidFile.h \ qpid/sys/posix/PipeHandle.cpp \ qpid/log/posix/SinkOptions.h \ qpid/sys/posix/Fork.h diff --git a/qpid/cpp/src/qpid/DataDir.cpp b/qpid/cpp/src/qpid/DataDir.cpp index 0ee30709af..ad732052ab 100644 --- a/qpid/cpp/src/qpid/DataDir.cpp +++ b/qpid/cpp/src/qpid/DataDir.cpp @@ -22,6 +22,7 @@ #include "qpid/DataDir.h" #include "qpid/log/Statement.h" #include "qpid/sys/FileSysDir.h" +#include "qpid/sys/LockFile.h" namespace qpid { diff --git a/qpid/cpp/src/qpid/DataDir.h b/qpid/cpp/src/qpid/DataDir.h index dfdd498cbc..828299f3ba 100644 --- a/qpid/cpp/src/qpid/DataDir.h +++ b/qpid/cpp/src/qpid/DataDir.h @@ -23,11 +23,14 @@ #include <string> #include <memory> -#include "qpid/sys/LockFile.h" #include "qpid/CommonImportExport.h" namespace qpid { + namespace sys { + class LockFile; + } + /** * DataDir class. */ diff --git a/qpid/cpp/src/qpid/broker/Daemon.cpp b/qpid/cpp/src/qpid/broker/Daemon.cpp index e1d400e01b..b30e5f18cb 100644 --- a/qpid/cpp/src/qpid/broker/Daemon.cpp +++ b/qpid/cpp/src/qpid/broker/Daemon.cpp @@ -15,10 +15,16 @@ * limitations under the License. * */ + +/* + * TODO: Note this is really a Posix specific implementation and so should be + * refactored together with windows/QpiddBroker into a more coherent daemon driver/ + * platform specific split + */ #include "qpid/broker/Daemon.h" #include "qpid/log/Statement.h" #include "qpid/Exception.h" -#include "qpid/sys/LockFile.h" +#include "qpid/sys/posix/PidFile.h" #include <errno.h> #include <fcntl.h> @@ -31,7 +37,7 @@ namespace qpid { namespace broker { using namespace std; -using qpid::sys::LockFile; +using qpid::sys::PidFile; Daemon::Daemon(std::string _pidDir) : pidDir(_pidDir) { struct stat s; @@ -176,7 +182,7 @@ uint16_t Daemon::wait(int timeout) { // parent waits for child. */ void Daemon::ready(uint16_t port) { // child lockFile = pidFile(pidDir, port); - LockFile lf(lockFile, true); + PidFile lf(lockFile, true); /* * Write the PID to the lockfile. @@ -200,7 +206,7 @@ void Daemon::ready(uint16_t port) { // child */ pid_t Daemon::getPid(string _pidDir, uint16_t port) { string name = pidFile(_pidDir, port); - LockFile lf(name, false); + PidFile lf(name, false); pid_t pid = lf.readPid(); if (kill(pid, 0) < 0 && errno != EPERM) { unlink(name.c_str()); diff --git a/qpid/cpp/src/qpid/sys/LockFile.h b/qpid/cpp/src/qpid/sys/LockFile.h index 1f0a9e13b3..14a76cbf3e 100644 --- a/qpid/cpp/src/qpid/sys/LockFile.h +++ b/qpid/cpp/src/qpid/sys/LockFile.h @@ -29,7 +29,7 @@ namespace qpid { namespace sys { -class LockFilePrivate; +class LockFilePrivate; /** * @class LockFile @@ -43,34 +43,17 @@ class LockFilePrivate; */ class LockFile : private boost::noncopyable { - boost::shared_ptr<LockFilePrivate> impl; - std::string path; bool created; + boost::shared_ptr<LockFilePrivate> impl; + +protected: + int read(void*, size_t) const; + int write(void*, size_t) const; public: QPID_COMMON_EXTERN LockFile(const std::string& path_, bool create); QPID_COMMON_EXTERN ~LockFile(); - - /** - * Read the process ID from the lock file. This method assumes that - * if there is a process ID in the file, it was written there by - * writePid(); thus, it's at the start of the file. - * - * Throws an exception if there is an error reading the file. - * - * @returns The stored process ID. No validity check is done on it. - */ - QPID_COMMON_EXTERN pid_t readPid(void) const; - - /** - * Write the current process's ID to the lock file. It's written at - * the start of the file and will overwrite any other content that - * may be in the file. - * - * Throws an exception if the write fails. - */ - QPID_COMMON_EXTERN void writePid(void); }; }} /* namespace qpid::sys */ diff --git a/qpid/cpp/src/qpid/sys/posix/LockFile.cpp b/qpid/cpp/src/qpid/sys/posix/LockFile.cpp index 4900252984..1862ff6ac9 100755 --- a/qpid/cpp/src/qpid/sys/posix/LockFile.cpp +++ b/qpid/cpp/src/qpid/sys/posix/LockFile.cpp @@ -17,6 +17,7 @@ */ #include "qpid/sys/LockFile.h" +#include "qpid/sys/posix/PidFile.h" #include <string> #include <unistd.h> @@ -31,6 +32,7 @@ namespace sys { class LockFilePrivate { friend class LockFile; + friend class PidFile; int fd; @@ -64,27 +66,43 @@ LockFile::~LockFile() { } } -pid_t LockFile::readPid(void) const { +int LockFile::read(void* bytes, size_t len) const { if (!impl) - throw Exception("Lock file not open"); + throw Exception("Lock file not open: " + path); - pid_t pid; - int desired_read = sizeof(pid_t); - if (desired_read > ::read(impl->fd, &pid, desired_read) ) { - throw Exception("Cannot read lock file " + path); + ssize_t rc = ::read(impl->fd, bytes, len); + if ((ssize_t)len > rc) { + throw Exception("Cannot read lock file: " + path); } - return pid; + return rc; } -void LockFile::writePid(void) { +int LockFile::write(void* bytes, size_t len) const { if (!impl) - throw Exception("Lock file not open"); + throw Exception("Lock file not open: " + path); + + ssize_t rc = ::write(impl->fd, bytes, len); + if ((ssize_t)len > rc) { + throw Exception("Cannot write lock file: " + path); + } + return rc; +} + +PidFile::PidFile(const std::string& path_, bool create): + LockFile(path_, create) +{} +pid_t PidFile::readPid(void) const { + pid_t pid; + int desired_read = sizeof(pid_t); + read(&pid, desired_read); + return pid; +} + +void PidFile::writePid(void) { pid_t pid = getpid(); int desired_write = sizeof(pid_t); - if (desired_write > ::write(impl->fd, &pid, desired_write)) { - throw Exception("Cannot write lock file " + path); - } + write(&pid, desired_write); } }} /* namespace qpid::sys */ diff --git a/qpid/cpp/src/qpid/sys/posix/PidFile.h b/qpid/cpp/src/qpid/sys/posix/PidFile.h new file mode 100644 index 0000000000..fb19d407f4 --- /dev/null +++ b/qpid/cpp/src/qpid/sys/posix/PidFile.h @@ -0,0 +1,62 @@ +#ifndef _sys_PidFile_h +#define _sys_PidFile_h + +/* + * + * Copyright (c) 2008 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "qpid/sys/LockFile.h" + +#include "qpid/CommonImportExport.h" +#include "qpid/sys/IntegerTypes.h" + +#include <boost/noncopyable.hpp> +#include <boost/shared_ptr.hpp> +#include <string> + +namespace qpid { +namespace sys { + +class PidFile : public LockFile +{ +public: + QPID_COMMON_EXTERN PidFile(const std::string& path_, bool create); + + /** + * Read the process ID from the lock file. This method assumes that + * if there is a process ID in the file, it was written there by + * writePid(); thus, it's at the start of the file. + * + * Throws an exception if there is an error reading the file. + * + * @returns The stored process ID. No validity check is done on it. + */ + QPID_COMMON_EXTERN pid_t readPid(void) const; + + /** + * Write the current process's ID to the lock file. It's written at + * the start of the file and will overwrite any other content that + * may be in the file. + * + * Throws an exception if the write fails. + */ + QPID_COMMON_EXTERN void writePid(void); +}; + +}} /* namespace qpid::sys */ + +#endif /*!_sys_PidFile_h*/ diff --git a/qpid/cpp/src/qpid/sys/windows/LockFile.cpp b/qpid/cpp/src/qpid/sys/windows/LockFile.cpp index e9079b6094..e9fe01ca72 100755 --- a/qpid/cpp/src/qpid/sys/windows/LockFile.cpp +++ b/qpid/cpp/src/qpid/sys/windows/LockFile.cpp @@ -56,29 +56,4 @@ LockFile::~LockFile() { } } -pid_t LockFile::readPid(void) const { - if (!impl) - throw Exception("Lock file not open"); - - pid_t pid; - DWORD desired_read = sizeof(pid_t); - DWORD actual_read = 0; - if (!ReadFile(impl->fd, &pid, desired_read, &actual_read, 0)) { - throw Exception("Cannot read lock file " + path); - } - return pid; -} - -void LockFile::writePid(void) { - if (!impl) - throw Exception("Lock file not open"); - - pid_t pid = GetCurrentProcessId(); - DWORD desired_write = sizeof(pid_t); - DWORD written = 0; - if (!WriteFile(impl->fd, &pid, desired_write, &written, 0)) { - throw Exception("Cannot write lock file " + path); - } -} - }} /* namespace qpid::sys */ diff --git a/qpid/cpp/src/tests/SocketProxy.h b/qpid/cpp/src/tests/SocketProxy.h index df243cb42a..4582dc36fd 100644 --- a/qpid/cpp/src/tests/SocketProxy.h +++ b/qpid/cpp/src/tests/SocketProxy.h @@ -141,12 +141,12 @@ class SocketProxy : private qpid::sys::Runnable } // Something is set; relay data as needed until something closes if (FD_ISSET(server->getFd(), &socks)) { - ssize_t n = server->read(buffer, sizeof(buffer)); + int n = server->read(buffer, sizeof(buffer)); throwIf(n <= 0, "SocketProxy: server disconnected"); if (!dropServer) client.write(buffer, n); } if (FD_ISSET(client.getFd(), &socks)) { - ssize_t n = client.read(buffer, sizeof(buffer)); + int n = client.read(buffer, sizeof(buffer)); throwIf(n <= 0, "SocketProxy: client disconnected"); if (!dropServer) server->write(buffer, n); } diff --git a/qpid/cpp/src/windows/QpiddBroker.cpp b/qpid/cpp/src/windows/QpiddBroker.cpp index fc4f9f8a92..15380dda0b 100644 --- a/qpid/cpp/src/windows/QpiddBroker.cpp +++ b/qpid/cpp/src/windows/QpiddBroker.cpp @@ -34,7 +34,6 @@ const char *QPIDD_MODULE_DIR = "."; #include "qpid/Options.h" #include "qpid/Plugin.h" #include "qpid/sys/IntegerTypes.h" -#include "qpid/sys/LockFile.h" #include "qpid/sys/windows/check.h" #include "qpid/broker/Broker.h" @@ -59,74 +58,68 @@ namespace { const std::string TCP = "tcp"; -std::string brokerPidFile(std::string piddir, uint16_t port) -{ - std::ostringstream path; - path << piddir << "\\broker_" << port << ".pid"; - return path.str(); -} - // ShutdownEvent maintains an event that can be used to ask the broker // to stop. Analogous to sending SIGTERM/SIGINT to the posix broker. // The signal() method signals the event. class ShutdownEvent { public: - ShutdownEvent(pid_t other = 0); + ShutdownEvent(int port); ~ShutdownEvent(); + void create(); + void open(); void signal(); + private: + std::string eventName; + protected: - std::string eventName(pid_t pid); HANDLE event; }; class ShutdownHandler : public ShutdownEvent, public qpid::sys::Runnable { public: - ShutdownHandler(const boost::intrusive_ptr<Broker>& b) - : ShutdownEvent() { broker = b; } + ShutdownHandler(int port, const boost::intrusive_ptr<Broker>& b) + : ShutdownEvent(port) { broker = b; } private: virtual void run(); // Inherited from Runnable boost::intrusive_ptr<Broker> broker; }; -ShutdownEvent::ShutdownEvent(pid_t other) : event(NULL) { - // If given a pid, open an event assumedly created by that pid. If there's - // no pid, create a new event using the current process id. - if (other == 0) { - std::string name = eventName(GetCurrentProcessId()); - // Auto-reset event in case multiple processes try to signal a - // broker that doesn't respond for some reason. Initially not signaled. - event = CreateEvent(NULL, false, false, name.c_str()); - } - else { - std::string name = eventName(other); - event = OpenEvent(EVENT_MODIFY_STATE, false, name.c_str()); - } +ShutdownEvent::ShutdownEvent(int port) : event(NULL) { + std::ostringstream name; + name << "qpidd_" << port << std::ends; + eventName = name.str(); +} + +void ShutdownEvent::create() { + // Auto-reset event in case multiple processes try to signal a + // broker that doesn't respond for some reason. Initially not signaled. + event = ::CreateEvent(NULL, false, false, eventName.c_str()); + QPID_WINDOWS_CHECK_NULL(event); +} + +void ShutdownEvent::open() { + // TODO: Might need to search Global\\ name if unadorned name fails + event = ::OpenEvent(EVENT_MODIFY_STATE, false, eventName.c_str()); QPID_WINDOWS_CHECK_NULL(event); } ShutdownEvent::~ShutdownEvent() { - CloseHandle(event); + ::CloseHandle(event); event = NULL; } void ShutdownEvent::signal() { - QPID_WINDOWS_CHECK_NOT(SetEvent(event), 0); -} - -std::string ShutdownEvent::eventName(pid_t pid) { - std::ostringstream name; - name << "qpidd_" << pid << std::ends; - return name.str(); + QPID_WINDOWS_CHECK_NOT(::SetEvent(event), 0); } void ShutdownHandler::run() { if (event == NULL) return; - WaitForSingleObject(event, INFINITE); + ::WaitForSingleObject(event, INFINITE); if (broker.get()) { broker->shutdown(); broker = 0; // Release the broker reference @@ -134,19 +127,89 @@ void ShutdownHandler::run() { } // Console control handler to properly handle ctl-c. +int ourPort; BOOL CtrlHandler(DWORD ctl) { - ShutdownEvent shutter; // no pid specified == shut me down + ShutdownEvent shutter(ourPort); // We have to have set up the port before interrupting + shutter.open(); shutter.signal(); return ((ctl == CTRL_C_EVENT || ctl == CTRL_CLOSE_EVENT) ? TRUE : FALSE); } +template <typename T> +class NamedSharedMemory { + std::string name; + HANDLE memory; + T* data; + +public: + NamedSharedMemory(const std::string&); + ~NamedSharedMemory(); + + T& create(); + T& get(); +}; + +template <typename T> +NamedSharedMemory<T>::NamedSharedMemory(const std::string& n) : + name(n), + memory(NULL), + data(0) +{}; + +template <typename T> +NamedSharedMemory<T>::~NamedSharedMemory() { + if (data) + ::UnmapViewOfFile(data); + if (memory != NULL) + ::CloseHandle(memory); +}; + +template <typename T> +T& NamedSharedMemory<T>::create() { + assert(memory == NULL); + + // Create named shared memory file + memory = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(T), name.c_str()); + QPID_WINDOWS_CHECK_NULL(memory); + + // Map file into memory + data = static_cast<T*>(::MapViewOfFile(memory, FILE_MAP_WRITE, 0, 0, 0)); + QPID_WINDOWS_CHECK_NULL(data); + + return *data; +} + +template <typename T> +T& NamedSharedMemory<T>::get() { + if (memory == NULL) { + // TODO: Might need to search Global\\ name if unadorned name fails + memory = ::OpenFileMapping(FILE_MAP_WRITE, FALSE, name.c_str()); + QPID_WINDOWS_CHECK_NULL(memory); + + data = static_cast<T*>(::MapViewOfFile(memory, FILE_MAP_WRITE, 0, 0, 0)); + QPID_WINDOWS_CHECK_NULL(data); + } + + return *data; +} + +std::string brokerInfoName(uint16_t port) +{ + std::ostringstream path; + path << "qpidd_info_" << port; + return path.str(); +} + +struct BrokerInfo { + DWORD pid; +}; + } struct ProcessControlOptions : public qpid::Options { bool quit; bool check; - std::string piddir; //std::string transport; No transport options yet - TCP is it. ProcessControlOptions() @@ -154,18 +217,9 @@ struct ProcessControlOptions : public qpid::Options { quit(false), check(false) //, transport(TCP) { - const DWORD pathLen = MAX_PATH + 1; - char tempDir[pathLen]; - if (GetTempPath(pathLen, tempDir) == 0) - piddir = "C:\\WINDOWS\\TEMP\\"; - else - piddir = tempDir; - piddir += "qpidd"; - // Only have TCP for now, so don't need this... // ("transport", optValue(transport, "TRANSPORT"), "The transport for which to return the port") addOptions() - ("pid-dir", qpid::optValue(piddir, "DIR"), "Directory where port-specific PID file is stored") ("check,c", qpid::optValue(check), "Prints the broker's process ID to stdout and returns 0 if the broker is running, otherwise returns 1") ("quit,q", qpid::optValue(quit), "Tells the broker to shut down"); } @@ -207,57 +261,50 @@ int QpiddBroker::execute (QpiddOptions *options) { if (myOptions->control.check || myOptions->control.quit) { // Relies on port number being set via --port or QPID_PORT env variable. - qpid::sys::LockFile getPid (brokerPidFile(myOptions->control.piddir, - options->broker.port), - false); - pid_t pid = getPid.readPid(); + NamedSharedMemory<BrokerInfo> info(brokerInfoName(options->broker.port)); + int pid = info.get().pid; if (pid < 0) return 1; if (myOptions->control.check) std::cout << pid << std::endl; if (myOptions->control.quit) { - ShutdownEvent shutter(pid); - HANDLE brokerHandle = OpenProcess(SYNCHRONIZE, false, pid); - QPID_WINDOWS_CHECK_NULL(brokerHandle); + ShutdownEvent shutter(options->broker.port); + shutter.open(); shutter.signal(); - WaitForSingleObject(brokerHandle, INFINITE); - CloseHandle(brokerHandle); + HANDLE brokerHandle = ::OpenProcess(SYNCHRONIZE, false, pid); + QPID_WINDOWS_CHECK_NULL(brokerHandle); + ::WaitForSingleObject(brokerHandle, INFINITE); + ::CloseHandle(brokerHandle); } return 0; } boost::intrusive_ptr<Broker> brokerPtr(new Broker(options->broker)); - // Make sure the pid directory exists, creating if needed. LockFile - // will throw an exception that makes little sense if it can't create - // the file. - if (!CreateDirectory(myOptions->control.piddir.c_str(), 0)) { - DWORD err = GetLastError(); - if (err != ERROR_ALREADY_EXISTS) - throw qpid::Exception(QPID_MSG("Can't create pid-dir " + - myOptions->control.piddir + - ": " + - qpid::sys::strError(err))); - } // Need the correct port number to use in the pid file name. if (options->broker.port == 0) options->broker.port = brokerPtr->getPort(""); - qpid::sys::LockFile myPid(brokerPidFile(myOptions->control.piddir, - options->broker.port), - true); - myPid.writePid(); + + BrokerInfo info; + info.pid = ::GetCurrentProcessId(); + + NamedSharedMemory<BrokerInfo> sharedInfo(brokerInfoName(options->broker.port)); + sharedInfo.create() = info; // Allow the broker to receive a shutdown request via a qpidd --quit // command. Note that when the broker is run as a service this operation // should not be allowed. - - ShutdownHandler waitShut(brokerPtr); + ourPort = options->broker.port; + ShutdownHandler waitShut(ourPort, brokerPtr); + waitShut.create(); qpid::sys::Thread waitThr(waitShut); // Wait for shutdown event - SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE); + ::SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE); brokerPtr->accept(); std::cout << options->broker.port << std::endl; brokerPtr->run(); waitShut.signal(); // In case we shut down some other way waitThr.join(); + + // CloseHandle(h); return 0; } |