// bslmt_threadutilimpl_win32.h -*-C++-*- // ---------------------------------------------------------------------------- // NOTICE // // This component is not up to date with current BDE coding standards, and // should not be used as an example for new development. // ---------------------------------------------------------------------------- #ifndef INCLUDED_BSLMT_THREADUTILIMPL_WIN32 #define INCLUDED_BSLMT_THREADUTILIMPL_WIN32 #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a win32 implementation of 'bslmt::ThreadUtil'. // //@CLASSES: // bslmt::ThreadUtilImpl<Win32Threads>: win32 specialization // //@SEE_ALSO: bslmt_threadutil // //@DESCRIPTION: This component provides an implementation of // 'bslmt::ThreadUtil' for Windows (win32), // 'bslmt::ThreadUtilImpl<Win32Threads>', via the template specialization: //.. // bslmt::ThreadUtilImpl<Platform::Win32Threads> //.. // This template class should not be used (directly) by client code. Clients // should instead use 'bslmt::ThreadUtil'. // ///Supported Clock-Types ///--------------------- // 'bsls::SystemClockType' supplies the enumeration indicating the system clock // on which timeouts supplied to other methods should be based. If the clock // type indicated at construction is 'bsls::SystemClockType::e_REALTIME', the // 'absTime' argument passed to the 'timedWait' method of the various // synchronization primitives offered in 'bslmt' should be expressed as an // *absolute* offset since 00:00:00 UTC, January 1, 1970 (which matches the // epoch used in 'bsls::SystemTime::now(bsls::SystemClockType::e_REALTIME)'. // If the clock type indicated at construction is // 'bsls::SystemClockType::e_MONOTONIC', the 'absTime' argument passed to the // 'timedWait' method of the various synchronization primitives offered in // 'bslmt' should be expressed as an *absolute* offset since the epoch of this // clock (which matches the epoch used in // 'bsls::SystemTime::now(bsls::SystemClockType::e_MONOTONIC)'. // ///Usage ///----- // This component is an implementation detail of 'bslmt' and is *not* intended // for direct client use. It is subject to change without notice. As such, a // usage example is not provided. #include <bslscm_version.h> #include <bslmt_platform.h> #ifdef BSLMT_PLATFORM_WIN32_THREADS // Platform-specific implementation starts here. #include <bslmt_saturatedtimeconversionimputil.h> #include <bslmt_threadattributes.h> #include <bsls_assert.h> #include <bsls_systemclocktype.h> #include <bsls_timeinterval.h> #include <bsls_types.h> #include <bsl_string.h> typedef unsigned long DWORD; typedef int BOOL; typedef void *HANDLE; extern "C" { __declspec(dllimport) void __stdcall Sleep( DWORD dwMilliseconds ); __declspec(dllimport) DWORD __stdcall SleepEx( DWORD dwMilliseconds, BOOL bAlertable ); __declspec(dllimport) DWORD __stdcall GetCurrentThreadId( void ); __declspec(dllimport) HANDLE __stdcall GetCurrentThread( void ); __declspec(dllimport) void* __stdcall TlsGetValue( DWORD dwTlsIndex ); __declspec(dllimport) BOOL __stdcall TlsSetValue( DWORD dwTlsIndex, void *lpTlsValue ); }; namespace BloombergLP { extern "C" { typedef void *(*bslmt_ThreadFunction)(void *); // 'bslmt_ThreadFunction' is an alias for a function type taking a // single 'void' pointer argument and returning 'void *'. Such // functions are suitable to be specified as thread entry point // functions to 'bslmt::ThreadUtil::create'. typedef void (*bslmt_KeyDestructorFunction)(void *); // 'bslmt_KeyDestructorFunction' is an alias for a function type taking // a single 'void' pointer argument and returning 'void'. Such // functions are suitable to be specified as thread-specific key // destructor functions to 'bslmt::ThreadUtil::createKey'. } namespace bslmt { template <class THREAD_POLICY> struct ThreadUtilImpl; // ============================================ // class ThreadUtilImpl<Platform::Win32Threads> // ============================================ template <> struct ThreadUtilImpl<Platform::Win32Threads> { // This class provides a full specialization of 'ThreadUtilImpl' for // Windows. // TYPES struct Handle { // Representation of a thread handle. If a thread is created as // joinable, then a duplicate of to original handle is created to be // used in calls to 'join' and 'detach'. HANDLE d_handle; // win32 thread handle DWORD d_id; // duplicate of thread handle used for joinable // threads }; typedef HANDLE NativeHandle; // Native WIN32 thread handle type typedef DWORD Id; // Win32 thread Id type typedef DWORD Key; // Win32 thread specific key(TLS index) // CLASS METHODS static const Handle INVALID_HANDLE; static int create(Handle *thread, const ThreadAttributes& attribute, bslmt_ThreadFunction function, void *userData); // Create a new thread of program control having the attributes // specified by 'attribute', that invokes the specified 'function' with // a single argument specified by 'userData' and load into the // specified 'threadHandle', an identifier that may be used to refer to // the thread in future calls to this utility. Return 0 on success, // and a non-zero value otherwise. The behavior is undefined if // 'thread' is 0. Note that unless explicitly "detached"('detach'), or // unless the 'BSLMT_CREATE_DETACHED' attribute is specified, a call to // 'join' must be made once the thread terminates to reclaim any system // resources associated with the newly created identifier. static int create(Handle *thread, bslmt_ThreadFunction function, void *userData); // Create a new thread of program control having platform specific // default attributes(i.e., "stack size", "scheduling priority"), that // invokes the specified 'function' with a single argument specified by // 'userData', and load into the specified 'threadHandle', an // identifier that may be used to refer to the thread in future calls // to this utility. Return 0 on success, and a non-zero value // otherwise. The behavior is undefined if 'thread' is 0. Note that // unless explicitly "detached"('detach'), a call to 'join' must be // made once the thread terminates to reclaim any system resources // associated with the newly created identifier. static int getMinSchedulingPriority( ThreadAttributes::SchedulingPolicy policy); // Return the minimum available priority for the 'policy', where // 'policy' is of type 'ThreadAttributes::SchedulingPolicy'. Return // 'ThreadAttributes::BSLMT_UNSET_PRIORITY' if the minimum scheduling // priority cannot be determined. Note that, for some platform / // policy combinations, 'getMinSchedulingPriority(policy)' and // 'getMaxSchedulingPriority(policy)' return the same value. static int getMaxSchedulingPriority( ThreadAttributes::SchedulingPolicy policy); // Return the maximum available priority for the 'policy', where // 'policy' is of type 'ThreadAttributes::SchedulingPolicy'. Return // 'ThreadAttributes::BSLMT_UNSET_PRIORITY' if the maximum scheduling // priority cannot be determined. Note that, for some platform / // policy combinations, 'getMinSchedulingPriority(policy)' and // 'getMaxSchedulingPriority(policy)' return the same value. static void getThreadName(bsl::string *threadName); // Load the name of the current thread into the specified 'threadName'. // Note that this method clears '*threadName' as thread naming is not // implemented on Windows. static int join(Handle& thread, void **status = 0); // Suspend execution of the current thread until the thread specified // by 'threadHandle' terminates, and reclaim any system resources // associated with the specified 'threadHandle'. Return 0 on success, // and a non-zero value otherwise. If the specified 'status' is not 0, // load into the specified 'status', the value returned by the // specified 'thread'. static void yield(); // Put the current thread to the end of the scheduler's queue and // schedule another thread to run. This allows cooperating threads of // the same priority to share CPU resources equally. static void setThreadName(const bslstl::StringRef& threadName); // Set the name of the current thread to the specified 'threadName'. // On Windows this function has no effect. static void sleep(const bsls::TimeInterval& sleepTime); // Suspend execution of the current thread for a period of at least the // specified 'sleepTime' (relative time). Note that the actual time // suspended depends on many factors including system scheduling, and // system timer resolution. On the win32 platform the sleep timer has // a resolution of 1 millisecond. static void microSleep(int microseconds, int seconds = 0); // Suspend execution of the current thread for a period of at least the // specified 'seconds' and 'microseconds' (relative time). Note that // the actual time suspended depends on many factors including system // scheduling, and system timer resolution. On the win32 platform the // sleep timer has a resolution of 1 millisecond. static int sleepUntil(const bsls::TimeInterval& absoluteTime, bsls::SystemClockType::Enum clockType = bsls::SystemClockType::e_REALTIME); // Suspend execution of the current thread until the specified // 'absoluteTime'. Optionally specify 'clockType' which determines the // epoch from which the interval 'absoluteTime' is measured (see // {Supported Clock-Types} in the component documentation). Return 0 // on success, and a non-zero value otherwise. The behavior is // undefined unless 'absoluteTime' represents a time after January 1, // 1970 and before the end of December 31, 9999 (i.e., a time interval // greater than or equal to 0, and less than 253,402,300,800 seconds). // Note that the actual time suspended depends on many factors // including system scheduling and system timer resolution. static void exit(void *status); // Exit the current thread and return the specified 'status'. If the // current thread is not "detached", then a call to 'join' must be made // to reclaim any resources used by the thread, and to retrieve the // exit status. Note that generally, the preferred method of exiting a // thread is to return form the entry point function. static Handle self(); // Return a thread 'Handle' that can be used to refer to the current // thread. The handle can be specified to any function that supports // operations on itself (e.g., 'detach', 'areEqual'). Note that the // returned handle is only valid in the context of the calling thread. static int detach(Handle& threadHandle); // "Detach" the thread identified by 'threadHandle', such that when it // terminates, the resources associated the thread will automatically // be reclaimed. Note that once a thread is "detached", it is no // longer possible to 'join' the thread to retrieve the its exit // status. static NativeHandle nativeHandle(const Handle& threadHandle); // Return the platform specific identifier associated with the thread // specified by 'threadHandle'. Note that the returned native handle // may not be a globally unique identifier for the thread (see // 'selfIdAsUint'). static bool areEqual(const Handle& a, const Handle& b); // Return 'true' if the specified 'a' and 'b' thread handles identify // the same thread and a 'false' value otherwise. static Id selfId(); // Return an identifier that can be used to uniquely identify the // current thread within the current process. Note that the id is only // valid until the thread terminates and may be reused thereafter. static bsls::Types::Uint64 selfIdAsInt(); // Return an integral identifier that can be used to uniquely identify // the current thread within the current process. This representation // is particularly useful for logging purposes. Note that this value // is only valid until the thread terminates and may be reused // thereafter. // // DEPRECATED: Use 'selfIdAsUint64' instead. static bsls::Types::Uint64 selfIdAsUint64(); // Return an integral identifier that can be used to uniquely identify // the current thread within the current process. This representation // is particularly useful for logging purposes. Note that this value // is only valid until the thread terminates and may be reused // thereafter. static Id handleToId(const Handle& threadHandle); // Return the unique identifier of the thread having the specified // 'threadHandle' within the current process. Note that this value is // only valid until the thread terminates and may be reused thereafter. static bsls::Types::Uint64 idAsUint64(const Id& threadId); // Return the unique integral identifier of a thread uniquely // identified by the specified 'threadId' within the current process. // Note that this representation is particularly useful for logging // purposes. Also note that this value is only valid until the thread // terminates and may be reused thereafter. static int idAsInt(const Id& threadId); // Return the unique integral identifier of a thread uniquely // identified by the specified 'threadId' within the current process. // Note that this representation is particularly useful for logging // purposes. Also note that this value is only valid until the thread // terminates and may be reused thereafter. // // DEPRECATED: use 'idAsUint64'. static bool areEqualId(const Id& a, const Id& b); // Return 'true' if the specified 'a' and 'b' thread id identify the // same thread and 'false' otherwise. static int createKey(Key *key, bslmt_KeyDestructorFunction destructor); // Store into the specified 'key', an identifier that can be used to // associate('setSpecific') and retrieve('getSpecific') a single // thread-specific pointer value. Associated with the identifier,the // optional 'destructor' if a non-zero value is specified. Return 0 on // success, and a non-zero value otherwise. static int deleteKey(Key& key); // Delete the specified thread-specific 'key'. Note that deleting a // key does not delete any data that is currently associated with the // key in the calling thread or any other thread. static void *getSpecific(const Key& key); // Return the value associated with the specified thread-specific // 'key'. Note that if the key is not valid, a value of zero is // returned, which is indistinguishable from a valid key with a 0 // value. static int setSpecific(const Key& key, const void *value); // Associate the specified 'value' with the specified thread-specific // 'key'. Return 0 on success, and a non-zero value otherwise. static unsigned int hardwareConcurrency(); // Return the number of concurrent threads supported by the // implementation on success, and 0 otherwise. }; // FREE OPERATORS bool operator==(const ThreadUtilImpl<Platform::Win32Threads>::Handle& lhs, const ThreadUtilImpl<Platform::Win32Threads>::Handle& rhs); // Return 'true' if the specified 'lhs' and 'rhs' thread handles have the // same value, and 'false' otherwise. bool operator!=(const ThreadUtilImpl<Platform::Win32Threads>::Handle& lhs, const ThreadUtilImpl<Platform::Win32Threads>::Handle& rhs); // Return 'true' if the specified 'lhs' and 'rhs' thread handles do not // have the same value, and 'false' otherwise. } // close package namespace // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ---------------------- // ThreadUtilImpl::Handle // ---------------------- // FREE OPERATORS inline bool bslmt::operator==( const ThreadUtilImpl<bslmt::Platform::Win32Threads>::Handle& lhs, const ThreadUtilImpl<bslmt::Platform::Win32Threads>::Handle& rhs) { return ThreadUtilImpl<Platform::Win32Threads>::areEqual(lhs, rhs); } inline bool bslmt::operator!=( const ThreadUtilImpl<bslmt::Platform::Win32Threads>::Handle& lhs, const ThreadUtilImpl<bslmt::Platform::Win32Threads>::Handle& rhs) { return !(lhs == rhs); } // -------------------------------------------- // class ThreadUtilImpl<Platform::Win32Threads> // -------------------------------------------- // CLASS METHODS inline int bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>:: getMinSchedulingPriority(ThreadAttributes::SchedulingPolicy) { return ThreadAttributes::e_UNSET_PRIORITY; } inline int bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>:: getMaxSchedulingPriority(ThreadAttributes::SchedulingPolicy) { return ThreadAttributes::e_UNSET_PRIORITY; } inline void bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::yield() { ::SleepEx(0, 0); } inline void bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::sleep( const bsls::TimeInterval& sleepTime) { DWORD milliSeconds; SaturatedTimeConversionImpUtil::toMillisec(&milliSeconds, sleepTime); ::Sleep(milliSeconds); } inline void bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::microSleep( int microsecs, int seconds) { enum { k_MILLION = 1000 * 1000 }; bsls::TimeInterval ti((microsecs / k_MILLION) + seconds, (microsecs % k_MILLION) * 1000); DWORD milliSeconds; SaturatedTimeConversionImpUtil::toMillisec(&milliSeconds, ti); ::Sleep(milliSeconds); } inline bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::Handle bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::self() { Handle h; h.d_id = GetCurrentThreadId(); h.d_handle = GetCurrentThread(); return h; } inline bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::NativeHandle bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::nativeHandle( const Handle& handle) { return handle.d_handle; } inline bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::Id bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::selfId() { return GetCurrentThreadId(); } inline bsls::Types::Uint64 bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::selfIdAsInt() { return idAsInt(selfId()); } inline bsls::Types::Uint64 bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::selfIdAsUint64() { return idAsUint64(selfId()); } inline bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::Id bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::handleToId( const Handle& threadHandle) { return threadHandle.d_id; } inline bsls::Types::Uint64 bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::idAsUint64( const Id& threadId) { return static_cast<bsls::Types::Uint64>(threadId); } inline int bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::idAsInt( const Id& threadId) { return static_cast<int>(threadId); } inline bool bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::areEqualId( const Id& a, const Id& b) { return a == b; } inline void *bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::getSpecific( const Key& key) { return TlsGetValue(key); } inline int bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::setSpecific( const Key& key, const void *value) { return 0 == TlsSetValue(key, (void*)value) ? 1 : 0; } } // close enterprise namespace #endif // BSLMT_PLATFORM_WIN32_THREADS #endif // ---------------------------------------------------------------------------- // Copyright 2015 Bloomberg Finance L.P. // // 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. // ----------------------------- END-OF-FILE ----------------------------------