Update ooo320-m1
[ooovba.git] / sal / osl / os2 / thread.c
blobab52976db0e781d256d0b7029a69d3f80994ae0e
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: thread.c,v $
10 * $Revision: 1.7 $
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 ************************************************************************/
32 #include "system.h"
34 #include <osl/diagnose.h>
35 #include <osl/thread.h>
36 #include <osl/time.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 */
47 sal_Int32 m_Flags;
48 HEV m_hEvent;
49 sal_uInt32 m_Timeout;
50 oslWorkerFunction m_WorkerFunction;
51 void* m_pData;
52 sal_Bool m_StartSuspended;
53 HAB m_hab;
54 HMQ m_hmq;
56 } osl_TThreadImpl;
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? */
73 return NULL;
75 else
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? */
87 return NULL;
89 else
91 return pThreadImpl->m_hmq;
96 /*****************************************************************************/
97 /* oslWorkerWrapperFunction */
98 /*****************************************************************************/
99 static void oslWorkerWrapperFunction(void* pData)
101 BOOL rc;
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);
106 #endif
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);
111 #endif
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);
115 #endif
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);
123 #endif
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);
128 #endif
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);
132 #endif
136 /*****************************************************************************/
137 /* oslCreateThread */
138 /*****************************************************************************/
139 static oslThread oslCreateThread(oslWorkerFunction pWorker,
140 void* pThreadData,
141 sal_Bool nFlags)
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 */
168 pThreadImpl );
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);
177 #endif
178 if(pThreadImpl->m_ThreadId == -1)
180 /* create failed */
181 if (pThreadImpl->m_hEvent != 0)
182 DosCloseEventSem(pThreadImpl->m_hEvent);
184 free(pThreadImpl);
185 return 0;
188 pThreadImpl->m_hEvent= 0;
190 return pThreadImpl;
194 /*****************************************************************************/
195 /* osl_createThread */
196 /*****************************************************************************/
197 oslThread SAL_CALL osl_createThread(oslWorkerFunction pWorker,
198 void* pThreadData)
200 return oslCreateThread(pWorker,pThreadData,sal_False);
203 /*****************************************************************************/
204 /* osl_createSuspendedThread */
205 /*****************************************************************************/
206 oslThread SAL_CALL osl_createSuspendedThread(oslWorkerFunction pWorker,
207 void* pThreadData)
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);
221 else
223 PTIB pptib = NULL;
224 PPIB pppib = NULL;
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 */
241 return;
244 if(pThreadImpl->m_ThreadId != -1) /* valid handle ? */
246 /* cancel thread */
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 */
261 return;
264 if (pThreadImpl->m_hEvent != 0)
265 DosCloseEventSem(pThreadImpl->m_hEvent);
267 /* free memory */
268 free(Thread);
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? */
307 switch(Priority) {
309 case osl_Thread_PriorityHighest:
311 nOs2PriorityClass = PRTYC_REGULAR;
312 nOs2PriorityDelta = PRTYD_MAXIMUM;
313 break;
315 case osl_Thread_PriorityAboveNormal:
317 nOs2PriorityClass = PRTYC_REGULAR;
318 nOs2PriorityDelta = 16;
319 break;
321 case osl_Thread_PriorityNormal:
323 nOs2PriorityClass = PRTYC_REGULAR;
324 nOs2PriorityDelta = 0;
325 break;
327 case osl_Thread_PriorityBelowNormal:
329 nOs2PriorityClass = PRTYC_REGULAR;
330 nOs2PriorityDelta = -16;
331 break;
333 case osl_Thread_PriorityLowest:
335 nOs2PriorityClass = PRTYC_REGULAR;
336 nOs2PriorityDelta = PRTYD_MINIMUM;
337 break;
339 case osl_Thread_PriorityUnknown:
340 OSL_ASSERT(FALSE); /* only fools try this...*/
342 /* let release-version behave friendly */
343 return;
345 default:
346 OSL_ASSERT(FALSE); /* enum expanded, but forgotten here...*/
348 /* let release-version behave friendly */
349 return;
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 */
382 PTIB pptib = NULL;
383 PPIB pppib = NULL;
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;
395 break;
397 case PRTYC_REGULAR:
399 if( nOs2PriorityDelta == 0 )
401 Priority= osl_Thread_PriorityNormal;
402 break;
405 if( nOs2PriorityDelta < -16 )
407 Priority= osl_Thread_PriorityLowest;
408 break;
411 if( nOs2PriorityDelta < 0 )
413 Priority= osl_Thread_PriorityBelowNormal;
414 break;
417 if( nOs2PriorityDelta > 0 )
419 Priority= osl_Thread_PriorityAboveNormal;
420 break;
423 Priority= osl_Thread_PriorityHighest;
424 break;
426 case PRTYC_IDLETIME:
427 Priority= osl_Thread_PriorityLowest;
428 break;
430 default:
431 OSL_ASSERT(FALSE); /* OS/2 API changed, incorporate new prio-level! */
433 /* release-version behaves friendly */
434 Priority= osl_Thread_PriorityUnknown;
437 return Priority;
440 /*****************************************************************************/
441 /* osl_isThreadRunning */
442 /*****************************************************************************/
443 sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread)
445 osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
446 APIRET rc;
448 /* invalid arguments ?*/
449 if(pThreadImpl==0 || pThreadImpl->m_ThreadId==-1)
451 return sal_False;
454 if( osl_getThreadIdentifier( 0 ) == osl_getThreadIdentifier( Thread ) )
455 return sal_True;
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 */
473 return;
476 DosWaitThread( &pThreadImpl->m_ThreadId, DCWW_WAIT );
479 /*****************************************************************************/
480 /* osl_waitThread */
481 /*****************************************************************************/
482 void SAL_CALL osl_waitThread(const TimeValue* pDelay)
484 int millisecs;
486 OSL_ASSERT(pDelay);
488 millisecs = pDelay->Seconds * 1000 + pDelay->Nanosec / 1000000;
490 DosSleep(millisecs);
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 */
504 return;
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;
520 osl_yieldThread();
522 /* invalid arguments?*/
523 if (pThreadImpl==0 || pThreadImpl->m_ThreadId==-1)
525 /* assume thread is not running */
526 return sal_False;
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()
552 DosSleep(0);
555 typedef struct _TLS
557 PULONG pulPtr;
558 oslThreadKeyCallbackFunction pfnCallback;
559 struct _TLS *pNext, *pPrev;
560 } TLS, *PTLS;
562 static PTLS g_pThreadKeyList = NULL;
564 static void AddKeyToList( PTLS pTls )
566 if ( pTls )
568 DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT );
570 pTls->pNext = g_pThreadKeyList;
571 pTls->pPrev = 0;
573 if ( g_pThreadKeyList )
574 g_pThreadKeyList->pPrev = pTls;
576 g_pThreadKeyList = pTls;
578 DosReleaseMutexSem( MutexLock);
582 static void RemoveKeyFromList( PTLS pTls )
584 if ( pTls )
586 DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT );
587 if ( pTls->pPrev )
588 pTls->pPrev->pNext = pTls->pNext;
589 else
591 OSL_ASSERT( pTls == g_pThreadKeyList );
592 g_pThreadKeyList = pTls->pNext;
595 if ( pTls->pNext )
596 pTls->pNext->pPrev = pTls->pPrev;
597 DosReleaseMutexSem( MutexLock);
601 void SAL_CALL _osl_callThreadKeyCallbackOnThreadDetach(void)
603 PTLS pTls;
605 DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT );
606 pTls = g_pThreadKeyList;
607 while ( pTls )
609 if ( pTls->pfnCallback )
611 void *pValue = (void*)*pTls->pulPtr;
613 if ( pValue )
614 pTls->pfnCallback( pValue );
617 pTls = pTls->pNext;
619 DosReleaseMutexSem( MutexLock);
622 /*****************************************************************************/
623 /* osl_createThreadKey */
624 /*****************************************************************************/
625 oslThreadKey SAL_CALL osl_createThreadKey(oslThreadKeyCallbackFunction pCallback)
627 PTLS pTls = (PTLS)rtl_allocateMemory( sizeof(TLS) );
629 if ( pTls )
631 pTls->pfnCallback = pCallback;
632 if (DosAllocThreadLocalMemory(1, &pTls->pulPtr) != NO_ERROR)
634 rtl_freeMemory( pTls );
635 pTls = 0;
637 else
639 *pTls->pulPtr = 0;
640 AddKeyToList( pTls );
644 return ((oslThreadKey)pTls);
647 /*****************************************************************************/
648 /* osl_destroyThreadKey */
649 /*****************************************************************************/
650 void SAL_CALL osl_destroyThreadKey(oslThreadKey Key)
652 if (Key != 0)
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)
667 if (Key != 0)
669 PTLS pTls = (PTLS)Key;
671 return ((void *) *pTls->pulPtr);
674 return (NULL);
677 /*****************************************************************************/
678 /* osl_setThreadKeyData */
679 /*****************************************************************************/
680 sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData)
682 if (Key != 0)
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);
699 return (sal_False);
704 /*****************************************************************************/
705 /* osl_getThreadTextEncoding */
706 /*****************************************************************************/
708 ULONG g_dwTLSTextEncodingIndex = (ULONG)-1;
710 sal_uInt32 SAL_CALL _GetACP( void)
712 APIRET rc;
713 ULONG aulCpList[8] = {0};
714 ULONG ulListSize;
716 rc = DosQueryCp( sizeof( aulCpList), aulCpList, &ulListSize);
717 if (rc)
718 return 437; // in case of error, return codepage EN_US
719 // current codepage is first of list, others are the prepared codepages.
720 return aulCpList[0];
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");
736 if (pszEncoding)
737 defaultEncoding = atoi(pszEncoding);
738 else
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");
751 if (pszEncoding)
752 _encoding = atoi(pszEncoding);
753 else
754 _encoding = rtl_getTextEncodingFromWindowsCodePage( _GetACP());
755 /* save for future reference */
756 osl_setThreadKeyData( g_dwTLSTextEncodingIndex, (void*)_encoding);
759 return _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);
771 return oldEncoding;