summaryrefslogtreecommitdiff
path: root/sal/osl/w32/thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'sal/osl/w32/thread.c')
-rw-r--r--sal/osl/w32/thread.c593
1 files changed, 593 insertions, 0 deletions
diff --git a/sal/osl/w32/thread.c b/sal/osl/w32/thread.c
new file mode 100644
index 000000000000..88ce87cdf175
--- /dev/null
+++ b/sal/osl/w32/thread.c
@@ -0,0 +1,593 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "system.h"
+
+#include <osl/diagnose.h>
+#include <osl/thread.h>
+#include <rtl/alloc.h>
+#include <osl/time.h>
+#include <osl/interlck.h>
+#include <rtl/tencinfo.h>
+
+/*
+ Thread-data structure hidden behind oslThread:
+*/
+typedef struct _osl_TThreadImpl
+{
+ 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;
+
+#define THREADIMPL_FLAGS_TERMINATE 0x0001
+
+static unsigned __stdcall oslWorkerWrapperFunction(void* pData);
+static oslThread oslCreateThread(oslWorkerFunction pWorker, void* pThreadData, sal_uInt32 nFlags);
+
+/*****************************************************************************/
+/* oslWorkerWrapperFunction */
+/*****************************************************************************/
+static unsigned __stdcall oslWorkerWrapperFunction(void* pData)
+{
+ osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)pData;
+
+ /* Initialize COM */
+
+ CoInitializeEx(NULL, COINIT_MULTITHREADED);
+
+ /* call worker-function with data */
+
+ pThreadImpl->m_WorkerFunction(pThreadImpl->m_pData);
+
+ CoUninitialize();
+
+ return (0);
+}
+
+/*****************************************************************************/
+/* oslCreateThread */
+/*****************************************************************************/
+static oslThread oslCreateThread(oslWorkerFunction pWorker,
+ void* pThreadData,
+ sal_uInt32 nFlags)
+{
+ osl_TThreadImpl* pThreadImpl;
+
+ /* alloc mem. for our internal data structure */
+ pThreadImpl= malloc(sizeof(osl_TThreadImpl));
+
+ OSL_ASSERT(pThreadImpl);
+
+ if ( pThreadImpl == 0 )
+ {
+ return 0;
+ }
+
+ pThreadImpl->m_WorkerFunction= pWorker;
+ pThreadImpl->m_pData= pThreadData;
+ pThreadImpl->m_nTerminationRequested= 0;
+
+ pThreadImpl->m_hThread=
+ (HANDLE)_beginthreadex(NULL, /* 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 == 0)
+ {
+ /* create failed */
+ free(pThreadImpl);
+ return 0;
+ }
+
+ return (oslThread)pThreadImpl;
+}
+
+/*****************************************************************************/
+/* osl_createThread */
+/*****************************************************************************/
+oslThread SAL_CALL osl_createThread(oslWorkerFunction pWorker,
+ void* pThreadData)
+{
+ return oslCreateThread(pWorker, pThreadData, 0);
+}
+
+/*****************************************************************************/
+/* osl_createSuspendedThread */
+/*****************************************************************************/
+oslThread SAL_CALL osl_createSuspendedThread(oslWorkerFunction pWorker,
+ void* pThreadData)
+{
+ return oslCreateThread(pWorker, pThreadData, CREATE_SUSPENDED);
+}
+
+/*****************************************************************************/
+/* osl_getThreadIdentifier */
+/*****************************************************************************/
+oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread)
+{
+ osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
+
+ if (pThreadImpl != NULL)
+ return ((oslThreadIdentifier)pThreadImpl->m_ThreadId);
+ else
+ return ((oslThreadIdentifier)GetCurrentThreadId());
+}
+
+/*****************************************************************************/
+/* osl_destroyThread */
+/*****************************************************************************/
+void SAL_CALL osl_destroyThread(oslThread Thread)
+{
+ osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
+
+ if (Thread == 0) /* valid ptr? */
+ {
+ /* thread already destroyed or not created */
+ return;
+ }
+
+ /* !!!! _exitthreadex does _not_ call CloseHandle !!! */
+ CloseHandle( pThreadImpl->m_hThread );
+
+ /* free memory */
+ free(Thread);
+}
+
+/*****************************************************************************/
+/* osl_resumeThread */
+/*****************************************************************************/
+void SAL_CALL osl_resumeThread(oslThread Thread)
+{
+ osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
+
+ OSL_ASSERT(pThreadImpl); /* valid ptr? */
+
+ ResumeThread(pThreadImpl->m_hThread);
+}
+
+/*****************************************************************************/
+/* osl_suspendThread */
+/*****************************************************************************/
+void SAL_CALL osl_suspendThread(oslThread Thread)
+{
+ osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
+
+ OSL_ASSERT(pThreadImpl); /* valid ptr? */
+
+ SuspendThread(pThreadImpl->m_hThread);
+}
+
+/*****************************************************************************/
+/* osl_setThreadPriority */
+/*****************************************************************************/
+void SAL_CALL osl_setThreadPriority(oslThread Thread,
+ oslThreadPriority Priority)
+{
+ int winPriority;
+ osl_TThreadImpl* pThreadImpl= (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);
+}
+
+/*****************************************************************************/
+/* osl_getThreadPriority */
+/*****************************************************************************/
+oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread)
+{
+ int winPriority;
+ oslThreadPriority Priority;
+
+ osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
+
+ /* invalid arguments ?*/
+ if(pThreadImpl==0 || pThreadImpl->m_hThread==0)
+ {
+ 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;
+}
+
+/*****************************************************************************/
+/* osl_isThreadRunning */
+/*****************************************************************************/
+sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread)
+{
+ osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
+
+ /* invalid arguments ?*/
+ if(pThreadImpl==0 || pThreadImpl->m_hThread==0)
+ {
+ return sal_False;
+ }
+
+ return (sal_Bool)(WaitForSingleObject(pThreadImpl->m_hThread, 0) != WAIT_OBJECT_0);
+}
+
+/*****************************************************************************/
+/* osl_joinWithThread */
+/*****************************************************************************/
+void SAL_CALL osl_joinWithThread(oslThread Thread)
+{
+ osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
+
+ /* invalid arguments?*/
+ if(pThreadImpl==0 || pThreadImpl->m_hThread==0)
+ {
+ /* assume thread is not running */
+ return;
+ }
+
+ WaitForSingleObject(pThreadImpl->m_hThread, INFINITE);
+}
+
+/*****************************************************************************/
+/* osl_waitThread */
+/*****************************************************************************/
+void SAL_CALL osl_waitThread(const TimeValue* pDelay)
+{
+ if (pDelay)
+ {
+ DWORD millisecs = pDelay->Seconds * 1000L + pDelay->Nanosec / 1000000L;
+
+ Sleep(millisecs);
+ }
+}
+
+/*****************************************************************************/
+/* osl_terminateThread */
+/*****************************************************************************/
+void SAL_CALL osl_terminateThread(oslThread Thread)
+{
+ osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
+
+ /* invalid arguments?*/
+ if (pThreadImpl==0 || pThreadImpl->m_hThread==0)
+ {
+ /* assume thread is not running */
+ return;
+ }
+
+ osl_incrementInterlockedCount(&(pThreadImpl->m_nTerminationRequested));
+}
+
+
+/*****************************************************************************/
+/* osl_scheduleThread */
+/*****************************************************************************/
+sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread)
+{
+ osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
+
+ osl_yieldThread();
+
+ /* invalid arguments?*/
+ if (pThreadImpl==0 || pThreadImpl->m_hThread==0)
+ {
+ /* assume thread is not running */
+ return sal_False;
+ }
+
+ return (sal_Bool)(0 == pThreadImpl->m_nTerminationRequested);
+}
+
+/*****************************************************************************/
+/* osl_yieldThread */
+/*****************************************************************************/
+void SAL_CALL osl_yieldThread(void)
+{
+ Sleep(0);
+}
+
+typedef struct _TLS
+{
+ DWORD dwIndex;
+ oslThreadKeyCallbackFunction pfnCallback;
+ struct _TLS *pNext, *pPrev;
+} TLS, *PTLS;
+
+static PTLS g_pThreadKeyList = NULL;
+CRITICAL_SECTION g_ThreadKeyListCS;
+
+static void AddKeyToList( PTLS pTls )
+{
+ if ( pTls )
+ {
+ EnterCriticalSection( &g_ThreadKeyListCS );
+
+ pTls->pNext = g_pThreadKeyList;
+ pTls->pPrev = 0;
+
+ 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 SAL_CALL _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 );
+}
+
+/*****************************************************************************/
+/* osl_createThreadKey */
+/*****************************************************************************/
+oslThreadKey SAL_CALL osl_createThreadKey(oslThreadKeyCallbackFunction pCallback)
+{
+ PTLS pTls = rtl_allocateMemory( sizeof(TLS) );
+
+ if ( pTls )
+ {
+ pTls->pfnCallback = pCallback;
+ if ( (DWORD)-1 == (pTls->dwIndex = TlsAlloc()) )
+ {
+ rtl_freeMemory( pTls );
+ pTls = 0;
+ }
+ else
+ AddKeyToList( pTls );
+ }
+
+ return ((oslThreadKey)pTls);
+}
+
+/*****************************************************************************/
+/* osl_destroyThreadKey */
+/*****************************************************************************/
+void SAL_CALL osl_destroyThreadKey(oslThreadKey Key)
+{
+ if (Key != 0)
+ {
+ PTLS pTls = (PTLS)Key;
+
+ RemoveKeyFromList( pTls );
+ TlsFree( pTls->dwIndex );
+ rtl_freeMemory( pTls );
+ }
+}
+
+/*****************************************************************************/
+/* osl_getThreadKeyData */
+/*****************************************************************************/
+void* SAL_CALL osl_getThreadKeyData(oslThreadKey Key)
+{
+ if (Key != 0)
+ {
+ PTLS pTls = (PTLS)Key;
+
+ return (TlsGetValue( pTls->dwIndex ));
+ }
+
+ return (NULL);
+}
+
+/*****************************************************************************/
+/* osl_setThreadKeyData */
+/*****************************************************************************/
+sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData)
+{
+ if (Key != 0)
+ {
+ PTLS pTls = (PTLS)Key;
+ void* pOldData = NULL;
+ BOOL fSuccess;
+
+ if ( pTls->pfnCallback )
+ pOldData = TlsGetValue( pTls->dwIndex );
+
+ fSuccess = TlsSetValue( pTls->dwIndex, pData );
+
+ if ( fSuccess && pTls->pfnCallback && pOldData )
+ pTls->pfnCallback( pOldData );
+
+ return (sal_Bool)(fSuccess != FALSE);
+ }
+
+ return (sal_False);
+}
+
+
+/*****************************************************************************/
+/* osl_getThreadTextEncoding */
+/*****************************************************************************/
+
+DWORD g_dwTLSTextEncodingIndex = (DWORD)-1;
+
+
+rtl_TextEncoding SAL_CALL osl_getThreadTextEncoding(void)
+{
+ DWORD dwEncoding;
+ rtl_TextEncoding _encoding;
+ BOOL gotACP;
+
+ if ( (DWORD)-1 == g_dwTLSTextEncodingIndex )
+ g_dwTLSTextEncodingIndex = TlsAlloc();
+
+ dwEncoding = (DWORD)TlsGetValue( g_dwTLSTextEncodingIndex );
+ _encoding = LOWORD(dwEncoding);
+ gotACP = HIWORD(dwEncoding);
+
+
+ if ( !gotACP )
+ {
+ char *pszEncoding;
+
+ if ( NULL != (pszEncoding = getenv( "SOLAR_USER_RTL_TEXTENCODING" )) )
+ _encoding = (rtl_TextEncoding)atoi(pszEncoding);
+ else
+ _encoding = rtl_getTextEncodingFromWindowsCodePage( GetACP() );
+
+ TlsSetValue( g_dwTLSTextEncodingIndex, (LPVOID)MAKELONG( _encoding, TRUE ) );
+ }
+
+ return _encoding;
+}
+
+/*****************************************************************************/
+/* osl_getThreadTextEncoding */
+/*****************************************************************************/
+rtl_TextEncoding SAL_CALL osl_setThreadTextEncoding( rtl_TextEncoding Encoding )
+{
+ rtl_TextEncoding oldEncoding = osl_getThreadTextEncoding();
+
+ TlsSetValue( g_dwTLSTextEncodingIndex, (LPVOID)MAKELONG( Encoding, TRUE) );
+
+ return oldEncoding;
+}
+
+
+