summaryrefslogtreecommitdiffstats
path: root/sal/osl/w32/thread.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sal/osl/w32/thread.cxx555
1 files changed, 555 insertions, 0 deletions
diff --git a/sal/osl/w32/thread.cxx b/sal/osl/w32/thread.cxx
new file mode 100644
index 000000000..19479de03
--- /dev/null
+++ b/sal/osl/w32/thread.cxx
@@ -0,0 +1,555 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include "system.h"
+#include "thread.hxx"
+
+#include <osl/diagnose.h>
+#include <osl/thread.h>
+#include <rtl/alloc.h>
+#include <osl/time.h>
+#include <osl/interlck.h>
+#include <rtl/tencinfo.h>
+#include <errno.h>
+
+namespace {
+
+/**
+ Thread-data structure hidden behind oslThread:
+ */
+typedef struct
+{
+ HANDLE m_hThread; /* OS-handle used for all thread-functions */
+ unsigned m_ThreadId; /* identifier for this thread */
+ sal_Int32 m_nTerminationRequested;
+ oslWorkerFunction m_WorkerFunction;
+ void* m_pData;
+
+} osl_TThreadImpl;
+
+}
+
+static unsigned __stdcall oslWorkerWrapperFunction(void* pData);
+static oslThread oslCreateThread(oslWorkerFunction pWorker, void* pThreadData, sal_uInt32 nFlags);
+
+static unsigned __stdcall oslWorkerWrapperFunction(void* pData)
+{
+ osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(pData);
+
+ /* Initialize COM - Multi Threaded Apartment (MTA) for all threads */
+ CoInitializeEx(nullptr, COINIT_MULTITHREADED); /* spawned by oslCreateThread */
+
+ /* call worker-function with data */
+
+ pThreadImpl->m_WorkerFunction(pThreadImpl->m_pData);
+
+ CoUninitialize();
+
+ return 0;
+}
+
+static oslThread oslCreateThread(oslWorkerFunction pWorker,
+ void* pThreadData,
+ sal_uInt32 nFlags)
+{
+ osl_TThreadImpl* pThreadImpl;
+
+ /* alloc mem. for our internal data structure */
+ pThreadImpl= static_cast<osl_TThreadImpl *>(malloc(sizeof(osl_TThreadImpl)));
+
+ OSL_ASSERT(pThreadImpl);
+
+ if ( pThreadImpl == nullptr )
+ {
+ return nullptr;
+ }
+
+ pThreadImpl->m_WorkerFunction= pWorker;
+ pThreadImpl->m_pData= pThreadData;
+ pThreadImpl->m_nTerminationRequested= 0;
+
+ pThreadImpl->m_hThread=
+ reinterpret_cast<HANDLE>(_beginthreadex(nullptr, /* no security */
+ 0, /* default stack-size */
+ oslWorkerWrapperFunction, /* worker-function */
+ pThreadImpl, /* provide worker-function with data */
+ nFlags, /* start thread immediately or suspended */
+ &pThreadImpl->m_ThreadId));
+
+ if(pThreadImpl->m_hThread == nullptr)
+ {
+ switch (errno)
+ {
+ case EAGAIN:
+ fprintf(stderr, "_beginthreadex errno EAGAIN\n");
+ break;
+ case EINVAL:
+ fprintf(stderr, "_beginthreadex errno EINVAL\n");
+ break;
+ case EACCES:
+ fprintf(stderr, "_beginthreadex errno EACCES\n");
+ break;
+ case ENOMEM:
+ fprintf(stderr, "_beginthreadex undocumented errno ENOMEM - this means not enough VM for stack\n");
+ break;
+ default:
+ fprintf(stderr, "_beginthreadex unexpected errno %d\n", errno);
+ break;
+ }
+
+ /* create failed */
+ free(pThreadImpl);
+ return nullptr;
+ }
+
+ return pThreadImpl;
+}
+
+oslThread SAL_CALL osl_createThread(oslWorkerFunction pWorker,
+ void* pThreadData)
+{
+ return oslCreateThread(pWorker, pThreadData, 0);
+}
+
+oslThread SAL_CALL osl_createSuspendedThread(oslWorkerFunction pWorker,
+ void* pThreadData)
+{
+ return oslCreateThread(pWorker, pThreadData, CREATE_SUSPENDED);
+}
+
+oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread)
+{
+ osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(Thread);
+
+ if (pThreadImpl != nullptr)
+ return static_cast<oslThreadIdentifier>(pThreadImpl->m_ThreadId);
+ else
+ return static_cast<oslThreadIdentifier>(GetCurrentThreadId());
+}
+
+void SAL_CALL osl_destroyThread(oslThread Thread)
+{
+ osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(Thread);
+
+ if (Thread == nullptr) /* valid ptr? */
+ {
+ /* thread already destroyed or not created */
+ return;
+ }
+
+ /* !!!! _exitthreadex does _not_ call CloseHandle !!! */
+ CloseHandle( pThreadImpl->m_hThread );
+
+ /* free memory */
+ free(Thread);
+}
+
+void SAL_CALL osl_resumeThread(oslThread Thread)
+{
+ osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(Thread);
+
+ OSL_ASSERT(pThreadImpl); /* valid ptr? */
+
+ ResumeThread(pThreadImpl->m_hThread);
+}
+
+void SAL_CALL osl_suspendThread(oslThread Thread)
+{
+ osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(Thread);
+
+ OSL_ASSERT(pThreadImpl); /* valid ptr? */
+
+ SuspendThread(pThreadImpl->m_hThread);
+}
+
+void SAL_CALL osl_setThreadPriority(oslThread Thread,
+ oslThreadPriority Priority)
+{
+ int winPriority;
+ osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(Thread);
+
+ OSL_ASSERT(pThreadImpl); /* valid ptr? */
+
+ /* map enum to WIN32 levels
+ it would be faster and more elegant to preset
+ the enums, but that would require an #ifdef in
+ the exported header, which is not desired.
+ */
+ switch(Priority) {
+
+ case osl_Thread_PriorityHighest:
+ winPriority= THREAD_PRIORITY_HIGHEST;
+ break;
+
+ case osl_Thread_PriorityAboveNormal:
+ winPriority= THREAD_PRIORITY_ABOVE_NORMAL;
+ break;
+
+ case osl_Thread_PriorityNormal:
+ winPriority= THREAD_PRIORITY_NORMAL;
+ break;
+
+ case osl_Thread_PriorityBelowNormal:
+ winPriority= THREAD_PRIORITY_BELOW_NORMAL;
+ break;
+
+ case osl_Thread_PriorityLowest:
+ winPriority= THREAD_PRIORITY_LOWEST;
+ break;
+
+ case osl_Thread_PriorityUnknown:
+ OSL_ASSERT(FALSE); /* only fools try this...*/
+
+ /* let release-version behave friendly */
+ return;
+
+ default:
+ OSL_ASSERT(FALSE); /* enum expanded, but forgotten here...*/
+
+ /* let release-version behave friendly */
+ return;
+ }
+
+ SetThreadPriority(pThreadImpl->m_hThread, winPriority);
+}
+
+oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread)
+{
+ int winPriority;
+ oslThreadPriority Priority;
+
+ osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(Thread);
+
+ /* invalid arguments ?*/
+ if(pThreadImpl==nullptr || pThreadImpl->m_hThread==nullptr)
+ {
+ return osl_Thread_PriorityUnknown;
+ }
+
+ winPriority=
+ GetThreadPriority(pThreadImpl->m_hThread);
+
+ if(winPriority == THREAD_PRIORITY_ERROR_RETURN)
+ {
+ return osl_Thread_PriorityUnknown;
+ }
+
+ /* map WIN32 priority to enum */
+ switch(winPriority)
+ {
+ case THREAD_PRIORITY_TIME_CRITICAL:
+ case THREAD_PRIORITY_HIGHEST:
+ Priority= osl_Thread_PriorityHighest;
+ break;
+
+ case THREAD_PRIORITY_ABOVE_NORMAL:
+ Priority= osl_Thread_PriorityAboveNormal;
+ break;
+
+ case THREAD_PRIORITY_NORMAL:
+ Priority= osl_Thread_PriorityNormal;
+ break;
+
+ case THREAD_PRIORITY_BELOW_NORMAL:
+ Priority= osl_Thread_PriorityBelowNormal;
+ break;
+
+ case THREAD_PRIORITY_IDLE:
+ case THREAD_PRIORITY_LOWEST:
+ Priority= osl_Thread_PriorityLowest;
+ break;
+
+ default:
+ OSL_ASSERT(FALSE); /* WIN32 API changed, incorporate new prio-level! */
+
+ /* release-version behaves friendly */
+ Priority= osl_Thread_PriorityUnknown;
+ }
+
+ return Priority;
+}
+
+sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread)
+{
+ osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(Thread);
+
+ /* invalid arguments ?*/
+ if(pThreadImpl==nullptr || pThreadImpl->m_hThread==nullptr)
+ {
+ return false;
+ }
+
+ return WaitForSingleObject(pThreadImpl->m_hThread, 0) != WAIT_OBJECT_0;
+}
+
+void SAL_CALL osl_joinWithThread(oslThread Thread)
+{
+ osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(Thread);
+
+ /* invalid arguments?*/
+ if(pThreadImpl==nullptr || pThreadImpl->m_hThread==nullptr)
+ {
+ /* assume thread is not running */
+ return;
+ }
+
+ WaitForSingleObject(pThreadImpl->m_hThread, INFINITE);
+}
+
+void SAL_CALL osl_waitThread(const TimeValue* pDelay)
+{
+ if (pDelay)
+ {
+ DWORD millisecs = pDelay->Seconds * 1000L + pDelay->Nanosec / 1000000L;
+
+ Sleep(millisecs);
+ }
+}
+
+void SAL_CALL osl_terminateThread(oslThread Thread)
+{
+ osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(Thread);
+
+ /* invalid arguments?*/
+ if (pThreadImpl==nullptr || pThreadImpl->m_hThread==nullptr)
+ {
+ /* assume thread is not running */
+ return;
+ }
+
+ osl_atomic_increment(&(pThreadImpl->m_nTerminationRequested));
+}
+
+sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread)
+{
+ osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(Thread);
+
+ osl_yieldThread();
+
+ /* invalid arguments?*/
+ if (pThreadImpl==nullptr || pThreadImpl->m_hThread==nullptr)
+ {
+ /* assume thread is not running */
+ return false;
+ }
+
+ return 0 == pThreadImpl->m_nTerminationRequested;
+}
+
+void SAL_CALL osl_yieldThread(void)
+{
+ Sleep(0);
+}
+
+void SAL_CALL osl_setThreadName(char const * name) {
+#ifdef _MSC_VER
+ /* See <http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx>: */
+#pragma pack(push, 8)
+ struct {
+ DWORD dwType;
+ LPCSTR szName;
+ DWORD dwThreadID;
+ DWORD dwFlags;
+ } info;
+#pragma pack(pop)
+ info.dwType = 0x1000;
+ info.szName = name;
+ info.dwThreadID = DWORD(-1);
+ info.dwFlags = 0;
+ __try {
+ RaiseException(
+ 0x406D1388, 0, sizeof info / sizeof (ULONG_PTR),
+ reinterpret_cast<ULONG_PTR *>(&info));
+ } __except (EXCEPTION_EXECUTE_HANDLER) {}
+#else
+ (void) name;
+#endif
+}
+
+namespace {
+
+typedef struct TLS_
+{
+ DWORD dwIndex;
+ oslThreadKeyCallbackFunction pfnCallback;
+ struct TLS_ *pNext, *pPrev;
+} TLS, *PTLS;
+
+}
+
+static PTLS g_pThreadKeyList = nullptr;
+CRITICAL_SECTION g_ThreadKeyListCS;
+
+static void AddKeyToList( PTLS pTls )
+{
+ if ( pTls )
+ {
+ EnterCriticalSection( &g_ThreadKeyListCS );
+
+ pTls->pNext = g_pThreadKeyList;
+ pTls->pPrev = nullptr;
+
+ if ( g_pThreadKeyList )
+ g_pThreadKeyList->pPrev = pTls;
+
+ g_pThreadKeyList = pTls;
+
+ LeaveCriticalSection( &g_ThreadKeyListCS );
+ }
+}
+
+static void RemoveKeyFromList( PTLS pTls )
+{
+ if ( pTls )
+ {
+ EnterCriticalSection( &g_ThreadKeyListCS );
+ if ( pTls->pPrev )
+ pTls->pPrev->pNext = pTls->pNext;
+ else
+ {
+ OSL_ASSERT( pTls == g_pThreadKeyList );
+ g_pThreadKeyList = pTls->pNext;
+ }
+
+ if ( pTls->pNext )
+ pTls->pNext->pPrev = pTls->pPrev;
+ LeaveCriticalSection( &g_ThreadKeyListCS );
+ }
+}
+
+void osl_callThreadKeyCallbackOnThreadDetach(void)
+{
+ PTLS pTls;
+
+ EnterCriticalSection( &g_ThreadKeyListCS );
+ pTls = g_pThreadKeyList;
+ while ( pTls )
+ {
+ if ( pTls->pfnCallback )
+ {
+ void *pValue = TlsGetValue( pTls->dwIndex );
+
+ if ( pValue )
+ pTls->pfnCallback( pValue );
+ }
+
+ pTls = pTls->pNext;
+ }
+ LeaveCriticalSection( &g_ThreadKeyListCS );
+}
+
+oslThreadKey SAL_CALL osl_createThreadKey(oslThreadKeyCallbackFunction pCallback)
+{
+ PTLS pTls = static_cast<PTLS>(malloc( sizeof(TLS) ));
+
+ if ( pTls )
+ {
+ pTls->pfnCallback = pCallback;
+ if ( DWORD(-1) == (pTls->dwIndex = TlsAlloc()) )
+ {
+ free( pTls );
+ pTls = nullptr;
+ }
+ else
+ AddKeyToList( pTls );
+ }
+
+ return pTls;
+}
+
+void SAL_CALL osl_destroyThreadKey(oslThreadKey Key)
+{
+ if (Key != nullptr)
+ {
+ PTLS pTls = static_cast<PTLS>(Key);
+
+ RemoveKeyFromList( pTls );
+ TlsFree( pTls->dwIndex );
+ free( pTls );
+ }
+}
+
+void* SAL_CALL osl_getThreadKeyData(oslThreadKey Key)
+{
+ if (Key != nullptr)
+ {
+ PTLS pTls = static_cast<PTLS>(Key);
+
+ return TlsGetValue( pTls->dwIndex );
+ }
+
+ return nullptr;
+}
+
+sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData)
+{
+ if (Key != nullptr)
+ {
+ PTLS pTls = static_cast<PTLS>(Key);
+ void* pOldData = nullptr;
+ bool fSuccess;
+
+ if ( pTls->pfnCallback )
+ pOldData = TlsGetValue( pTls->dwIndex );
+
+ fSuccess = TlsSetValue( pTls->dwIndex, pData );
+
+ if ( fSuccess && pTls->pfnCallback && pOldData )
+ pTls->pfnCallback( pOldData );
+
+ return fSuccess;
+ }
+
+ return false;
+}
+
+DWORD g_dwTLSTextEncodingIndex = DWORD(-1);
+
+rtl_TextEncoding SAL_CALL osl_getThreadTextEncoding(void)
+{
+ DWORD_PTR dwEncoding;
+ rtl_TextEncoding _encoding;
+ bool gotACP;
+
+ if ( DWORD(-1) == g_dwTLSTextEncodingIndex )
+ g_dwTLSTextEncodingIndex = TlsAlloc();
+
+ dwEncoding = reinterpret_cast<DWORD_PTR>(TlsGetValue( g_dwTLSTextEncodingIndex ));
+ _encoding = LOWORD(dwEncoding);
+ gotACP = HIWORD(dwEncoding);
+
+ if ( !gotACP )
+ {
+ _encoding = rtl_getTextEncodingFromWindowsCodePage( GetACP() );
+ TlsSetValue( g_dwTLSTextEncodingIndex, reinterpret_cast<LPVOID>(static_cast<DWORD_PTR>(MAKELONG( _encoding, TRUE ))) );
+ }
+
+ return _encoding;
+}
+
+rtl_TextEncoding SAL_CALL osl_setThreadTextEncoding( rtl_TextEncoding Encoding )
+{
+ rtl_TextEncoding oldEncoding = osl_getThreadTextEncoding();
+
+ TlsSetValue( g_dwTLSTextEncodingIndex, reinterpret_cast<LPVOID>(static_cast<DWORD_PTR>(MAKELONG( Encoding, TRUE))) );
+
+ return oldEncoding;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */