// bslmt_threadutilimpl_win32.h                                       -*-C++-*-
#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" {
    /// `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_ThreadFunction)(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`.
    typedef void (*bslmt_KeyDestructorFunction)(void *);
}

namespace bslmt {

template <class THREAD_POLICY>
struct ThreadUtilImpl;

               // ============================================
               // class ThreadUtilImpl<Platform::Win32Threads>
               // ============================================

/// This class provides a full specialization of 'ThreadUtilImpl' for
/// Windows.
template <>
struct ThreadUtilImpl<Platform::Win32Threads> {

    // TYPES

    /// 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`.
    struct Handle {

        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;

    /// 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,
                      const ThreadAttributes&  attribute,
                      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 create(Handle               *thread,
                      bslmt_ThreadFunction  function,
                      void                 *userData);

    /// 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 getMinSchedulingPriority(
                                    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 int getMaxSchedulingPriority(
                                    ThreadAttributes::SchedulingPolicy policy);

    /// 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 void getThreadName(bsl::string *threadName);

    /// 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 int join(Handle& thread, void **status = 0);

    /// 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 yield();

    /// Set the name of the current thread to the specified `threadName`.
    /// On Windows this function has no effect.
    static void setThreadName(const bslstl::StringRef&  threadName);

    /// 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 sleep(const bsls::TimeInterval& sleepTime);

    /// 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 void microSleep(int microseconds, int seconds = 0);

    /// 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 int sleepUntil(const bsls::TimeInterval&   absoluteTime,
                          bsls::SystemClockType::Enum clockType
                                          = bsls::SystemClockType::e_REALTIME);

    /// 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 void exit(void *status);

    /// 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 Handle self();

    /// "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 int detach(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 NativeHandle nativeHandle(const Handle& threadHandle);

    /// Return `true` if the specified `a` and `b` thread handles identify
    /// the same thread and a `false` value otherwise.
    static bool areEqual(const Handle& a, const Handle& b);

    /// 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 Id selfId();

    /// 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 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.
    static bsls::Types::Uint64 selfIdAsUint64();

    /// Return an integral identifier of the current thread used by the
    /// operating system.  Note that this value is only valid until the thread
    /// terminates and may be reused thereafter.  Also note that this method on
    /// Windows returns the same value as `selfIdAsUint64`.
    static bsls::Types::Uint64 selfKernelIdAsUint64();

    /// 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 Id handleToId(const Handle& threadHandle);

    /// 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 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.
    ///
    /// DEPRECATED: use `idAsUint64`.
    static int idAsInt(const Id& threadId);

    /// Return `true` if the specified `a` and `b` thread id identify the
    /// same thread and `false` otherwise.
    static bool areEqualId(const Id& a, const Id& b);

    /// 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 createKey(Key *key, bslmt_KeyDestructorFunction destructor);

    /// 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 int deleteKey(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 void *getSpecific(const Key& key);

    /// Associate the specified `value` with the specified thread-specific
    /// `key`.  Return 0 on success, and a non-zero value otherwise.
    static int setSpecific(const Key& key, const void *value);

    /// Return the number of concurrent threads supported by the
    /// implementation on success, and 0 otherwise.
    static unsigned int hardwareConcurrency();
};

// FREE OPERATORS

/// 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.
bool operator!=(const ThreadUtilImpl<Platform::Win32Threads>::Handle& lhs,
                const ThreadUtilImpl<Platform::Win32Threads>::Handle& rhs);


// ============================================================================
//                             INLINE DEFINITIONS
// ============================================================================

