1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: thread.c,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
34 #include <osl/diagnose.h>
35 #include <osl/thread.h>
37 #include <rtl/alloc.h>
38 #include <rtl/tencinfo.h>
41 Thread-data structure hidden behind oslThread:
43 typedef struct _osl_TThreadImpl
46 TID m_ThreadId
; /* identifier for this thread */
50 oslWorkerFunction m_WorkerFunction
;
52 sal_Bool m_StartSuspended
;
58 #define THREADIMPL_FLAGS_TERMINATE 0x0001
59 #define THREADIMPL_FLAGS_SLEEP 0x0002
62 // static mutex to control access to private members of oslMutexImpl
63 static HMTX MutexLock
= NULL
;
65 /*****************************************************************************/
67 HAB
osl_getPMinternal_HAB(oslThread hThread
)
69 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)hThread
;
71 if(pThreadImpl
== NULL
) /* valid ptr? */
77 return pThreadImpl
->m_hab
;
81 HMQ
osl_getPMinternal_HMQ(oslThread hThread
)
83 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)hThread
;
85 if(pThreadImpl
== NULL
) /* valid ptr? */
91 return pThreadImpl
->m_hmq
;
96 /*****************************************************************************/
97 /* oslWorkerWrapperFunction */
98 /*****************************************************************************/
99 static void oslWorkerWrapperFunction(void* pData
)
102 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)pData
;
104 #if OSL_DEBUG_LEVEL>0
105 printf("oslWorkerWrapperFunction pThreadImpl %x, pThreadImpl->m_ThreadId %d\n", pThreadImpl
, pThreadImpl
->m_ThreadId
);
107 /* Inizialize PM for this thread */
108 pThreadImpl
->m_hab
= WinInitialize( 0 );
109 #if OSL_DEBUG_LEVEL>0
110 printf("pThreadImpl->m_ThreadId %d, pThreadImpl->m_hab %x\n", pThreadImpl
->m_ThreadId
,pThreadImpl
->m_hab
);
112 pThreadImpl
->m_hmq
= WinCreateMsgQueue( pThreadImpl
->m_hab
, 0 );
113 #if OSL_DEBUG_LEVEL>0
114 printf("pThreadImpl->m_ThreadId %d, pThreadImpl->m_hmq %x\n", pThreadImpl
->m_ThreadId
,pThreadImpl
->m_hmq
);
117 /* call worker-function with data */
118 pThreadImpl
->m_WorkerFunction( pThreadImpl
->m_pData
);
120 /* Free all PM-resources for this thread */
121 #if OSL_DEBUG_LEVEL>0
122 printf("pThreadImpl->m_ThreadId %d, about to destroy queue\n", pThreadImpl
->m_ThreadId
);
124 rc
= WinDestroyMsgQueue( pThreadImpl
->m_hmq
);
125 #if OSL_DEBUG_LEVEL>0
126 printf("pThreadImpl->m_ThreadId %d, WinDestroyMsgQueue rc=%d (should be 1)\n", pThreadImpl
->m_ThreadId
, rc
);
127 printf("pThreadImpl->m_ThreadId %d, about to terminate hab\n", pThreadImpl
->m_ThreadId
);
129 rc
= WinTerminate( pThreadImpl
->m_hab
);
130 #if OSL_DEBUG_LEVEL>0
131 printf("pThreadImpl->m_ThreadId %d, WinTerminate rc=%d (should be 1)\n", pThreadImpl
->m_ThreadId
, rc
);
136 /*****************************************************************************/
137 /* oslCreateThread */
138 /*****************************************************************************/
139 static oslThread
oslCreateThread(oslWorkerFunction pWorker
,
143 osl_TThreadImpl
* pThreadImpl
;
145 /* alloc mem. for our internal data structure */
146 pThreadImpl
= (osl_TThreadImpl
*)malloc(sizeof(osl_TThreadImpl
));
148 OSL_ASSERT(pThreadImpl
);
150 pThreadImpl
->m_WorkerFunction
= pWorker
;
151 pThreadImpl
->m_pData
= pThreadData
;
153 pThreadImpl
->m_Flags
= 0;
154 pThreadImpl
->m_hEvent
= 0;
155 pThreadImpl
->m_Timeout
= 0;
156 pThreadImpl
->m_StartSuspended
= nFlags
;
157 pThreadImpl
->m_hab
= 0;
158 pThreadImpl
->m_hmq
= 0;
160 if ( nFlags
== sal_True
)
162 DosRequestMutexSem( MutexLock
, SEM_INDEFINITE_WAIT
);
165 pThreadImpl
->m_ThreadId
= (TID
) _beginthread( oslWorkerWrapperFunction
, /* worker-function */
166 NULL
, /* unused parameter */
167 1024*1024, /* max. Stacksize */
169 if ( nFlags
== sal_True
)
171 if( pThreadImpl
->m_ThreadId
!= -1 )
172 DosSuspendThread( pThreadImpl
->m_ThreadId
);
173 DosReleaseMutexSem( MutexLock
);
175 #if OSL_DEBUG_LEVEL>0
176 printf("oslCreateThread pThreadImpl %x, pThreadImpl->m_ThreadId %d\n", pThreadImpl
, pThreadImpl
->m_ThreadId
);
178 if(pThreadImpl
->m_ThreadId
== -1)
181 if (pThreadImpl
->m_hEvent
!= 0)
182 DosCloseEventSem(pThreadImpl
->m_hEvent
);
188 pThreadImpl
->m_hEvent
= 0;
194 /*****************************************************************************/
195 /* osl_createThread */
196 /*****************************************************************************/
197 oslThread SAL_CALL
osl_createThread(oslWorkerFunction pWorker
,
200 return oslCreateThread(pWorker
,pThreadData
,sal_False
);
203 /*****************************************************************************/
204 /* osl_createSuspendedThread */
205 /*****************************************************************************/
206 oslThread SAL_CALL
osl_createSuspendedThread(oslWorkerFunction pWorker
,
209 return oslCreateThread(pWorker
,pThreadData
,sal_True
);
212 /*****************************************************************************/
213 /* osl_getThreadIdentifier */
214 /*****************************************************************************/
215 oslThreadIdentifier SAL_CALL
osl_getThreadIdentifier(oslThread Thread
)
217 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)Thread
;
219 if (pThreadImpl
!= NULL
)
220 return ((oslThreadIdentifier
)pThreadImpl
->m_ThreadId
);
226 DosGetInfoBlocks( &pptib
, &pppib
);
227 return ((oslThreadIdentifier
) pptib
->tib_ptib2
->tib2_ultid
);
231 /*****************************************************************************/
232 /* osl_destroyThread */
233 /*****************************************************************************/
234 void SAL_CALL
osl_destroyThread(oslThread Thread
)
236 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)Thread
;
238 if(Thread
== 0) /* valid ptr? */
240 /* thread already destroyed or not created */
244 if(pThreadImpl
->m_ThreadId
!= -1) /* valid handle ? */
247 DosKillThread( pThreadImpl
->m_ThreadId
);
251 /*****************************************************************************/
252 /* osl_freeThreadHandle */
253 /*****************************************************************************/
254 void SAL_CALL
osl_freeThreadHandle(oslThread Thread
)
256 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)Thread
;
258 if(Thread
== 0) /* valid ptr? */
260 /* thread already destroyed or not created */
264 if (pThreadImpl
->m_hEvent
!= 0)
265 DosCloseEventSem(pThreadImpl
->m_hEvent
);
271 /*****************************************************************************/
272 /* osl_resumeThread */
273 /*****************************************************************************/
274 void SAL_CALL
osl_resumeThread(oslThread Thread
)
276 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)Thread
;
278 OSL_ASSERT(pThreadImpl
); /* valid ptr? */
280 DosResumeThread( pThreadImpl
->m_ThreadId
);
283 /*****************************************************************************/
284 /* osl_suspendThread */
285 /*****************************************************************************/
286 void SAL_CALL
osl_suspendThread(oslThread Thread
)
288 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)Thread
;
290 OSL_ASSERT(pThreadImpl
); /* valid ptr? */
292 DosSuspendThread( pThreadImpl
->m_ThreadId
);
295 /*****************************************************************************/
296 /* osl_setThreadPriority */
297 /*****************************************************************************/
298 void SAL_CALL
osl_setThreadPriority(oslThread Thread
,
299 oslThreadPriority Priority
)
301 ULONG nOs2PriorityClass
;
302 ULONG nOs2PriorityDelta
;
303 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)Thread
;
305 OSL_ASSERT(pThreadImpl
); /* valid ptr? */
309 case osl_Thread_PriorityHighest
:
311 nOs2PriorityClass
= PRTYC_REGULAR
;
312 nOs2PriorityDelta
= PRTYD_MAXIMUM
;
315 case osl_Thread_PriorityAboveNormal
:
317 nOs2PriorityClass
= PRTYC_REGULAR
;
318 nOs2PriorityDelta
= 16;
321 case osl_Thread_PriorityNormal
:
323 nOs2PriorityClass
= PRTYC_REGULAR
;
324 nOs2PriorityDelta
= 0;
327 case osl_Thread_PriorityBelowNormal
:
329 nOs2PriorityClass
= PRTYC_REGULAR
;
330 nOs2PriorityDelta
= -16;
333 case osl_Thread_PriorityLowest
:
335 nOs2PriorityClass
= PRTYC_REGULAR
;
336 nOs2PriorityDelta
= PRTYD_MINIMUM
;
339 case osl_Thread_PriorityUnknown
:
340 OSL_ASSERT(FALSE
); /* only fools try this...*/
342 /* let release-version behave friendly */
346 OSL_ASSERT(FALSE
); /* enum expanded, but forgotten here...*/
348 /* let release-version behave friendly */
352 DosSetPriority( PRTYS_THREAD
,
353 nOs2PriorityClass
, nOs2PriorityDelta
,
354 pThreadImpl
->m_ThreadId
);
358 /*****************************************************************************/
359 /* osl_getThreadPriority */
360 /*****************************************************************************/
362 #define BYTE1FROMULONG(ul) ((UCHAR) (ul))
363 #define BYTE2FROMULONG(ul) ((UCHAR) ((ULONG) ul >> 8))
365 oslThreadPriority SAL_CALL
osl_getThreadPriority(const oslThread Thread
)
367 ULONG nOs2PriorityClass
;
368 ULONG nOs2PriorityDelta
;
370 oslThreadPriority Priority
;
372 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)Thread
;
374 /* invalid arguments ?*/
375 if(pThreadImpl
==0 || pThreadImpl
->m_ThreadId
==-1)
377 return osl_Thread_PriorityUnknown
;
380 /* get current priorities */
385 DosGetInfoBlocks( &pptib
, &pppib
);
386 nOs2PriorityClass
= BYTE1FROMULONG( pptib
->tib_ptib2
->tib2_ulpri
);
387 nOs2PriorityDelta
= BYTE2FROMULONG( pptib
->tib_ptib2
->tib2_ulpri
);
390 /* map OS2 priority to enum */
391 switch(nOs2PriorityClass
)
393 case PRTYC_TIMECRITICAL
:
394 Priority
= osl_Thread_PriorityHighest
;
399 if( nOs2PriorityDelta
== 0 )
401 Priority
= osl_Thread_PriorityNormal
;
405 if( nOs2PriorityDelta
< -16 )
407 Priority
= osl_Thread_PriorityLowest
;
411 if( nOs2PriorityDelta
< 0 )
413 Priority
= osl_Thread_PriorityBelowNormal
;
417 if( nOs2PriorityDelta
> 0 )
419 Priority
= osl_Thread_PriorityAboveNormal
;
423 Priority
= osl_Thread_PriorityHighest
;
427 Priority
= osl_Thread_PriorityLowest
;
431 OSL_ASSERT(FALSE
); /* OS/2 API changed, incorporate new prio-level! */
433 /* release-version behaves friendly */
434 Priority
= osl_Thread_PriorityUnknown
;
440 /*****************************************************************************/
441 /* osl_isThreadRunning */
442 /*****************************************************************************/
443 sal_Bool SAL_CALL
osl_isThreadRunning(const oslThread Thread
)
445 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)Thread
;
448 /* invalid arguments ?*/
449 if(pThreadImpl
==0 || pThreadImpl
->m_ThreadId
==-1)
454 if( osl_getThreadIdentifier( 0 ) == osl_getThreadIdentifier( Thread
) )
457 rc
= DosWaitThread( &pThreadImpl
->m_ThreadId
, DCWW_NOWAIT
);
459 return( rc
!= ERROR_INVALID_THREADID
);
462 /*****************************************************************************/
463 /* osl_joinWithThread */
464 /*****************************************************************************/
465 void SAL_CALL
osl_joinWithThread(oslThread Thread
)
467 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)Thread
;
469 /* invalid arguments?*/
470 if(pThreadImpl
==0 || pThreadImpl
->m_ThreadId
==-1)
472 /* assume thread is not running */
476 DosWaitThread( &pThreadImpl
->m_ThreadId
, DCWW_WAIT
);
479 /*****************************************************************************/
481 /*****************************************************************************/
482 void SAL_CALL
osl_waitThread(const TimeValue
* pDelay
)
488 millisecs
= pDelay
->Seconds
* 1000 + pDelay
->Nanosec
/ 1000000;
493 /*****************************************************************************/
494 /* osl_terminateThread */
495 /*****************************************************************************/
496 void SAL_CALL
osl_terminateThread(oslThread Thread
)
498 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)Thread
;
500 /* invalid arguments?*/
501 if (pThreadImpl
==0 || pThreadImpl
->m_ThreadId
==-1)
503 /* assume thread is not running */
507 DosRequestMutexSem( MutexLock
, SEM_INDEFINITE_WAIT
);
508 pThreadImpl
->m_Flags
|= THREADIMPL_FLAGS_TERMINATE
;
509 DosReleaseMutexSem( MutexLock
);
513 /*****************************************************************************/
514 /* osl_scheduleThread */
515 /*****************************************************************************/
516 sal_Bool SAL_CALL
osl_scheduleThread(oslThread Thread
)
518 osl_TThreadImpl
* pThreadImpl
= (osl_TThreadImpl
*)Thread
;
522 /* invalid arguments?*/
523 if (pThreadImpl
==0 || pThreadImpl
->m_ThreadId
==-1)
525 /* assume thread is not running */
529 if (pThreadImpl
->m_Flags
& THREADIMPL_FLAGS_SLEEP
)
531 OSL_ASSERT (pThreadImpl
->m_hEvent
!= 0);
533 DosWaitEventSem(pThreadImpl
->m_hEvent
, pThreadImpl
->m_Timeout
);
535 DosRequestMutexSem( MutexLock
, SEM_INDEFINITE_WAIT
);
537 pThreadImpl
->m_Timeout
= 0;
539 pThreadImpl
->m_Flags
&= ~THREADIMPL_FLAGS_SLEEP
;
541 DosReleaseMutexSem( MutexLock
);
544 return ((pThreadImpl
->m_Flags
& THREADIMPL_FLAGS_TERMINATE
) == 0);
547 /*****************************************************************************/
548 /* osl_yieldThread */
549 /*****************************************************************************/
550 void SAL_CALL
osl_yieldThread()
558 oslThreadKeyCallbackFunction pfnCallback
;
559 struct _TLS
*pNext
, *pPrev
;
562 static PTLS g_pThreadKeyList
= NULL
;
564 static void AddKeyToList( PTLS pTls
)
568 DosRequestMutexSem( MutexLock
, SEM_INDEFINITE_WAIT
);
570 pTls
->pNext
= g_pThreadKeyList
;
573 if ( g_pThreadKeyList
)
574 g_pThreadKeyList
->pPrev
= pTls
;
576 g_pThreadKeyList
= pTls
;
578 DosReleaseMutexSem( MutexLock
);
582 static void RemoveKeyFromList( PTLS pTls
)
586 DosRequestMutexSem( MutexLock
, SEM_INDEFINITE_WAIT
);
588 pTls
->pPrev
->pNext
= pTls
->pNext
;
591 OSL_ASSERT( pTls
== g_pThreadKeyList
);
592 g_pThreadKeyList
= pTls
->pNext
;
596 pTls
->pNext
->pPrev
= pTls
->pPrev
;
597 DosReleaseMutexSem( MutexLock
);
601 void SAL_CALL
_osl_callThreadKeyCallbackOnThreadDetach(void)
605 DosRequestMutexSem( MutexLock
, SEM_INDEFINITE_WAIT
);
606 pTls
= g_pThreadKeyList
;
609 if ( pTls
->pfnCallback
)
611 void *pValue
= (void*)*pTls
->pulPtr
;
614 pTls
->pfnCallback( pValue
);
619 DosReleaseMutexSem( MutexLock
);
622 /*****************************************************************************/
623 /* osl_createThreadKey */
624 /*****************************************************************************/
625 oslThreadKey SAL_CALL
osl_createThreadKey(oslThreadKeyCallbackFunction pCallback
)
627 PTLS pTls
= (PTLS
)rtl_allocateMemory( sizeof(TLS
) );
631 pTls
->pfnCallback
= pCallback
;
632 if (DosAllocThreadLocalMemory(1, &pTls
->pulPtr
) != NO_ERROR
)
634 rtl_freeMemory( pTls
);
640 AddKeyToList( pTls
);
644 return ((oslThreadKey
)pTls
);
647 /*****************************************************************************/
648 /* osl_destroyThreadKey */
649 /*****************************************************************************/
650 void SAL_CALL
osl_destroyThreadKey(oslThreadKey Key
)
654 PTLS pTls
= (PTLS
)Key
;
656 RemoveKeyFromList( pTls
);
657 DosFreeThreadLocalMemory(pTls
->pulPtr
);
658 rtl_freeMemory( pTls
);
662 /*****************************************************************************/
663 /* osl_getThreadKeyData */
664 /*****************************************************************************/
665 void * SAL_CALL
osl_getThreadKeyData(oslThreadKey Key
)
669 PTLS pTls
= (PTLS
)Key
;
671 return ((void *) *pTls
->pulPtr
);
677 /*****************************************************************************/
678 /* osl_setThreadKeyData */
679 /*****************************************************************************/
680 sal_Bool SAL_CALL
osl_setThreadKeyData(oslThreadKey Key
, void *pData
)
684 PTLS pTls
= (PTLS
)Key
;
685 void* pOldData
= NULL
;
686 BOOL fSuccess
= TRUE
; //YD cannot fail
688 if ( pTls
->pfnCallback
)
689 pOldData
= (void*)*pTls
->pulPtr
;
691 *pTls
->pulPtr
= (ULONG
)pData
;
693 if ( fSuccess
&& pTls
->pfnCallback
&& pOldData
)
694 pTls
->pfnCallback( pOldData
);
696 return (sal_Bool
)(fSuccess
!= FALSE
);
704 /*****************************************************************************/
705 /* osl_getThreadTextEncoding */
706 /*****************************************************************************/
708 ULONG g_dwTLSTextEncodingIndex
= (ULONG
)-1;
710 sal_uInt32 SAL_CALL
_GetACP( void)
713 ULONG aulCpList
[8] = {0};
716 rc
= DosQueryCp( sizeof( aulCpList
), aulCpList
, &ulListSize
);
718 return 437; // in case of error, return codepage EN_US
719 // current codepage is first of list, others are the prepared codepages.
723 rtl_TextEncoding SAL_CALL
osl_getThreadTextEncoding(void)
725 rtl_TextEncoding _encoding
;
727 if ( (ULONG
)-1 == g_dwTLSTextEncodingIndex
) {
728 rtl_TextEncoding defaultEncoding
;
729 const char * pszEncoding
;
731 /* create thread specific data key */
732 g_dwTLSTextEncodingIndex
= osl_createThreadKey( NULL
);
734 /* determine default text encoding */
735 pszEncoding
= getenv ("SOLAR_USER_RTL_TEXTENCODING");
737 defaultEncoding
= atoi(pszEncoding
);
739 defaultEncoding
= rtl_getTextEncodingFromWindowsCodePage( _GetACP());
741 //OSL_ASSERT(defaultEncoding != RTL_TEXTENCODING_DONTKNOW);
742 //g_thread.m_textencoding.m_default = defaultEncoding;
743 osl_setThreadKeyData( g_dwTLSTextEncodingIndex
, (void*)defaultEncoding
);
746 _encoding
= (rtl_TextEncoding
)osl_getThreadKeyData( g_dwTLSTextEncodingIndex
);
747 if (0 == _encoding
) {
748 const char * pszEncoding
;
749 /* determine default text encoding */
750 pszEncoding
= getenv ("SOLAR_USER_RTL_TEXTENCODING");
752 _encoding
= atoi(pszEncoding
);
754 _encoding
= rtl_getTextEncodingFromWindowsCodePage( _GetACP());
755 /* save for future reference */
756 osl_setThreadKeyData( g_dwTLSTextEncodingIndex
, (void*)_encoding
);
762 /*****************************************************************************/
763 /* osl_getThreadTextEncoding */
764 /*****************************************************************************/
765 rtl_TextEncoding SAL_CALL
osl_setThreadTextEncoding( rtl_TextEncoding Encoding
)
767 rtl_TextEncoding oldEncoding
= osl_getThreadTextEncoding();
769 osl_setThreadKeyData( g_dwTLSTextEncodingIndex
, (void*)Encoding
);