merged tag ooo/DEV300_m102
[LibreOffice.git] / sal / osl / os2 / thread.c
blob0f0c396a407cc55a4cd2fda70a807c805d4f8400
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
29 #include "system.h"
31 #include <osl/diagnose.h>
32 #include <osl/thread.h>
33 #include <osl/time.h>
34 #include <rtl/alloc.h>
35 #include <rtl/tencinfo.h>
38 Thread-data structure hidden behind oslThread:
40 typedef struct _osl_TThreadImpl
43 TID m_ThreadId; /* identifier for this thread */
44 sal_Int32 m_Flags;
45 HEV m_hEvent;
46 sal_uInt32 m_Timeout;
47 oslWorkerFunction m_WorkerFunction;
48 void* m_pData;
49 sal_Bool m_StartSuspended;
50 HAB m_hab;
51 HMQ m_hmq;
53 } osl_TThreadImpl;
55 #define THREADIMPL_FLAGS_TERMINATE 0x0001
56 #define THREADIMPL_FLAGS_SLEEP 0x0002
59 // static mutex to control access to private members of oslMutexImpl
60 static HMTX MutexLock = NULL;
62 /*****************************************************************************/
64 HAB osl_getPMinternal_HAB(oslThread hThread)
66 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)hThread;
68 if(pThreadImpl == NULL) /* valid ptr? */
70 return NULL;
72 else
74 return pThreadImpl->m_hab;
78 HMQ osl_getPMinternal_HMQ(oslThread hThread)
80 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)hThread;
82 if(pThreadImpl == NULL) /* valid ptr? */
84 return NULL;
86 else
88 return pThreadImpl->m_hmq;
93 /*****************************************************************************/
94 /* oslWorkerWrapperFunction */
95 /*****************************************************************************/
96 static void oslWorkerWrapperFunction(void* pData)
98 BOOL rc;
99 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)pData;
101 #if OSL_DEBUG_LEVEL>0
102 printf("oslWorkerWrapperFunction pThreadImpl %x, pThreadImpl->m_ThreadId %d\n", pThreadImpl, pThreadImpl->m_ThreadId);
103 #endif
104 /* Inizialize PM for this thread */
105 pThreadImpl->m_hab = WinInitialize( 0 );
106 #if OSL_DEBUG_LEVEL>0
107 printf("pThreadImpl->m_ThreadId %d, pThreadImpl->m_hab %x\n", pThreadImpl->m_ThreadId,pThreadImpl->m_hab);
108 #endif
109 pThreadImpl->m_hmq = WinCreateMsgQueue( pThreadImpl->m_hab, 0 );
110 #if OSL_DEBUG_LEVEL>0
111 printf("pThreadImpl->m_ThreadId %d, pThreadImpl->m_hmq %x\n", pThreadImpl->m_ThreadId,pThreadImpl->m_hmq);
112 #endif
114 /* call worker-function with data */
115 pThreadImpl->m_WorkerFunction( pThreadImpl->m_pData );
117 /* Free all PM-resources for this thread */
118 #if OSL_DEBUG_LEVEL>0
119 printf("pThreadImpl->m_ThreadId %d, about to destroy queue\n", pThreadImpl->m_ThreadId);
120 #endif
121 rc = WinDestroyMsgQueue( pThreadImpl->m_hmq );
122 #if OSL_DEBUG_LEVEL>0
123 printf("pThreadImpl->m_ThreadId %d, WinDestroyMsgQueue rc=%d (should be 1)\n", pThreadImpl->m_ThreadId, rc);
124 printf("pThreadImpl->m_ThreadId %d, about to terminate hab\n", pThreadImpl->m_ThreadId);
125 #endif
126 rc = WinTerminate( pThreadImpl->m_hab );
127 #if OSL_DEBUG_LEVEL>0
128 printf("pThreadImpl->m_ThreadId %d, WinTerminate rc=%d (should be 1)\n", pThreadImpl->m_ThreadId, rc);
129 #endif
133 /*****************************************************************************/
134 /* oslCreateThread */
135 /*****************************************************************************/
136 static oslThread oslCreateThread(oslWorkerFunction pWorker,
137 void* pThreadData,
138 sal_Bool nFlags)
140 osl_TThreadImpl* pThreadImpl;
142 /* alloc mem. for our internal data structure */
143 pThreadImpl = (osl_TThreadImpl*)malloc(sizeof(osl_TThreadImpl));
145 OSL_ASSERT(pThreadImpl);
147 pThreadImpl->m_WorkerFunction= pWorker;
148 pThreadImpl->m_pData= pThreadData;
150 pThreadImpl->m_Flags = 0;
151 pThreadImpl->m_hEvent = 0;
152 pThreadImpl->m_Timeout = 0;
153 pThreadImpl->m_StartSuspended = nFlags;
154 pThreadImpl->m_hab = 0;
155 pThreadImpl->m_hmq = 0;
157 if ( nFlags == sal_True )
159 DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT );
162 pThreadImpl->m_ThreadId = (TID) _beginthread( oslWorkerWrapperFunction, /* worker-function */
163 NULL, /* unused parameter */
164 1024*1024, /* max. Stacksize */
165 pThreadImpl );
166 if ( nFlags == sal_True )
168 if( pThreadImpl->m_ThreadId != -1 )
169 DosSuspendThread( pThreadImpl->m_ThreadId );
170 DosReleaseMutexSem( MutexLock);
172 #if OSL_DEBUG_LEVEL>0
173 printf("oslCreateThread pThreadImpl %x, pThreadImpl->m_ThreadId %d\n", pThreadImpl, pThreadImpl->m_ThreadId);
174 #endif
175 if(pThreadImpl->m_ThreadId == -1)
177 /* create failed */
178 if (pThreadImpl->m_hEvent != 0)
179 DosCloseEventSem(pThreadImpl->m_hEvent);
181 free(pThreadImpl);
182 return 0;
185 pThreadImpl->m_hEvent= 0;
187 return pThreadImpl;
191 /*****************************************************************************/
192 /* osl_createThread */
193 /*****************************************************************************/
194 oslThread SAL_CALL osl_createThread(oslWorkerFunction pWorker,
195 void* pThreadData)
197 return oslCreateThread(pWorker,pThreadData,sal_False);
200 /*****************************************************************************/
201 /* osl_createSuspendedThread */
202 /*****************************************************************************/
203 oslThread SAL_CALL osl_createSuspendedThread(oslWorkerFunction pWorker,
204 void* pThreadData)
206 return oslCreateThread(pWorker,pThreadData,sal_True);
209 /*****************************************************************************/
210 /* osl_getThreadIdentifier */
211 /*****************************************************************************/
212 oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread)
214 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
216 if (pThreadImpl != NULL)
217 return ((oslThreadIdentifier)pThreadImpl->m_ThreadId);
218 else
220 PTIB pptib = NULL;
221 PPIB pppib = NULL;
223 DosGetInfoBlocks( &pptib, &pppib );
224 return ((oslThreadIdentifier) pptib->tib_ptib2->tib2_ultid );
228 /*****************************************************************************/
229 /* osl_destroyThread */
230 /*****************************************************************************/
231 void SAL_CALL osl_destroyThread(oslThread Thread)
233 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
235 if(Thread == 0) /* valid ptr? */
237 /* thread already destroyed or not created */
238 return;
241 if(pThreadImpl->m_ThreadId != -1) /* valid handle ? */
243 /* cancel thread */
244 DosKillThread( pThreadImpl->m_ThreadId );
248 /*****************************************************************************/
249 /* osl_freeThreadHandle */
250 /*****************************************************************************/
251 void SAL_CALL osl_freeThreadHandle(oslThread Thread)
253 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
255 if(Thread == 0) /* valid ptr? */
257 /* thread already destroyed or not created */
258 return;
261 if (pThreadImpl->m_hEvent != 0)
262 DosCloseEventSem(pThreadImpl->m_hEvent);
264 /* free memory */
265 free(Thread);
268 /*****************************************************************************/
269 /* osl_resumeThread */
270 /*****************************************************************************/
271 void SAL_CALL osl_resumeThread(oslThread Thread)
273 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
275 OSL_ASSERT(pThreadImpl); /* valid ptr? */
277 DosResumeThread( pThreadImpl->m_ThreadId );
280 /*****************************************************************************/
281 /* osl_suspendThread */
282 /*****************************************************************************/
283 void SAL_CALL osl_suspendThread(oslThread Thread)
285 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
287 OSL_ASSERT(pThreadImpl); /* valid ptr? */
289 DosSuspendThread( pThreadImpl->m_ThreadId );
292 /*****************************************************************************/
293 /* osl_setThreadPriority */
294 /*****************************************************************************/
295 void SAL_CALL osl_setThreadPriority(oslThread Thread,
296 oslThreadPriority Priority)
298 ULONG nOs2PriorityClass;
299 ULONG nOs2PriorityDelta;
300 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
302 OSL_ASSERT(pThreadImpl); /* valid ptr? */
304 switch(Priority) {
306 case osl_Thread_PriorityHighest:
308 nOs2PriorityClass = PRTYC_REGULAR;
309 nOs2PriorityDelta = PRTYD_MAXIMUM;
310 break;
312 case osl_Thread_PriorityAboveNormal:
314 nOs2PriorityClass = PRTYC_REGULAR;
315 nOs2PriorityDelta = 16;
316 break;
318 case osl_Thread_PriorityNormal:
320 nOs2PriorityClass = PRTYC_REGULAR;
321 nOs2PriorityDelta = 0;
322 break;
324 case osl_Thread_PriorityBelowNormal:
326 nOs2PriorityClass = PRTYC_REGULAR;
327 nOs2PriorityDelta = -16;
328 break;
330 case osl_Thread_PriorityLowest:
332 nOs2PriorityClass = PRTYC_REGULAR;
333 nOs2PriorityDelta = PRTYD_MINIMUM;
334 break;
336 case osl_Thread_PriorityUnknown:
337 OSL_ASSERT(FALSE); /* only fools try this...*/
339 /* let release-version behave friendly */
340 return;
342 default:
343 OSL_ASSERT(FALSE); /* enum expanded, but forgotten here...*/
345 /* let release-version behave friendly */
346 return;
349 DosSetPriority( PRTYS_THREAD,
350 nOs2PriorityClass, nOs2PriorityDelta,
351 pThreadImpl->m_ThreadId );
355 /*****************************************************************************/
356 /* osl_getThreadPriority */
357 /*****************************************************************************/
359 #define BYTE1FROMULONG(ul) ((UCHAR) (ul))
360 #define BYTE2FROMULONG(ul) ((UCHAR) ((ULONG) ul >> 8))
362 oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread)
364 ULONG nOs2PriorityClass;
365 ULONG nOs2PriorityDelta;
367 oslThreadPriority Priority;
369 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
371 /* invalid arguments ?*/
372 if(pThreadImpl==0 || pThreadImpl->m_ThreadId==-1)
374 return osl_Thread_PriorityUnknown;
377 /* get current priorities */
379 PTIB pptib = NULL;
380 PPIB pppib = NULL;
382 DosGetInfoBlocks( &pptib, &pppib );
383 nOs2PriorityClass = BYTE1FROMULONG( pptib->tib_ptib2->tib2_ulpri );
384 nOs2PriorityDelta = BYTE2FROMULONG( pptib->tib_ptib2->tib2_ulpri );
387 /* map OS2 priority to enum */
388 switch(nOs2PriorityClass)
390 case PRTYC_TIMECRITICAL:
391 Priority= osl_Thread_PriorityHighest;
392 break;
394 case PRTYC_REGULAR:
396 if( nOs2PriorityDelta == 0 )
398 Priority= osl_Thread_PriorityNormal;
399 break;
402 if( nOs2PriorityDelta < -16 )
404 Priority= osl_Thread_PriorityLowest;
405 break;
408 if( nOs2PriorityDelta < 0 )
410 Priority= osl_Thread_PriorityBelowNormal;
411 break;
414 if( nOs2PriorityDelta > 0 )
416 Priority= osl_Thread_PriorityAboveNormal;
417 break;
420 Priority= osl_Thread_PriorityHighest;
421 break;
423 case PRTYC_IDLETIME:
424 Priority= osl_Thread_PriorityLowest;
425 break;
427 default:
428 OSL_ASSERT(FALSE); /* OS/2 API changed, incorporate new prio-level! */
430 /* release-version behaves friendly */
431 Priority= osl_Thread_PriorityUnknown;
434 return Priority;
437 /*****************************************************************************/
438 /* osl_isThreadRunning */
439 /*****************************************************************************/
440 sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread)
442 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
443 APIRET rc;
445 /* invalid arguments ?*/
446 if(pThreadImpl==0 || pThreadImpl->m_ThreadId==-1)
448 return sal_False;
451 if( osl_getThreadIdentifier( 0 ) == osl_getThreadIdentifier( Thread ) )
452 return sal_True;
454 rc = DosWaitThread( &pThreadImpl->m_ThreadId, DCWW_NOWAIT );
456 return( rc != ERROR_INVALID_THREADID );
459 /*****************************************************************************/
460 /* osl_joinWithThread */
461 /*****************************************************************************/
462 void SAL_CALL osl_joinWithThread(oslThread Thread)
464 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
466 /* invalid arguments?*/
467 if(pThreadImpl==0 || pThreadImpl->m_ThreadId==-1)
469 /* assume thread is not running */
470 return;
473 DosWaitThread( &pThreadImpl->m_ThreadId, DCWW_WAIT );
476 /*****************************************************************************/
477 /* osl_waitThread */
478 /*****************************************************************************/
479 void SAL_CALL osl_waitThread(const TimeValue* pDelay)
481 int millisecs;
483 OSL_ASSERT(pDelay);
485 millisecs = pDelay->Seconds * 1000 + pDelay->Nanosec / 1000000;
487 DosSleep(millisecs);
490 /*****************************************************************************/
491 /* osl_terminateThread */
492 /*****************************************************************************/
493 void SAL_CALL osl_terminateThread(oslThread Thread)
495 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
497 /* invalid arguments?*/
498 if (pThreadImpl==0 || pThreadImpl->m_ThreadId==-1)
500 /* assume thread is not running */
501 return;
504 DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT );
505 pThreadImpl->m_Flags |= THREADIMPL_FLAGS_TERMINATE;
506 DosReleaseMutexSem( MutexLock);
510 /*****************************************************************************/
511 /* osl_scheduleThread */
512 /*****************************************************************************/
513 sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread)
515 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
517 osl_yieldThread();
519 /* invalid arguments?*/
520 if (pThreadImpl==0 || pThreadImpl->m_ThreadId==-1)
522 /* assume thread is not running */
523 return sal_False;
526 if (pThreadImpl->m_Flags & THREADIMPL_FLAGS_SLEEP)
528 OSL_ASSERT (pThreadImpl->m_hEvent != 0);
530 DosWaitEventSem(pThreadImpl->m_hEvent, pThreadImpl->m_Timeout);
532 DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT );
534 pThreadImpl->m_Timeout = 0;
536 pThreadImpl->m_Flags &= ~THREADIMPL_FLAGS_SLEEP;
538 DosReleaseMutexSem( MutexLock);
541 return ((pThreadImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) == 0);
544 /*****************************************************************************/
545 /* osl_yieldThread */
546 /*****************************************************************************/
547 void SAL_CALL osl_yieldThread()
549 DosSleep(0);
552 void osl_setThreadName(char const * name) {
553 (void) name;
556 typedef struct _TLS
558 PULONG pulPtr;
559 oslThreadKeyCallbackFunction pfnCallback;
560 struct _TLS *pNext, *pPrev;
561 } TLS, *PTLS;
563 static PTLS g_pThreadKeyList = NULL;
565 static void AddKeyToList( PTLS pTls )
567 if ( pTls )
569 DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT );
571 pTls->pNext = g_pThreadKeyList;
572 pTls->pPrev = 0;
574 if ( g_pThreadKeyList )
575 g_pThreadKeyList->pPrev = pTls;
577 g_pThreadKeyList = pTls;
579 DosReleaseMutexSem( MutexLock);
583 static void RemoveKeyFromList( PTLS pTls )
585 if ( pTls )
587 DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT );
588 if ( pTls->pPrev )
589 pTls->pPrev->pNext = pTls->pNext;
590 else
592 OSL_ASSERT( pTls == g_pThreadKeyList );
593 g_pThreadKeyList = pTls->pNext;
596 if ( pTls->pNext )
597 pTls->pNext->pPrev = pTls->pPrev;
598 DosReleaseMutexSem( MutexLock);
602 void SAL_CALL _osl_callThreadKeyCallbackOnThreadDetach(void)
604 PTLS pTls;
606 DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT );
607 pTls = g_pThreadKeyList;
608 while ( pTls )
610 if ( pTls->pfnCallback )
612 void *pValue = (void*)*pTls->pulPtr;
614 if ( pValue )
615 pTls->pfnCallback( pValue );
618 pTls = pTls->pNext;
620 DosReleaseMutexSem( MutexLock);
623 /*****************************************************************************/
624 /* osl_createThreadKey */
625 /*****************************************************************************/
626 oslThreadKey SAL_CALL osl_createThreadKey(oslThreadKeyCallbackFunction pCallback)
628 PTLS pTls = (PTLS)rtl_allocateMemory( sizeof(TLS) );
630 if ( pTls )
632 pTls->pfnCallback = pCallback;
633 if (DosAllocThreadLocalMemory(1, &pTls->pulPtr) != NO_ERROR)
635 rtl_freeMemory( pTls );
636 pTls = 0;
638 else
640 *pTls->pulPtr = 0;
641 AddKeyToList( pTls );
645 return ((oslThreadKey)pTls);
648 /*****************************************************************************/
649 /* osl_destroyThreadKey */
650 /*****************************************************************************/
651 void SAL_CALL osl_destroyThreadKey(oslThreadKey Key)
653 if (Key != 0)
655 PTLS pTls = (PTLS)Key;
657 RemoveKeyFromList( pTls );
658 DosFreeThreadLocalMemory(pTls->pulPtr);
659 rtl_freeMemory( pTls );
663 /*****************************************************************************/
664 /* osl_getThreadKeyData */
665 /*****************************************************************************/
666 void * SAL_CALL osl_getThreadKeyData(oslThreadKey Key)
668 if (Key != 0)
670 PTLS pTls = (PTLS)Key;
672 return ((void *) *pTls->pulPtr);
675 return (NULL);
678 /*****************************************************************************/
679 /* osl_setThreadKeyData */
680 /*****************************************************************************/
681 sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData)
683 if (Key != 0)
685 PTLS pTls = (PTLS)Key;
686 void* pOldData = NULL;
687 BOOL fSuccess = TRUE; //YD cannot fail
689 if ( pTls->pfnCallback )
690 pOldData = (void*)*pTls->pulPtr;
692 *pTls->pulPtr = (ULONG)pData;
694 if ( fSuccess && pTls->pfnCallback && pOldData )
695 pTls->pfnCallback( pOldData );
697 return (sal_Bool)(fSuccess != FALSE);
700 return (sal_False);
705 /*****************************************************************************/
706 /* osl_getThreadTextEncoding */
707 /*****************************************************************************/
709 ULONG g_dwTLSTextEncodingIndex = (ULONG)-1;
711 sal_uInt32 SAL_CALL _GetACP( void)
713 APIRET rc;
714 ULONG aulCpList[8] = {0};
715 ULONG ulListSize;
717 rc = DosQueryCp( sizeof( aulCpList), aulCpList, &ulListSize);
718 if (rc)
719 return 437; // in case of error, return codepage EN_US
720 // current codepage is first of list, others are the prepared codepages.
721 return aulCpList[0];
724 rtl_TextEncoding SAL_CALL osl_getThreadTextEncoding(void)
726 rtl_TextEncoding _encoding;
728 if ( (ULONG)-1 == g_dwTLSTextEncodingIndex ) {
729 rtl_TextEncoding defaultEncoding;
730 const char * pszEncoding;
732 /* create thread specific data key */
733 g_dwTLSTextEncodingIndex = osl_createThreadKey( NULL);
735 /* determine default text encoding */
736 pszEncoding = getenv ("SOLAR_USER_RTL_TEXTENCODING");
737 if (pszEncoding)
738 defaultEncoding = atoi(pszEncoding);
739 else
740 defaultEncoding = rtl_getTextEncodingFromWindowsCodePage( _GetACP());
742 //OSL_ASSERT(defaultEncoding != RTL_TEXTENCODING_DONTKNOW);
743 //g_thread.m_textencoding.m_default = defaultEncoding;
744 osl_setThreadKeyData( g_dwTLSTextEncodingIndex, (void*)defaultEncoding);
747 _encoding = (rtl_TextEncoding)osl_getThreadKeyData( g_dwTLSTextEncodingIndex );
748 if (0 == _encoding) {
749 const char * pszEncoding;
750 /* determine default text encoding */
751 pszEncoding = getenv ("SOLAR_USER_RTL_TEXTENCODING");
752 if (pszEncoding)
753 _encoding = atoi(pszEncoding);
754 else
755 _encoding = rtl_getTextEncodingFromWindowsCodePage( _GetACP());
756 /* save for future reference */
757 osl_setThreadKeyData( g_dwTLSTextEncodingIndex, (void*)_encoding);
760 return _encoding;
763 /*****************************************************************************/
764 /* osl_getThreadTextEncoding */
765 /*****************************************************************************/
766 rtl_TextEncoding SAL_CALL osl_setThreadTextEncoding( rtl_TextEncoding Encoding )
768 rtl_TextEncoding oldEncoding = osl_getThreadTextEncoding();
770 osl_setThreadKeyData( g_dwTLSTextEncodingIndex, (void*)Encoding);
772 return oldEncoding;