               // --------------------------------------------
               // class ThreadUtilImpl<Platform::Win32Threads>
               // --------------------------------------------

// CLASS METHODS
inline
int ThreadUtilImpl<bslmt::Platform::Win32Threads>::
    getMinSchedulingPriority(ThreadAttributes::SchedulingPolicy)
{
    return ThreadAttributes::e_UNSET_PRIORITY;
}

inline
int ThreadUtilImpl<bslmt::Platform::Win32Threads>::
    getMaxSchedulingPriority(ThreadAttributes::SchedulingPolicy)
{
    return ThreadAttributes::e_UNSET_PRIORITY;
}

inline
void ThreadUtilImpl<bslmt::Platform::Win32Threads>::yield()
{
    ::SleepEx(0, 0);
}

inline
void ThreadUtilImpl<bslmt::Platform::Win32Threads>::sleep(
                                           const bsls::TimeInterval& sleepTime)

{
    DWORD milliSeconds;
    SaturatedTimeConversionImpUtil::toMillisec(&milliSeconds, sleepTime);

    ::Sleep(milliSeconds);
}

inline
void 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
ThreadUtilImpl<bslmt::Platform::Win32Threads>::Handle
ThreadUtilImpl<bslmt::Platform::Win32Threads>::self()
{
    Handle h;
    h.d_id     = GetCurrentThreadId();
    h.d_handle = GetCurrentThread();
    return h;
}

inline
ThreadUtilImpl<bslmt::Platform::Win32Threads>::NativeHandle
ThreadUtilImpl<bslmt::Platform::Win32Threads>::nativeHandle(
                                                          const Handle& handle)
{
    return handle.d_handle;
}

inline
ThreadUtilImpl<bslmt::Platform::Win32Threads>::Id
ThreadUtilImpl<bslmt::Platform::Win32Threads>::selfId()
{
    return GetCurrentThreadId();
}

inline
bsls::Types::Uint64
ThreadUtilImpl<bslmt::Platform::Win32Threads>::selfIdAsInt()
{
    return idAsInt(selfId());
}

inline
bsls::Types::Uint64
ThreadUtilImpl<bslmt::Platform::Win32Threads>::selfIdAsUint64()
{
    return idAsUint64(selfId());
}

inline
bsls::Types::Uint64
ThreadUtilImpl<bslmt::Platform::Win32Threads>::selfKernelIdAsUint64()
{
    return selfIdAsUint64();
}

inline
ThreadUtilImpl<bslmt::Platform::Win32Threads>::Id
ThreadUtilImpl<bslmt::Platform::Win32Threads>::handleToId(
                                                    const Handle& threadHandle)
{
    return threadHandle.d_id;
}

inline
bsls::Types::Uint64
ThreadUtilImpl<bslmt::Platform::Win32Threads>::idAsUint64(
                                                            const Id& threadId)
{
    return static_cast<bsls::Types::Uint64>(threadId);
}

inline
int ThreadUtilImpl<bslmt::Platform::Win32Threads>::idAsInt(
                                                            const Id& threadId)
{
    return static_cast<int>(threadId);
}

inline
bool ThreadUtilImpl<bslmt::Platform::Win32Threads>::areEqualId(
                                                                   const Id& a,
                                                                   const Id& b)
{
    return a == b;
}

inline
void *ThreadUtilImpl<bslmt::Platform::Win32Threads>::getSpecific(
                                                                const Key& key)
{
    return TlsGetValue(key);
}

inline
int ThreadUtilImpl<bslmt::Platform::Win32Threads>::setSpecific(
                                                             const Key&  key,
                                                             const void *value)
{
    return 0 == TlsSetValue(key, (void*)value) ? 1 : 0;
}

}  // close package namespace

                          // ----------------------
                          // ThreadUtilImpl::Handle
                          // ----------------------

// FREE OPERATORS
inline
bool bslmt::operator==(
       const bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::Handle& lhs,
       const bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::Handle& rhs)
{
    return bslmt::ThreadUtilImpl<Platform::Win32Threads>::areEqual(lhs, rhs);
}

inline
bool bslmt::operator!=(
       const bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::Handle& lhs,
       const bslmt::ThreadUtilImpl<bslmt::Platform::Win32Threads>::Handle& rhs)
{
    return !(lhs == rhs);
}

}  // 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 ----------------------------------
