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