diff options
author | Stephen D. Huston <shuston@apache.org> | 2008-10-03 18:46:00 +0000 |
---|---|---|
committer | Stephen D. Huston <shuston@apache.org> | 2008-10-03 18:46:00 +0000 |
commit | 1555cda8e52e27be9ce9ee00026cf6f0e4507d28 (patch) | |
tree | b0e74b32303ae49e73828c28e9603a9fe41c058c /cpp/src | |
parent | c8fcdb008af74a937599a9b94ae169762bbc437d (diff) | |
download | qpid-python-1555cda8e52e27be9ce9ee00026cf6f0e4507d28.tar.gz |
Add Windows threading and synchronization primitives
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@701486 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'cpp/src')
-rw-r--r-- | cpp/src/qpid/sys/Condition.h | 2 | ||||
-rw-r--r-- | cpp/src/qpid/sys/Monitor.h | 2 | ||||
-rw-r--r-- | cpp/src/qpid/sys/Mutex.h | 2 | ||||
-rw-r--r-- | cpp/src/qpid/sys/Thread.h | 8 | ||||
-rwxr-xr-x | cpp/src/qpid/sys/windows/Condition.h | 82 | ||||
-rwxr-xr-x | cpp/src/qpid/sys/windows/Mutex.h | 188 | ||||
-rwxr-xr-x | cpp/src/qpid/sys/windows/Thread.cpp | 88 | ||||
-rwxr-xr-x | cpp/src/qpid/sys/windows/check.h | 48 |
8 files changed, 418 insertions, 2 deletions
diff --git a/cpp/src/qpid/sys/Condition.h b/cpp/src/qpid/sys/Condition.h index 961c15e1ee..fe0e3a1c71 100644 --- a/cpp/src/qpid/sys/Condition.h +++ b/cpp/src/qpid/sys/Condition.h @@ -24,6 +24,8 @@ #ifdef USE_APR_PLATFORM #include "apr/Condition.h" +#elif defined (_WIN32) +#include "windows/Condition.h" #else #include "posix/Condition.h" #endif diff --git a/cpp/src/qpid/sys/Monitor.h b/cpp/src/qpid/sys/Monitor.h index 1d9835675c..2dd405efaf 100644 --- a/cpp/src/qpid/sys/Monitor.h +++ b/cpp/src/qpid/sys/Monitor.h @@ -22,7 +22,6 @@ * */ -#include <sys/errno.h> #include "Condition.h" namespace qpid { @@ -33,7 +32,6 @@ namespace sys { */ class Monitor : public Mutex, public Condition { public: - using Condition::wait; inline void wait(); inline bool wait(const AbsTime& absoluteTime); }; diff --git a/cpp/src/qpid/sys/Mutex.h b/cpp/src/qpid/sys/Mutex.h index b4bd3a9b4a..00bf392604 100644 --- a/cpp/src/qpid/sys/Mutex.h +++ b/cpp/src/qpid/sys/Mutex.h @@ -82,6 +82,8 @@ class ConditionalScopedLock #ifdef USE_APR_PLATFORM #include "apr/Mutex.h" +#elif defined (_WIN32) +#include "windows/Mutex.h" #else #include "posix/Mutex.h" #endif diff --git a/cpp/src/qpid/sys/Thread.h b/cpp/src/qpid/sys/Thread.h index 3188e45341..2fd59621d8 100644 --- a/cpp/src/qpid/sys/Thread.h +++ b/cpp/src/qpid/sys/Thread.h @@ -23,6 +23,14 @@ */ #include <boost/shared_ptr.hpp> +#ifdef _WIN32 +# define QPID_TSS __declspec(thread) +#elif defined (gcc) +# define QPID_TSS __thread +#else +# define QPID_TSS +#endif + namespace qpid { namespace sys { diff --git a/cpp/src/qpid/sys/windows/Condition.h b/cpp/src/qpid/sys/windows/Condition.h new file mode 100755 index 0000000000..e16fa2a176 --- /dev/null +++ b/cpp/src/qpid/sys/windows/Condition.h @@ -0,0 +1,82 @@ +#ifndef _sys_windows_Condition_h +#define _sys_windows_Condition_h + +/* + * + * 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/Mutex.h" +#include "qpid/sys/Time.h" + +#include <time.h> +#include <boost/noncopyable.hpp> +#include <boost/thread/condition.hpp> +#include <boost/thread/thread_time.hpp> +#include <windows.h> + +namespace qpid { +namespace sys { + +// Private Time related implementation details +void toPtime(boost::posix_time::ptime& pt, const AbsTime& t); + +/** + * A condition variable for thread synchronization. + */ +class Condition : private boost::noncopyable +{ + public: + inline Condition(); + inline ~Condition(); + inline void wait(Mutex&); + inline bool wait(Mutex&, const AbsTime& absoluteTime); + inline void notify(); + inline void notifyAll(); + + private: + boost::condition_variable_any condition; +}; + +Condition::Condition() { +} + +Condition::~Condition() { +} + +void Condition::wait(Mutex& mutex) { + condition.wait(mutex.mutex); +} + +bool Condition::wait(Mutex& mutex, const AbsTime& absoluteTime){ + boost::system_time st; + toPtime(st, absoluteTime); + return condition.timed_wait(mutex.mutex, st); +} + +void Condition::notify(){ + condition.notify_one(); +} + +void Condition::notifyAll(){ + condition.notify_all(); +} + +}} +#endif /*!_sys_windows_Condition_h*/ diff --git a/cpp/src/qpid/sys/windows/Mutex.h b/cpp/src/qpid/sys/windows/Mutex.h new file mode 100755 index 0000000000..08de0712b9 --- /dev/null +++ b/cpp/src/qpid/sys/windows/Mutex.h @@ -0,0 +1,188 @@ +#ifndef _sys_windows_Mutex_h +#define _sys_windows_Mutex_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 "check.h" + +#include <boost/version.hpp> +#if (BOOST_VERSION < 103500) +#error The Windows port requires Boost version 1.35.0 or later +#endif + +#include <boost/noncopyable.hpp> +#include <boost/thread/recursive_mutex.hpp> +#include <boost/thread/shared_mutex.hpp> +#include <boost/thread/thread_time.hpp> +#include <boost/thread/tss.hpp> + +namespace qpid { +namespace sys { + +class Condition; + +/** + * Mutex lock. + */ +class Mutex : private boost::noncopyable { + friend class Condition; + +public: + typedef ::qpid::sys::ScopedLock<Mutex> ScopedLock; + typedef ::qpid::sys::ScopedUnlock<Mutex> ScopedUnlock; + + inline Mutex(); + inline ~Mutex(); + inline void lock(); + inline void unlock(); + inline bool trylock(); + + +protected: + boost::recursive_mutex mutex; +}; + +/** + * RW lock. + */ +class RWlock : private boost::noncopyable { + friend class Condition; + +public: + typedef ::qpid::sys::ScopedRlock<RWlock> ScopedRlock; + typedef ::qpid::sys::ScopedWlock<RWlock> ScopedWlock; + + inline RWlock(); + inline ~RWlock(); + inline void wlock(); // will write-lock + inline void rlock(); // will read-lock + inline void unlock(); + inline void trywlock(); // will write-try + inline void tryrlock(); // will read-try + +protected: + boost::shared_mutex rwMutex; + boost::thread_specific_ptr<bool> haveWrite; + + inline bool &write (void); +}; + + +/** + * PODMutex is a POD, can be static-initialized with + * PODMutex m = QPID_PODMUTEX_INITIALIZER + */ +struct PODMutex +{ + typedef ::qpid::sys::ScopedLock<PODMutex> ScopedLock; + + inline void lock(); + inline void unlock(); + inline bool trylock(); + + // Must be public to be a POD: + boost::recursive_mutex mutex; +}; + +#define QPID_MUTEX_INITIALIZER 0 + +void PODMutex::lock() { + mutex.lock(); +} + +void PODMutex::unlock() { + mutex.unlock(); +} + +bool PODMutex::trylock() { + return mutex.try_lock(); +} + +Mutex::Mutex() { +} + +Mutex::~Mutex(){ +} + +void Mutex::lock() { + mutex.lock(); +} + +void Mutex::unlock() { + mutex.unlock(); +} + +bool Mutex::trylock() { + return mutex.try_lock(); +} + + +RWlock::RWlock() { +} + +RWlock::~RWlock(){ +} + +void RWlock::wlock() { + bool &writer = write(); + rwMutex.lock(); + writer = true; // Remember this thread has write lock held. +} + +void RWlock::rlock() { + bool &writer = write(); + rwMutex.lock_shared(); + writer = false; // Remember this thread has shared lock held. +} + +void RWlock::unlock() { + bool &writer = write(); + if (writer) + rwMutex.unlock(); + else + rwMutex.unlock_shared(); +} + +void RWlock::trywlock() { + bool &writer = write(); + // shared_mutex::try_lock() seems to not be available... emulate it with + // a timed lock(). + boost::system_time now = boost::get_system_time(); + if (rwMutex.timed_lock(now)) + writer = true; +} + +void RWlock::tryrlock() { + bool &writer = write(); + if (rwMutex.try_lock_shared()) + writer = false; +} + +bool & RWlock::write (void) { + // Accessing thread-specific and stack-local info, so no locks needed. + bool *writePtr = haveWrite.get(); + if (writePtr == 0) { + writePtr = new bool(false); + haveWrite.reset(writePtr); + } + return *writePtr; +} + +}} +#endif /*!_sys_windows_Mutex_h*/ diff --git a/cpp/src/qpid/sys/windows/Thread.cpp b/cpp/src/qpid/sys/windows/Thread.cpp new file mode 100755 index 0000000000..6d5d78393e --- /dev/null +++ b/cpp/src/qpid/sys/windows/Thread.cpp @@ -0,0 +1,88 @@ +/* + * + * 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/Thread.h" +#include "qpid/sys/Runnable.h" +#include "check.h" + +#include <process.h> +#include <windows.h> + +namespace { +unsigned __stdcall runRunnable(void* p) +{ + static_cast<qpid::sys::Runnable*>(p)->run(); + _endthreadex(0); + return 0; +} +} + +namespace qpid { +namespace sys { + +class ThreadPrivate { + friend class Thread; + + HANDLE threadHandle; + unsigned threadId; + + ThreadPrivate(Runnable* runnable) { + uintptr_t h = _beginthreadex(0, + 0, + runRunnable, + runnable, + 0, + &threadId); + QPID_WINDOWS_CHECK_CRT_NZ(h); + threadHandle = reinterpret_cast<HANDLE>(h); + } + + ThreadPrivate() + : threadHandle(GetCurrentThread()), threadId(GetCurrentThreadId()) {} +}; + +Thread::Thread() {} + +Thread::Thread(Runnable* runnable) : impl(new ThreadPrivate(runnable)) {} + +Thread::Thread(Runnable& runnable) : impl(new ThreadPrivate(&runnable)) {} + +void Thread::join() { + if (impl) { + DWORD status = WaitForSingleObject (impl->threadHandle, INFINITE); + QPID_WINDOWS_CHECK_NOT(status, WAIT_FAILED); + CloseHandle (impl->threadHandle); + impl->threadHandle = 0; + } +} + +unsigned long Thread::id() { + return impl ? impl->threadId : 0; +} + +/* static */ +Thread Thread::current() { + Thread t; + t.impl.reset(new ThreadPrivate()); + return t; +} + +}} /* qpid::sys */ diff --git a/cpp/src/qpid/sys/windows/check.h b/cpp/src/qpid/sys/windows/check.h new file mode 100755 index 0000000000..aba38814b2 --- /dev/null +++ b/cpp/src/qpid/sys/windows/check.h @@ -0,0 +1,48 @@ +#ifndef _windows_check_h +#define _windows_check_h + +/* + * + * 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/Exception.h" +#include "qpid/sys/StrError.h" + +#define QPID_WINDOWS_ERROR(ERRVAL) qpid::Exception(QPID_MSG(qpid::sys::strError(ERRVAL))) +#define QPID_WINDOWS_CRT_ERROR(ERRNO) qpid::Exception(QPID_MSG(qpid::sys::strError(ERRNO))) + +/** THROW QPID_WINDOWS_ERROR(::GetLastError()) if RESULT is NULL */ +#define QPID_WINDOWS_CHECK_NULL(RESULT) \ + if ((RESULT) == NULL) throw QPID_WINDOWS_ERROR((::GetLastError())) + +#define QPID_WINDOWS_CHECK_NOT(RESULT,VAL) \ + if ((RESULT) == (VAL)) throw QPID_WINDOWS_ERROR((::GetLastError())) + +#define QPID_WINDOWS_CHECK_ASYNC_START(STATUS) \ + if (!(STATUS) && ::WSAGetLastError() != ERROR_IO_PENDING) \ + throw QPID_WINDOWS_ERROR((::WSAGetLastError())) + +#define QPID_WINDOWS_CHECK_CRT_NZ(VAL) \ + if ((VAL) == 0) throw QPID_WINDOWS_CRT_ERROR(errno) + +#define QPID_WINSOCK_CHECK(OP) \ + if ((OP) == SOCKET_ERROR) throw QPID_WINDOWS_ERROR((::WSAGetLastError())) + +#endif /*!_windows_check_h*/ |