diff options
author | Clifford Allan Jansen <cliffjansen@apache.org> | 2012-09-30 19:23:37 +0000 |
---|---|---|
committer | Clifford Allan Jansen <cliffjansen@apache.org> | 2012-09-30 19:23:37 +0000 |
commit | 694a0fb6c874a1bbf1d3eeeca6c18952a78b9f28 (patch) | |
tree | 7f3456ac3134c777c609d43fc53ae3d7feaf4fff /cpp/src | |
parent | 09818cb3d22e99ca30f1fafb7e296ba0b2e9f622 (diff) | |
download | qpid-python-694a0fb6c874a1bbf1d3eeeca6c18952a78b9f28.tar.gz |
QPID-4330: Windows static destructors: threadSafeShutdown() test
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk/qpid@1392093 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'cpp/src')
-rw-r--r-- | cpp/src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | cpp/src/Makefile.am | 2 | ||||
-rw-r--r-- | cpp/src/qpid/client/ConnectionImpl.cpp | 20 | ||||
-rw-r--r-- | cpp/src/qpid/client/windows/ClientDllMain.cpp | 22 | ||||
-rwxr-xr-x | cpp/src/qpid/sys/posix/SystemInfo.cpp | 7 | ||||
-rwxr-xr-x | cpp/src/qpid/sys/solaris/SystemInfo.cpp | 6 | ||||
-rw-r--r-- | cpp/src/qpid/sys/windows/QpidDllMain.h | 72 | ||||
-rw-r--r-- | cpp/src/qpid/sys/windows/Socket.cpp | 4 | ||||
-rwxr-xr-x | cpp/src/qpid/sys/windows/SystemInfo.cpp | 28 | ||||
-rwxr-xr-x | cpp/src/qpid/sys/windows/Thread.cpp | 23 |
10 files changed, 169 insertions, 16 deletions
diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index 21e82a97b9..299990a6e8 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -766,6 +766,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL Windows) ) set (qpidclient_platform_SOURCES ${sslclient_windows_SOURCES} + qpid/client/windows/ClientDllMain.cpp ) set (qpidclient_platform_LIBS ${windows_ssl_libs} diff --git a/cpp/src/Makefile.am b/cpp/src/Makefile.am index c39dd8114c..45c0d0fb77 100644 --- a/cpp/src/Makefile.am +++ b/cpp/src/Makefile.am @@ -25,6 +25,7 @@ SUBDIRS = . tests windows_dist = \ qpid/client/windows/SaslFactory.cpp \ qpid/client/windows/SslConnector.cpp \ + qpid/client/windows/ClientDllMain.cpp \ qpid/log/windows/SinkOptions.cpp \ qpid/log/windows/SinkOptions.h \ ../include/qpid/sys/windows/check.h \ @@ -42,6 +43,7 @@ windows_dist = \ qpid/sys/windows/PollableCondition.cpp \ qpid/sys/windows/PipeHandle.cpp \ ../include/qpid/sys/windows/Mutex.h \ + qpid/sys/windows/QpidDllMain.h \ qpid/sys/windows/Shlib.cpp \ qpid/sys/windows/SocketAddress.cpp \ qpid/sys/windows/Socket.cpp \ diff --git a/cpp/src/qpid/client/ConnectionImpl.cpp b/cpp/src/qpid/client/ConnectionImpl.cpp index 85b0e8303e..0abfbe09ec 100644 --- a/cpp/src/qpid/client/ConnectionImpl.cpp +++ b/cpp/src/qpid/client/ConnectionImpl.cpp @@ -128,15 +128,17 @@ public: // and we can't do that before we're unloaded as we can't // restart the Poller after shutting it down ~IOThread() { - std::vector<Thread> threads; - { - ScopedLock<Mutex> l(threadLock); - if (poller_) - poller_->shutdown(); - t.swap(threads); - } - for (std::vector<Thread>::iterator i = threads.begin(); i != threads.end(); ++i) { - i->join(); + if (SystemInfo::threadSafeShutdown()) { + std::vector<Thread> threads; + { + ScopedLock<Mutex> l(threadLock); + if (poller_) + poller_->shutdown(); + t.swap(threads); + } + for (std::vector<Thread>::iterator i = threads.begin(); i != threads.end(); ++i) { + i->join(); + } } } }; diff --git a/cpp/src/qpid/client/windows/ClientDllMain.cpp b/cpp/src/qpid/client/windows/ClientDllMain.cpp new file mode 100644 index 0000000000..d636489908 --- /dev/null +++ b/cpp/src/qpid/client/windows/ClientDllMain.cpp @@ -0,0 +1,22 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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/windows/QpidDllMain.h" diff --git a/cpp/src/qpid/sys/posix/SystemInfo.cpp b/cpp/src/qpid/sys/posix/SystemInfo.cpp index cfd2c64aee..dea74b4ab0 100755 --- a/cpp/src/qpid/sys/posix/SystemInfo.cpp +++ b/cpp/src/qpid/sys/posix/SystemInfo.cpp @@ -205,4 +205,11 @@ string SystemInfo::getProcessName() return value; } +// Always true. Only Windows has exception cases. +bool SystemInfo::threadSafeShutdown() +{ + return true; +} + + }} // namespace qpid::sys diff --git a/cpp/src/qpid/sys/solaris/SystemInfo.cpp b/cpp/src/qpid/sys/solaris/SystemInfo.cpp index e5856f55e6..d4b18e66c8 100755 --- a/cpp/src/qpid/sys/solaris/SystemInfo.cpp +++ b/cpp/src/qpid/sys/solaris/SystemInfo.cpp @@ -126,4 +126,10 @@ string SystemInfo::getProcessName() return value; } +// Always true. Only Windows has exception cases. +bool SystemInfo::threadSafeShutdown() +{ + return true; +} + }} // namespace qpid::sys diff --git a/cpp/src/qpid/sys/windows/QpidDllMain.h b/cpp/src/qpid/sys/windows/QpidDllMain.h new file mode 100644 index 0000000000..74eaf0256a --- /dev/null +++ b/cpp/src/qpid/sys/windows/QpidDllMain.h @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 this file once in each DLL that relies on SystemInfo.h: + * threadSafeShutdown(). Note that Thread.cpp has a more elaborate + * DllMain, that also provides this functionality separately. + * + * Teardown is in the reverse order of the DLL dependencies used + * during the load phase. The calls to DllMain and the static + * destructors are from the same thread, so no locking is necessary + * and there is no downside to an invocation of DllMain by multiple + * Qpid DLLs. + */ + +#ifdef _DLL + +#include <qpid/ImportExport.h> +#include <windows.h> + +namespace qpid { +namespace sys { +namespace windows { + +QPID_IMPORT bool processExiting; +QPID_IMPORT bool libraryUnloading; + +}}} // namespace qpid::sys::SystemInfo + + +BOOL APIENTRY DllMain(HMODULE hm, DWORD reason, LPVOID reserved) { + switch (reason) { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + + case DLL_PROCESS_DETACH: + // Remember how the process is terminating this DLL. + if (reserved != NULL) { + qpid::sys::windows::processExiting = true; + // Danger: all threading suspect, including indirect use of malloc or locks. + // Think twice before adding more functionality here. + return TRUE; + } + else { + qpid::sys::windows::libraryUnloading = true; + } + break; + } + return TRUE; +} + + +#endif diff --git a/cpp/src/qpid/sys/windows/Socket.cpp b/cpp/src/qpid/sys/windows/Socket.cpp index a4374260cc..17e3212a46 100644 --- a/cpp/src/qpid/sys/windows/Socket.cpp +++ b/cpp/src/qpid/sys/windows/Socket.cpp @@ -24,6 +24,7 @@ #include "qpid/sys/SocketAddress.h" #include "qpid/sys/windows/check.h" #include "qpid/sys/windows/IoHandlePrivate.h" +#include "qpid/sys/SystemInfo.h" // Ensure we get all of winsock2.h #ifndef _WIN32_WINNT @@ -67,7 +68,8 @@ public: } ~WinSockSetup() { - WSACleanup(); + if (SystemInfo::threadSafeShutdown()) + WSACleanup(); } public: diff --git a/cpp/src/qpid/sys/windows/SystemInfo.cpp b/cpp/src/qpid/sys/windows/SystemInfo.cpp index cef78dcc60..282bbb7e24 100755 --- a/cpp/src/qpid/sys/windows/SystemInfo.cpp +++ b/cpp/src/qpid/sys/windows/SystemInfo.cpp @@ -25,7 +25,8 @@ #include "qpid/sys/SystemInfo.h" #include "qpid/sys/IntegerTypes.h" -#include "qpid/Exception.h"
+#include "qpid/Exception.h" +#include "qpid/log/Statement.h" #include <assert.h> #include <winsock2.h> @@ -208,4 +209,29 @@ std::string SystemInfo::getProcessName() return name; } + +#ifdef _DLL +namespace windows { +// set from one or more Qpid DLLs: i.e. in DllMain with DLL_PROCESS_DETACH +QPID_EXPORT bool processExiting = false; +QPID_EXPORT bool libraryUnloading = false; +} +#endif + +bool SystemInfo::threadSafeShutdown() +{ +#ifdef _DLL + if (!windows::processExiting && !windows::libraryUnloading) { + // called before exit() or FreeLibrary(), or by a DLL without + // a participating DllMain. + QPID_LOG(warning, "invalid query for shutdown state"); + throw qpid::Exception(QPID_MSG("Unable to determine shutdown state.")); + } + return !windows::processExiting; +#else + // Not a DLL: shutdown can only be by exit() or return from main(). + return false; +#endif +} + }} // namespace qpid::sys diff --git a/cpp/src/qpid/sys/windows/Thread.cpp b/cpp/src/qpid/sys/windows/Thread.cpp index 23b0033be4..b342c9da1d 100755 --- a/cpp/src/qpid/sys/windows/Thread.cpp +++ b/cpp/src/qpid/sys/windows/Thread.cpp @@ -27,6 +27,7 @@ #include "qpid/sys/Thread.h" #include "qpid/sys/Runnable.h" #include "qpid/sys/windows/check.h" +#include "qpid/sys/SystemInfo.h" #include <process.h> #include <windows.h> @@ -274,8 +275,17 @@ Thread Thread::current() { #ifdef _DLL +namespace qpid { +namespace sys { +namespace windows { + +extern bool processExiting; +extern bool libraryUnloading; + +}}} // namespace qpid::sys::SystemInfo + // DllMain: called possibly many times in a process lifetime if dll -// loaded and freed repeatedly . Be mindful of Windows loader lock +// loaded and freed repeatedly. Be mindful of Windows loader lock // and other DllMain restrictions. BOOL APIENTRY DllMain(HMODULE hm, DWORD reason, LPVOID reserved) { @@ -290,10 +300,12 @@ BOOL APIENTRY DllMain(HMODULE hm, DWORD reason, LPVOID reserved) { if (reserved != NULL) { // process exit(): threads are stopped arbitrarily and // possibly in an inconsistent state. Not even threadLock - // can be trusted. All static destructors have been - // called at this point and any resources this unit knows - // about will be released as part of process tear down by - // the OS. Accordingly, do nothing. + // can be trusted. All static destructors for this unit + // are pending and face the same unsafe environment. + // Any resources this unit knows about will be released as + // part of process tear down by the OS. Accordingly, skip + // any clean up tasks. + qpid::sys::windows::processExiting = true; return TRUE; } else { @@ -301,6 +313,7 @@ BOOL APIENTRY DllMain(HMODULE hm, DWORD reason, LPVOID reserved) { // encouraged to clean up to avoid leaks. Mostly we just // want any straggler threads to finish and notify // threadsDone as the last thing they do. + qpid::sys::windows::libraryUnloading = true; while (1) { { ScopedCriticalSection l(threadLock); |