/************************************************************** * * 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 "system.h" #include #include #include #include #include #define INCL_DOSPROCESS #define INCL_DOSEXCEPTIONS #define INCL_DOSMODULEMGR #include /* Thread-data structure hidden behind oslThread: */ typedef struct _osl_TThreadImpl { TID m_ThreadId; /* identifier for this thread */ sal_Int32 m_Flags; HEV m_hEvent; sal_uInt32 m_Timeout; oslWorkerFunction m_WorkerFunction; void* m_pData; sal_Bool m_StartSuspended; HAB m_hab; HMQ m_hmq; } osl_TThreadImpl; #define THREADIMPL_FLAGS_TERMINATE 0x0001 #define THREADIMPL_FLAGS_SLEEP 0x0002 // static mutex to control access to private members of oslMutexImpl static HMTX MutexLock = NULL; /*****************************************************************************/ HAB osl_getPMinternal_HAB(oslThread hThread) { osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)hThread; if(pThreadImpl == NULL) /* valid ptr? */ { return NULL; } else { return pThreadImpl->m_hab; } } HMQ osl_getPMinternal_HMQ(oslThread hThread) { osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)hThread; if(pThreadImpl == NULL) /* valid ptr? */ { return NULL; } else { return pThreadImpl->m_hmq; } } /*****************************************************************************/ /* oslWorkerWrapperFunction */ /*****************************************************************************/ static void oslWorkerWrapperFunction(void* pData) { BOOL rc; osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)pData; #if OSL_DEBUG_LEVEL>0 printf("oslWorkerWrapperFunction pThreadImpl %x, pThreadImpl->m_ThreadId %d\n", pThreadImpl, pThreadImpl->m_ThreadId); #endif /* Inizialize PM for this thread */ pThreadImpl->m_hab = WinInitialize( 0 ); #if OSL_DEBUG_LEVEL>0 printf("pThreadImpl->m_ThreadId %d, pThreadImpl->m_hab %x\n", pThreadImpl->m_ThreadId,pThreadImpl->m_hab); #endif pThreadImpl->m_hmq = WinCreateMsgQueue( pThreadImpl->m_hab, 0 ); #if OSL_DEBUG_LEVEL>0 printf("pThreadImpl->m_ThreadId %d, pThreadImpl->m_hmq %x\n", pThreadImpl->m_ThreadId,pThreadImpl->m_hmq); #endif /* call worker-function with data */ pThreadImpl->m_WorkerFunction( pThreadImpl->m_pData ); /* Free all PM-resources for this thread */ #if OSL_DEBUG_LEVEL>0 printf("pThreadImpl->m_ThreadId %d, about to destroy queue\n", pThreadImpl->m_ThreadId); #endif rc = WinDestroyMsgQueue( pThreadImpl->m_hmq ); #if OSL_DEBUG_LEVEL>0 printf("pThreadImpl->m_ThreadId %d, WinDestroyMsgQueue rc=%d (should be 1)\n", pThreadImpl->m_ThreadId, rc); printf("pThreadImpl->m_ThreadId %d, about to terminate hab\n", pThreadImpl->m_ThreadId); #endif rc = WinTerminate( pThreadImpl->m_hab ); #if OSL_DEBUG_LEVEL>0 printf("pThreadImpl->m_ThreadId %d, WinTerminate rc=%d (should be 1)\n", pThreadImpl->m_ThreadId, rc); #endif } /*****************************************************************************/ /* oslCreateThread */ /*****************************************************************************/ static oslThread oslCreateThread(oslWorkerFunction pWorker, void* pThreadData, sal_Bool nFlags) { osl_TThreadImpl* pThreadImpl; /* alloc mem. for our internal data structure */ pThreadImpl = (osl_TThreadImpl*)malloc(sizeof(osl_TThreadImpl)); OSL_ASSERT(pThreadImpl); pThreadImpl->m_WorkerFunction= pWorker; pThreadImpl->m_pData= pThreadData; pThreadImpl->m_Flags = 0; pThreadImpl->m_hEvent = 0; pThreadImpl->m_Timeout = 0; pThreadImpl->m_StartSuspended = nFlags; pThreadImpl->m_hab = 0; pThreadImpl->m_hmq = 0; if ( nFlags == sal_True ) { DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT ); } pThreadImpl->m_ThreadId = (TID) _beginthread( oslWorkerWrapperFunction, /* worker-function */ NULL, /* unused parameter */ 1024*1024, /* max. Stacksize */ pThreadImpl ); if ( nFlags == sal_True ) { if( pThreadImpl->m_ThreadId != -1 ) DosSuspendThread( pThreadImpl->m_ThreadId ); DosReleaseMutexSem( MutexLock); } #if OSL_DEBUG_LEVEL>0 printf("oslCreateThread pThreadImpl %x, pThreadImpl->m_ThreadId %d\n", pThreadImpl, pThreadImpl->m_ThreadId); #endif if(pThreadImpl->m_ThreadId == -1) { /* create failed */ if (pThreadImpl->m_hEvent != 0) DosCloseEventSem(pThreadImpl->m_hEvent); free(pThreadImpl); return 0; } pThreadImpl->m_hEvent= 0; return pThreadImpl; } /*****************************************************************************/ /* osl_createThread */ /*****************************************************************************/ oslThread SAL_CALL osl_createThread(oslWorkerFunction pWorker, void* pThreadData) { return oslCreateThread(pWorker,pThreadData,sal_False); } /*****************************************************************************/ /* osl_createSuspendedThread */ /*****************************************************************************/ oslThread SAL_CALL osl_createSuspendedThread(oslWorkerFunction pWorker, void* pThreadData) { return oslCreateThread(pWorker,pThreadData,sal_True); } /*****************************************************************************/ /* osl_getThreadIdentifier */ /*****************************************************************************/ oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread) { osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; if (pThreadImpl != NULL) return ((oslThreadIdentifier)pThreadImpl->m_ThreadId); else { PTIB pptib = NULL; PPIB pppib = NULL; DosGetInfoBlocks( &pptib, &pppib ); return ((oslThreadIdentifier) pptib->tib_ptib2->tib2_ultid ); } } /*****************************************************************************/ /* 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; } if(pThreadImpl->m_ThreadId != -1) /* valid handle ? */ { /* cancel thread */ DosKillThread( pThreadImpl->m_ThreadId ); } } /*****************************************************************************/ /* osl_freeThreadHandle */ /*****************************************************************************/ void SAL_CALL osl_freeThreadHandle(oslThread Thread) { osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; if(Thread == 0) /* valid ptr? */ { /* thread already destroyed or not created */ return; } if (pThreadImpl->m_hEvent != 0) DosCloseEventSem(pThreadImpl->m_hEvent); /* free memory */ free(Thread); } /*****************************************************************************/ /* osl_resumeThread */ /*****************************************************************************/ void SAL_CALL osl_resumeThread(oslThread Thread) { osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; OSL_ASSERT(pThreadImpl); /* valid ptr? */ DosResumeThread( pThreadImpl->m_ThreadId ); } /*****************************************************************************/ /* osl_suspendThread */ /*****************************************************************************/ void SAL_CALL osl_suspendThread(oslThread Thread) { osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; OSL_ASSERT(pThreadImpl); /* valid ptr? */ DosSuspendThread( pThreadImpl->m_ThreadId ); } /*****************************************************************************/ /* osl_setThreadPriority */ /*****************************************************************************/ void SAL_CALL osl_setThreadPriority(oslThread Thread, oslThreadPriority Priority) { ULONG nOs2PriorityClass; ULONG nOs2PriorityDelta; osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; OSL_ASSERT(pThreadImpl); /* valid ptr? */ switch(Priority) { case osl_Thread_PriorityHighest: nOs2PriorityClass = PRTYC_REGULAR; nOs2PriorityDelta = PRTYD_MAXIMUM; break; case osl_Thread_PriorityAboveNormal: nOs2PriorityClass = PRTYC_REGULAR; nOs2PriorityDelta = 16; break; case osl_Thread_PriorityNormal: nOs2PriorityClass = PRTYC_REGULAR; nOs2PriorityDelta = 0; break; case osl_Thread_PriorityBelowNormal: nOs2PriorityClass = PRTYC_REGULAR; nOs2PriorityDelta = -16; break; case osl_Thread_PriorityLowest: nOs2PriorityClass = PRTYC_REGULAR; nOs2PriorityDelta = PRTYD_MINIMUM; 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; } DosSetPriority( PRTYS_THREAD, nOs2PriorityClass, nOs2PriorityDelta, pThreadImpl->m_ThreadId ); } /*****************************************************************************/ /* osl_getThreadPriority */ /*****************************************************************************/ #define BYTE1FROMULONG(ul) ((UCHAR) (ul)) #define BYTE2FROMULONG(ul) ((UCHAR) ((ULONG) ul >> 8)) oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread) { ULONG nOs2PriorityClass; ULONG nOs2PriorityDelta; oslThreadPriority Priority; osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; /* invalid arguments ?*/ if(pThreadImpl==NULL || pThreadImpl->m_ThreadId==-1) { return osl_Thread_PriorityUnknown; } /* get current priorities */ { PTIB pptib = NULL; PPIB pppib = NULL; DosGetInfoBlocks( &pptib, &pppib ); nOs2PriorityClass = BYTE1FROMULONG( pptib->tib_ptib2->tib2_ulpri ); nOs2PriorityDelta = BYTE2FROMULONG( pptib->tib_ptib2->tib2_ulpri ); } /* map OS2 priority to enum */ switch(nOs2PriorityClass) { case PRTYC_TIMECRITICAL: Priority= osl_Thread_PriorityHighest; break; case PRTYC_REGULAR: if( nOs2PriorityDelta == 0 ) { Priority= osl_Thread_PriorityNormal; break; } if( nOs2PriorityDelta < -16 ) { Priority= osl_Thread_PriorityLowest; break; } if( nOs2PriorityDelta < 0 ) { Priority= osl_Thread_PriorityBelowNormal; break; } if( nOs2PriorityDelta > 0 ) { Priority= osl_Thread_PriorityAboveNormal; break; } Priority= osl_Thread_PriorityHighest; break; case PRTYC_IDLETIME: Priority= osl_Thread_PriorityLowest; break; default: OSL_ASSERT(FALSE); /* OS/2 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; APIRET rc; /* invalid arguments ?*/ if(pThreadImpl==NULL || pThreadImpl->m_ThreadId==-1) { return sal_False; } if( osl_getThreadIdentifier( 0 ) == osl_getThreadIdentifier( Thread ) ) return sal_True; rc = DosWaitThread( &pThreadImpl->m_ThreadId, DCWW_NOWAIT ); return( rc != ERROR_INVALID_THREADID ); } /*****************************************************************************/ /* osl_joinWithThread */ /*****************************************************************************/ void SAL_CALL osl_joinWithThread(oslThread Thread) { osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; /* invalid arguments?*/ if(pThreadImpl==NULL || pThreadImpl->m_ThreadId==-1) { /* assume thread is not running */ return; } DosWaitThread( &pThreadImpl->m_ThreadId, DCWW_WAIT ); } /*****************************************************************************/ /* osl_waitThread */ /*****************************************************************************/ void SAL_CALL osl_waitThread(const TimeValue* pDelay) { int millisecs; OSL_ASSERT(pDelay); millisecs = pDelay->Seconds * 1000 + pDelay->Nanosec / 1000000; DosSleep(millisecs); } /*****************************************************************************/ /* osl_terminateThread */ /*****************************************************************************/ void SAL_CALL osl_terminateThread(oslThread Thread) { osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; /* invalid arguments?*/ if (pThreadImpl==NULL || pThreadImpl->m_ThreadId==-1) { /* assume thread is not running */ return; } DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT ); pThreadImpl->m_Flags |= THREADIMPL_FLAGS_TERMINATE; DosReleaseMutexSem( MutexLock); } /*****************************************************************************/ /* osl_scheduleThread */ /*****************************************************************************/ sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread) { osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread; osl_yieldThread(); /* invalid arguments?*/ if (pThreadImpl==NULL || pThreadImpl->m_ThreadId==-1) { /* assume thread is not running */ return sal_False; } if (pThreadImpl->m_Flags & THREADIMPL_FLAGS_SLEEP) { OSL_ASSERT (pThreadImpl->m_hEvent != 0); DosWaitEventSem(pThreadImpl->m_hEvent, pThreadImpl->m_Timeout); DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT ); pThreadImpl->m_Timeout = 0; pThreadImpl->m_Flags &= ~THREADIMPL_FLAGS_SLEEP; DosReleaseMutexSem( MutexLock); } return ((pThreadImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) == 0); } /*****************************************************************************/ /* osl_yieldThread */ /*****************************************************************************/ void SAL_CALL osl_yieldThread() { DosSleep(0); } void osl_setThreadName(char const * name) { (void) name; } typedef struct _TLS { PULONG pulPtr; oslThreadKeyCallbackFunction pfnCallback; struct _TLS *pNext, *pPrev; } TLS, *PTLS; static PTLS g_pThreadKeyList = NULL; static void AddKeyToList( PTLS pTls ) { if ( pTls ) { DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT ); pTls->pNext = g_pThreadKeyList; pTls->pPrev = NULL; if ( g_pThreadKeyList ) g_pThreadKeyList->pPrev = pTls; g_pThreadKeyList = pTls; DosReleaseMutexSem( MutexLock); } } static void RemoveKeyFromList( PTLS pTls ) { if ( pTls ) { DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT ); 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; DosReleaseMutexSem( MutexLock); } } void SAL_CALL _osl_callThreadKeyCallbackOnThreadDetach(void) { PTLS pTls; DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT ); pTls = g_pThreadKeyList; while ( pTls ) { if ( pTls->pfnCallback ) { void *pValue = (void*)*pTls->pulPtr; if ( pValue ) pTls->pfnCallback( pValue ); } pTls = pTls->pNext; } DosReleaseMutexSem( MutexLock); } /*****************************************************************************/ /* osl_createThreadKey */ /*****************************************************************************/ oslThreadKey SAL_CALL osl_createThreadKey(oslThreadKeyCallbackFunction pCallback) { PTLS pTls = (PTLS)rtl_allocateMemory( sizeof(TLS) ); if ( pTls ) { pTls->pfnCallback = pCallback; if (DosAllocThreadLocalMemory(1, &pTls->pulPtr) != NO_ERROR) { rtl_freeMemory( pTls ); pTls = NULL; } else { *pTls->pulPtr = 0; AddKeyToList( pTls ); } } return ((oslThreadKey)pTls); } /*****************************************************************************/ /* osl_destroyThreadKey */ /*****************************************************************************/ void SAL_CALL osl_destroyThreadKey(oslThreadKey Key) { if (Key != 0) { PTLS pTls = (PTLS)Key; RemoveKeyFromList( pTls ); DosFreeThreadLocalMemory(pTls->pulPtr); rtl_freeMemory( pTls ); } } /*****************************************************************************/ /* osl_getThreadKeyData */ /*****************************************************************************/ void * SAL_CALL osl_getThreadKeyData(oslThreadKey Key) { if (Key != 0) { PTLS pTls = (PTLS)Key; return ((void *) *pTls->pulPtr); } 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 = TRUE; //YD cannot fail if ( pTls->pfnCallback ) pOldData = (void*)*pTls->pulPtr; *pTls->pulPtr = (ULONG)pData; if ( fSuccess && pTls->pfnCallback && pOldData ) pTls->pfnCallback( pOldData ); return (sal_Bool)(fSuccess != FALSE); } return (sal_False); } /*****************************************************************************/ /* osl_getThreadTextEncoding */ /*****************************************************************************/ ULONG g_dwTLSTextEncodingIndex = (ULONG)-1; sal_uInt32 SAL_CALL _GetACP( void) { APIRET rc; ULONG aulCpList[8] = {0}; ULONG ulListSize; rc = DosQueryCp( sizeof( aulCpList), aulCpList, &ulListSize); if (rc) return 437; // in case of error, return codepage EN_US // current codepage is first of list, others are the prepared codepages. return aulCpList[0]; } rtl_TextEncoding SAL_CALL osl_getThreadTextEncoding(void) { rtl_TextEncoding _encoding; if ( (ULONG)-1 == g_dwTLSTextEncodingIndex ) { rtl_TextEncoding defaultEncoding; const char * pszEncoding; /* create thread specific data key */ g_dwTLSTextEncodingIndex = osl_createThreadKey( NULL); /* determine default text encoding */ pszEncoding = getenv ("SOLAR_USER_RTL_TEXTENCODING"); if (pszEncoding) defaultEncoding = atoi(pszEncoding); else defaultEncoding = rtl_getTextEncodingFromWindowsCodePage( _GetACP()); //OSL_ASSERT(defaultEncoding != RTL_TEXTENCODING_DONTKNOW); //g_thread.m_textencoding.m_default = defaultEncoding; osl_setThreadKeyData( g_dwTLSTextEncodingIndex, (void*)defaultEncoding); } _encoding = (rtl_TextEncoding)osl_getThreadKeyData( g_dwTLSTextEncodingIndex ); if (0 == _encoding) { const char * pszEncoding; /* determine default text encoding */ pszEncoding = getenv ("SOLAR_USER_RTL_TEXTENCODING"); if (pszEncoding) _encoding = atoi(pszEncoding); else _encoding = rtl_getTextEncodingFromWindowsCodePage( _GetACP()); /* save for future reference */ osl_setThreadKeyData( g_dwTLSTextEncodingIndex, (void*)_encoding); } return _encoding; } /*****************************************************************************/ /* osl_getThreadTextEncoding */ /*****************************************************************************/ rtl_TextEncoding SAL_CALL osl_setThreadTextEncoding( rtl_TextEncoding Encoding ) { rtl_TextEncoding oldEncoding = osl_getThreadTextEncoding(); osl_setThreadKeyData( g_dwTLSTextEncodingIndex, (void*)Encoding); return oldEncoding; }