xref: /trunk/main/sal/osl/os2/thread.c (revision d8dff77764cb74143fabc617dc8ee25d946bae78)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 
25 #include "system.h"
26 
27 #include <osl/diagnose.h>
28 #include <osl/thread.h>
29 #include <osl/time.h>
30 #include <rtl/alloc.h>
31 #include <rtl/tencinfo.h>
32 
33 #define INCL_DOSPROCESS
34 #define INCL_DOSEXCEPTIONS
35 #define INCL_DOSMODULEMGR
36 #include <os2.h>
37 
38 /*
39     Thread-data structure hidden behind oslThread:
40 */
41 typedef struct _osl_TThreadImpl
42 {
43 
44     TID                  m_ThreadId;        /* identifier for this thread */
45     sal_Int32            m_Flags;
46     HEV                  m_hEvent;
47     sal_uInt32           m_Timeout;
48     oslWorkerFunction    m_WorkerFunction;
49     void*                m_pData;
50     sal_Bool             m_StartSuspended;
51     HAB                  m_hab;
52     HMQ                  m_hmq;
53 
54 } osl_TThreadImpl;
55 
56 #define THREADIMPL_FLAGS_TERMINATE    0x0001
57 #define THREADIMPL_FLAGS_SLEEP        0x0002
58 
59 
60 // static mutex to control access to private members of oslMutexImpl
61 static HMTX MutexLock = NULL;
62 
63 /*****************************************************************************/
64 
65 HAB osl_getPMinternal_HAB(oslThread hThread)
66 {
67     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)hThread;
68 
69     if(pThreadImpl == NULL) /* valid ptr? */
70     {
71         return NULL;
72     }
73     else
74     {
75         return pThreadImpl->m_hab;
76     }
77 }
78 
79 HMQ osl_getPMinternal_HMQ(oslThread hThread)
80 {
81     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)hThread;
82 
83     if(pThreadImpl == NULL) /* valid ptr? */
84     {
85         return NULL;
86     }
87     else
88     {
89         return pThreadImpl->m_hmq;
90     }
91 }
92 
93 
94 /*****************************************************************************/
95 /* oslWorkerWrapperFunction */
96 /*****************************************************************************/
97 static void oslWorkerWrapperFunction(void* pData)
98 {
99     BOOL rc;
100     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)pData;
101 
102 #if OSL_DEBUG_LEVEL>0
103 printf("oslWorkerWrapperFunction pThreadImpl %x, pThreadImpl->m_ThreadId %d\n", pThreadImpl, pThreadImpl->m_ThreadId);
104 #endif
105     /* Inizialize PM for this thread */
106     pThreadImpl->m_hab = WinInitialize( 0 );
107 #if OSL_DEBUG_LEVEL>0
108 printf("pThreadImpl->m_ThreadId %d, pThreadImpl->m_hab %x\n", pThreadImpl->m_ThreadId,pThreadImpl->m_hab);
109 #endif
110     pThreadImpl->m_hmq = WinCreateMsgQueue( pThreadImpl->m_hab, 0 );
111 #if OSL_DEBUG_LEVEL>0
112 printf("pThreadImpl->m_ThreadId %d, pThreadImpl->m_hmq %x\n", pThreadImpl->m_ThreadId,pThreadImpl->m_hmq);
113 #endif
114 
115     /* call worker-function with data */
116     pThreadImpl->m_WorkerFunction( pThreadImpl->m_pData );
117 
118     /* Free all PM-resources for this thread */
119 #if OSL_DEBUG_LEVEL>0
120 printf("pThreadImpl->m_ThreadId %d, about to destroy queue\n", pThreadImpl->m_ThreadId);
121 #endif
122     rc = WinDestroyMsgQueue( pThreadImpl->m_hmq );
123 #if OSL_DEBUG_LEVEL>0
124 printf("pThreadImpl->m_ThreadId %d, WinDestroyMsgQueue rc=%d (should be 1)\n", pThreadImpl->m_ThreadId, rc);
125 printf("pThreadImpl->m_ThreadId %d, about to terminate hab\n", pThreadImpl->m_ThreadId);
126 #endif
127     rc = WinTerminate( pThreadImpl->m_hab );
128 #if OSL_DEBUG_LEVEL>0
129 printf("pThreadImpl->m_ThreadId %d, WinTerminate rc=%d (should be 1)\n", pThreadImpl->m_ThreadId, rc);
130 
131 #endif
132 }
133 
134 
135 /*****************************************************************************/
136 /* oslCreateThread */
137 /*****************************************************************************/
138 static oslThread oslCreateThread(oslWorkerFunction pWorker,
139                                  void* pThreadData,
140                                  sal_Bool nFlags)
141 {
142     osl_TThreadImpl* pThreadImpl;
143 
144     /* alloc mem. for our internal data structure */
145     pThreadImpl = (osl_TThreadImpl*)malloc(sizeof(osl_TThreadImpl));
146 
147     OSL_ASSERT(pThreadImpl);
148 
149     pThreadImpl->m_WorkerFunction= pWorker;
150     pThreadImpl->m_pData= pThreadData;
151 
152     pThreadImpl->m_Flags   = 0;
153     pThreadImpl->m_hEvent  = 0;
154     pThreadImpl->m_Timeout = 0;
155     pThreadImpl->m_StartSuspended = nFlags;
156     pThreadImpl->m_hab = 0;
157     pThreadImpl->m_hmq = 0;
158 
159     if ( nFlags == sal_True )
160     {
161         DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT );
162     }
163 
164     pThreadImpl->m_ThreadId = (TID) _beginthread( oslWorkerWrapperFunction,    /* worker-function */
165                                                   NULL,                        /* unused parameter */
166                                                   1024*1024,                   /* max. Stacksize */
167                                                   pThreadImpl );
168     if ( nFlags == sal_True )
169     {
170         if( pThreadImpl->m_ThreadId != -1 )
171             DosSuspendThread( pThreadImpl->m_ThreadId );
172         DosReleaseMutexSem( MutexLock);
173     }
174 #if OSL_DEBUG_LEVEL>0
175 printf("oslCreateThread pThreadImpl %x, pThreadImpl->m_ThreadId %d\n", pThreadImpl, pThreadImpl->m_ThreadId);
176 #endif
177     if(pThreadImpl->m_ThreadId == -1)
178     {
179         /* create failed */
180         if (pThreadImpl->m_hEvent != 0)
181             DosCloseEventSem(pThreadImpl->m_hEvent);
182 
183         free(pThreadImpl);
184         return 0;
185     }
186 
187     pThreadImpl->m_hEvent= 0;
188 
189     return pThreadImpl;
190 
191 }
192 
193 /*****************************************************************************/
194 /* osl_createThread */
195 /*****************************************************************************/
196 oslThread SAL_CALL osl_createThread(oslWorkerFunction pWorker,
197                                  void* pThreadData)
198 {
199     return oslCreateThread(pWorker,pThreadData,sal_False);
200 }
201 
202 /*****************************************************************************/
203 /* osl_createSuspendedThread */
204 /*****************************************************************************/
205 oslThread SAL_CALL osl_createSuspendedThread(oslWorkerFunction pWorker,
206                                           void* pThreadData)
207 {
208     return oslCreateThread(pWorker,pThreadData,sal_True);
209 }
210 
211 /*****************************************************************************/
212 /* osl_getThreadIdentifier */
213 /*****************************************************************************/
214 oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread)
215 {
216     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
217 
218     if (pThreadImpl != NULL)
219         return ((oslThreadIdentifier)pThreadImpl->m_ThreadId);
220     else
221         {
222         PTIB pptib = NULL;
223         PPIB pppib = NULL;
224 
225         DosGetInfoBlocks( &pptib, &pppib );
226         return ((oslThreadIdentifier) pptib->tib_ptib2->tib2_ultid );
227         }
228 }
229 
230 /*****************************************************************************/
231 /* osl_destroyThread */
232 /*****************************************************************************/
233 void SAL_CALL osl_destroyThread(oslThread Thread)
234 {
235     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
236 
237     if(Thread == 0) /* valid ptr? */
238     {
239         /* thread already destroyed or not created */
240         return;
241     }
242 
243     if(pThreadImpl->m_ThreadId != -1)    /* valid handle ? */
244     {
245         /* cancel thread  */
246         DosKillThread( pThreadImpl->m_ThreadId );
247     }
248 }
249 
250 /*****************************************************************************/
251 /* osl_freeThreadHandle */
252 /*****************************************************************************/
253 void SAL_CALL osl_freeThreadHandle(oslThread Thread)
254 {
255     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
256 
257     if(Thread == 0)        /* valid ptr? */
258     {
259         /* thread already destroyed or not created */
260         return;
261     }
262 
263     if (pThreadImpl->m_hEvent != 0)
264         DosCloseEventSem(pThreadImpl->m_hEvent);
265 
266     /* free memory */
267     free(Thread);
268 }
269 
270 /*****************************************************************************/
271 /* osl_resumeThread */
272 /*****************************************************************************/
273 void SAL_CALL osl_resumeThread(oslThread Thread)
274 {
275     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
276 
277     OSL_ASSERT(pThreadImpl);        /* valid ptr? */
278 
279     DosResumeThread( pThreadImpl->m_ThreadId );
280 }
281 
282 /*****************************************************************************/
283 /* osl_suspendThread */
284 /*****************************************************************************/
285 void SAL_CALL osl_suspendThread(oslThread Thread)
286 {
287     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
288 
289     OSL_ASSERT(pThreadImpl);        /* valid ptr? */
290 
291     DosSuspendThread( pThreadImpl->m_ThreadId );
292 }
293 
294 /*****************************************************************************/
295 /* osl_setThreadPriority */
296 /*****************************************************************************/
297 void SAL_CALL osl_setThreadPriority(oslThread Thread,
298                            oslThreadPriority Priority)
299 {
300     ULONG nOs2PriorityClass;
301     ULONG nOs2PriorityDelta;
302     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
303 
304     OSL_ASSERT(pThreadImpl);        /* valid ptr? */
305 
306     switch(Priority) {
307 
308     case osl_Thread_PriorityHighest:
309 
310         nOs2PriorityClass = PRTYC_REGULAR;
311         nOs2PriorityDelta = PRTYD_MAXIMUM;
312         break;
313 
314     case osl_Thread_PriorityAboveNormal:
315 
316         nOs2PriorityClass = PRTYC_REGULAR;
317         nOs2PriorityDelta = 16;
318         break;
319 
320     case osl_Thread_PriorityNormal:
321 
322         nOs2PriorityClass = PRTYC_REGULAR;
323         nOs2PriorityDelta = 0;
324         break;
325 
326     case osl_Thread_PriorityBelowNormal:
327 
328         nOs2PriorityClass = PRTYC_REGULAR;
329         nOs2PriorityDelta = -16;
330         break;
331 
332     case osl_Thread_PriorityLowest:
333 
334         nOs2PriorityClass = PRTYC_REGULAR;
335         nOs2PriorityDelta = PRTYD_MINIMUM;
336         break;
337 
338     case osl_Thread_PriorityUnknown:
339         OSL_ASSERT(FALSE);        /* only fools try this...*/
340 
341         /* let release-version behave friendly */
342         return;
343 
344     default:
345         OSL_ASSERT(FALSE);        /* enum expanded, but forgotten here...*/
346 
347         /* let release-version behave friendly */
348         return;
349     }
350 
351     DosSetPriority( PRTYS_THREAD,
352                     nOs2PriorityClass, nOs2PriorityDelta,
353                     pThreadImpl->m_ThreadId );
354 
355 }
356 
357 /*****************************************************************************/
358 /* osl_getThreadPriority  */
359 /*****************************************************************************/
360 
361 #define BYTE1FROMULONG(ul) ((UCHAR) (ul))
362 #define BYTE2FROMULONG(ul) ((UCHAR) ((ULONG) ul >> 8))
363 
364 oslThreadPriority  SAL_CALL osl_getThreadPriority(const oslThread Thread)
365 {
366     ULONG nOs2PriorityClass;
367     ULONG nOs2PriorityDelta;
368 
369     oslThreadPriority Priority;
370 
371     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
372 
373     /* invalid arguments ?*/
374     if(pThreadImpl==NULL || pThreadImpl->m_ThreadId==-1)
375     {
376         return osl_Thread_PriorityUnknown;
377     }
378 
379     /* get current priorities */
380     {
381     PTIB pptib = NULL;
382     PPIB pppib = NULL;
383 
384     DosGetInfoBlocks( &pptib, &pppib );
385     nOs2PriorityClass = BYTE1FROMULONG( pptib->tib_ptib2->tib2_ulpri );
386     nOs2PriorityDelta = BYTE2FROMULONG( pptib->tib_ptib2->tib2_ulpri );
387     }
388 
389     /* map OS2 priority to enum */
390     switch(nOs2PriorityClass)
391     {
392     case PRTYC_TIMECRITICAL:
393         Priority= osl_Thread_PriorityHighest;
394         break;
395 
396     case PRTYC_REGULAR:
397 
398         if( nOs2PriorityDelta == 0 )
399         {
400             Priority= osl_Thread_PriorityNormal;
401             break;
402         }
403 
404         if( nOs2PriorityDelta < -16 )
405         {
406             Priority= osl_Thread_PriorityLowest;
407             break;
408         }
409 
410         if( nOs2PriorityDelta < 0 )
411         {
412             Priority= osl_Thread_PriorityBelowNormal;
413             break;
414         }
415 
416         if( nOs2PriorityDelta > 0 )
417         {
418             Priority= osl_Thread_PriorityAboveNormal;
419             break;
420         }
421 
422         Priority= osl_Thread_PriorityHighest;
423         break;
424 
425     case PRTYC_IDLETIME:
426         Priority= osl_Thread_PriorityLowest;
427         break;
428 
429     default:
430         OSL_ASSERT(FALSE);        /* OS/2 API changed, incorporate new prio-level! */
431 
432         /* release-version behaves friendly */
433         Priority= osl_Thread_PriorityUnknown;
434     }
435 
436     return Priority;
437 }
438 
439 /*****************************************************************************/
440 /* osl_isThreadRunning */
441 /*****************************************************************************/
442 sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread)
443 {
444     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
445     APIRET rc;
446 
447     /* invalid arguments ?*/
448     if(pThreadImpl==NULL || pThreadImpl->m_ThreadId==-1)
449     {
450         return sal_False;
451     }
452 
453     if( osl_getThreadIdentifier( 0 ) == osl_getThreadIdentifier( Thread ) )
454         return sal_True;
455 
456     rc = DosWaitThread( &pThreadImpl->m_ThreadId, DCWW_NOWAIT );
457 
458     return( rc != ERROR_INVALID_THREADID );
459 }
460 
461 /*****************************************************************************/
462 /* osl_joinWithThread */
463 /*****************************************************************************/
464 void SAL_CALL osl_joinWithThread(oslThread Thread)
465 {
466     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
467 
468     /* invalid arguments?*/
469     if(pThreadImpl==NULL || pThreadImpl->m_ThreadId==-1)
470     {
471         /* assume thread is not running */
472         return;
473     }
474 
475     DosWaitThread( &pThreadImpl->m_ThreadId, DCWW_WAIT );
476 }
477 
478 /*****************************************************************************/
479 /* osl_waitThread */
480 /*****************************************************************************/
481 void SAL_CALL osl_waitThread(const TimeValue* pDelay)
482 {
483     int millisecs;
484 
485     OSL_ASSERT(pDelay);
486 
487     millisecs = pDelay->Seconds * 1000 + pDelay->Nanosec / 1000000;
488 
489     DosSleep(millisecs);
490 }
491 
492 /*****************************************************************************/
493 /* osl_terminateThread */
494 /*****************************************************************************/
495 void SAL_CALL osl_terminateThread(oslThread Thread)
496 {
497     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
498 
499     /* invalid arguments?*/
500     if (pThreadImpl==NULL || pThreadImpl->m_ThreadId==-1)
501     {
502         /* assume thread is not running */
503         return;
504     }
505 
506     DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT );
507     pThreadImpl->m_Flags |= THREADIMPL_FLAGS_TERMINATE;
508     DosReleaseMutexSem( MutexLock);
509 }
510 
511 
512 /*****************************************************************************/
513 /* osl_scheduleThread */
514 /*****************************************************************************/
515 sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread)
516 {
517     osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
518 
519     osl_yieldThread();
520 
521     /* invalid arguments?*/
522     if (pThreadImpl==NULL || pThreadImpl->m_ThreadId==-1)
523     {
524         /* assume thread is not running */
525         return sal_False;
526     }
527 
528     if (pThreadImpl->m_Flags & THREADIMPL_FLAGS_SLEEP)
529     {
530         OSL_ASSERT (pThreadImpl->m_hEvent != 0);
531 
532         DosWaitEventSem(pThreadImpl->m_hEvent, pThreadImpl->m_Timeout);
533 
534         DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT );
535 
536         pThreadImpl->m_Timeout = 0;
537 
538         pThreadImpl->m_Flags &= ~THREADIMPL_FLAGS_SLEEP;
539 
540         DosReleaseMutexSem( MutexLock);
541     }
542 
543     return ((pThreadImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) == 0);
544 }
545 
546 /*****************************************************************************/
547 /* osl_yieldThread */
548 /*****************************************************************************/
549 void SAL_CALL osl_yieldThread()
550 {
551     DosSleep(0);
552 }
553 
554 void osl_setThreadName(char const * name) {
555     (void) name;
556 }
557 
558 typedef struct _TLS
559 {
560     PULONG                          pulPtr;
561     oslThreadKeyCallbackFunction    pfnCallback;
562     struct _TLS                     *pNext, *pPrev;
563 } TLS, *PTLS;
564 
565 static  PTLS        g_pThreadKeyList = NULL;
566 
567 static void AddKeyToList( PTLS pTls )
568 {
569     if ( pTls )
570     {
571         DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT );
572 
573         pTls->pNext = g_pThreadKeyList;
574         pTls->pPrev = NULL;
575 
576         if ( g_pThreadKeyList )
577             g_pThreadKeyList->pPrev = pTls;
578 
579         g_pThreadKeyList = pTls;
580 
581         DosReleaseMutexSem( MutexLock);
582     }
583 }
584 
585 static void RemoveKeyFromList( PTLS pTls )
586 {
587     if ( pTls )
588     {
589         DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT );
590         if ( pTls->pPrev )
591             pTls->pPrev->pNext = pTls->pNext;
592         else
593         {
594             OSL_ASSERT( pTls == g_pThreadKeyList );
595             g_pThreadKeyList = pTls->pNext;
596         }
597 
598         if ( pTls->pNext )
599             pTls->pNext->pPrev = pTls->pPrev;
600         DosReleaseMutexSem( MutexLock);
601     }
602 }
603 
604 void SAL_CALL _osl_callThreadKeyCallbackOnThreadDetach(void)
605 {
606     PTLS    pTls;
607 
608     DosRequestMutexSem( MutexLock, SEM_INDEFINITE_WAIT );
609     pTls = g_pThreadKeyList;
610     while ( pTls )
611     {
612         if ( pTls->pfnCallback )
613         {
614             void    *pValue = (void*)*pTls->pulPtr;
615 
616             if ( pValue )
617                 pTls->pfnCallback( pValue );
618         }
619 
620         pTls = pTls->pNext;
621     }
622     DosReleaseMutexSem( MutexLock);
623 }
624 
625 /*****************************************************************************/
626 /* osl_createThreadKey */
627 /*****************************************************************************/
628 oslThreadKey SAL_CALL osl_createThreadKey(oslThreadKeyCallbackFunction pCallback)
629 {
630     PTLS    pTls = (PTLS)rtl_allocateMemory( sizeof(TLS) );
631 
632     if ( pTls )
633     {
634         pTls->pfnCallback = pCallback;
635         if (DosAllocThreadLocalMemory(1, &pTls->pulPtr) != NO_ERROR)
636         {
637             rtl_freeMemory( pTls );
638             pTls = NULL;
639         }
640         else
641         {
642             *pTls->pulPtr = 0;
643             AddKeyToList( pTls );
644         }
645     }
646 
647     return ((oslThreadKey)pTls);
648 }
649 
650 /*****************************************************************************/
651 /* osl_destroyThreadKey */
652 /*****************************************************************************/
653 void SAL_CALL osl_destroyThreadKey(oslThreadKey Key)
654 {
655     if (Key != 0)
656     {
657         PTLS    pTls = (PTLS)Key;
658 
659         RemoveKeyFromList( pTls );
660         DosFreeThreadLocalMemory(pTls->pulPtr);
661         rtl_freeMemory( pTls );
662     }
663 }
664 
665 /*****************************************************************************/
666 /* osl_getThreadKeyData */
667 /*****************************************************************************/
668 void * SAL_CALL osl_getThreadKeyData(oslThreadKey Key)
669 {
670     if (Key != 0)
671     {
672         PTLS    pTls = (PTLS)Key;
673 
674         return ((void *) *pTls->pulPtr);
675     }
676 
677     return (NULL);
678 }
679 
680 /*****************************************************************************/
681 /* osl_setThreadKeyData */
682 /*****************************************************************************/
683 sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData)
684 {
685     if (Key != 0)
686     {
687         PTLS    pTls = (PTLS)Key;
688         void*   pOldData = NULL;
689         BOOL    fSuccess = TRUE; //YD cannot fail
690 
691         if ( pTls->pfnCallback )
692             pOldData = (void*)*pTls->pulPtr;
693 
694         *pTls->pulPtr = (ULONG)pData;
695 
696         if ( fSuccess && pTls->pfnCallback && pOldData )
697             pTls->pfnCallback( pOldData );
698 
699         return (sal_Bool)(fSuccess != FALSE);
700     }
701 
702     return (sal_False);
703 }
704 
705 
706 
707 /*****************************************************************************/
708 /* osl_getThreadTextEncoding */
709 /*****************************************************************************/
710 
711 ULONG   g_dwTLSTextEncodingIndex = (ULONG)-1;
712 
713 sal_uInt32 SAL_CALL _GetACP( void)
714 {
715     APIRET  rc;
716     ULONG   aulCpList[8]  = {0};
717     ULONG   ulListSize;
718 
719     rc = DosQueryCp( sizeof( aulCpList), aulCpList, &ulListSize);
720     if (rc)
721         return 437; // in case of error, return codepage EN_US
722     // current codepage is first of list, others are the prepared codepages.
723     return aulCpList[0];
724 }
725 
726 rtl_TextEncoding SAL_CALL osl_getThreadTextEncoding(void)
727 {
728     rtl_TextEncoding    _encoding;
729 
730     if ( (ULONG)-1 == g_dwTLSTextEncodingIndex ) {
731         rtl_TextEncoding defaultEncoding;
732         const char *     pszEncoding;
733 
734         /* create thread specific data key */
735         g_dwTLSTextEncodingIndex = osl_createThreadKey( NULL);
736 
737         /* determine default text encoding */
738         pszEncoding = getenv ("SOLAR_USER_RTL_TEXTENCODING");
739         if (pszEncoding)
740             defaultEncoding = atoi(pszEncoding);
741         else
742             defaultEncoding = rtl_getTextEncodingFromWindowsCodePage( _GetACP());
743 
744         //OSL_ASSERT(defaultEncoding != RTL_TEXTENCODING_DONTKNOW);
745         //g_thread.m_textencoding.m_default = defaultEncoding;
746         osl_setThreadKeyData( g_dwTLSTextEncodingIndex, (void*)defaultEncoding);
747     }
748 
749     _encoding = (rtl_TextEncoding)osl_getThreadKeyData( g_dwTLSTextEncodingIndex );
750     if (0 == _encoding) {
751         const char *     pszEncoding;
752         /* determine default text encoding */
753         pszEncoding = getenv ("SOLAR_USER_RTL_TEXTENCODING");
754         if (pszEncoding)
755             _encoding = atoi(pszEncoding);
756         else
757             _encoding = rtl_getTextEncodingFromWindowsCodePage( _GetACP());
758         /* save for future reference */
759         osl_setThreadKeyData( g_dwTLSTextEncodingIndex, (void*)_encoding);
760     }
761 
762     return _encoding;
763 }
764 
765 /*****************************************************************************/
766 /* osl_getThreadTextEncoding */
767 /*****************************************************************************/
768 rtl_TextEncoding SAL_CALL osl_setThreadTextEncoding( rtl_TextEncoding Encoding )
769 {
770     rtl_TextEncoding oldEncoding = osl_getThreadTextEncoding();
771 
772     osl_setThreadKeyData( g_dwTLSTextEncodingIndex, (void*)Encoding);
773 
774     return oldEncoding;
775 }
776