xref: /trunk/main/sal/osl/w32/thread.c (revision 509a48ff)
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 #include "system.h"
25 
26 #include <osl/diagnose.h>
27 #include <osl/thread.h>
28 #include <rtl/alloc.h>
29 #include <osl/time.h>
30 #include <osl/interlck.h>
31 #include <rtl/tencinfo.h>
32 
33 /*
34 	Thread-data structure hidden behind oslThread:
35 */
36 typedef struct _osl_TThreadImpl
37 {
38 	HANDLE				m_hThread;		/* OS-handle used for all thread-functions */
39 	unsigned			m_ThreadId;		/* identifier for this thread */
40 	sal_Int32			m_nTerminationRequested;
41 	oslWorkerFunction	m_WorkerFunction;
42 	void*				m_pData;
43 
44 } osl_TThreadImpl;
45 
46 #define THREADIMPL_FLAGS_TERMINATE	0x0001
47 
48 static unsigned __stdcall oslWorkerWrapperFunction(void* pData);
49 static oslThread oslCreateThread(oslWorkerFunction pWorker, void* pThreadData, sal_uInt32 nFlags);
50 
51 /*****************************************************************************/
52 /* oslWorkerWrapperFunction */
53 /*****************************************************************************/
oslWorkerWrapperFunction(void * pData)54 static unsigned __stdcall oslWorkerWrapperFunction(void* pData)
55 {
56 	osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)pData;
57 
58 	/* Initialize COM */
59 
60     CoInitializeEx(NULL, COINIT_MULTITHREADED);
61 
62 	/* call worker-function with data */
63 
64 	pThreadImpl->m_WorkerFunction(pThreadImpl->m_pData);
65 
66 	CoUninitialize();
67 
68 	return (0);
69 }
70 
71 /*****************************************************************************/
72 /* oslCreateThread */
73 /*****************************************************************************/
oslCreateThread(oslWorkerFunction pWorker,void * pThreadData,sal_uInt32 nFlags)74 static oslThread oslCreateThread(oslWorkerFunction pWorker,
75                                  void* pThreadData,
76                                  sal_uInt32 nFlags)
77 {
78 	osl_TThreadImpl* pThreadImpl;
79 
80 	/* alloc mem. for our internal data structure */
81 	pThreadImpl= malloc(sizeof(osl_TThreadImpl));
82 
83 	OSL_ASSERT(pThreadImpl);
84 
85     if ( pThreadImpl == NULL )
86     {
87         return 0;
88     }
89 
90 	pThreadImpl->m_WorkerFunction= pWorker;
91 	pThreadImpl->m_pData= pThreadData;
92 	pThreadImpl->m_nTerminationRequested= 0;
93 
94 	pThreadImpl->m_hThread=
95 		(HANDLE)_beginthreadex(NULL,						/* no security */
96 							   0,							/* default stack-size */
97 							   oslWorkerWrapperFunction,	/* worker-function */
98 							   pThreadImpl,					/* provide worker-function with data */
99 							   nFlags,						/* start thread immediately or suspended */
100 							   &pThreadImpl->m_ThreadId);
101 
102 	if(pThreadImpl->m_hThread == 0)
103 	{
104 		/* create failed */
105 		free(pThreadImpl);
106 		return 0;
107 	}
108 
109 	return (oslThread)pThreadImpl;
110 }
111 
112 /*****************************************************************************/
113 /* osl_createThread */
114 /*****************************************************************************/
osl_createThread(oslWorkerFunction pWorker,void * pThreadData)115 oslThread SAL_CALL osl_createThread(oslWorkerFunction pWorker,
116                                     void* pThreadData)
117 {
118     return oslCreateThread(pWorker, pThreadData, 0);
119 }
120 
121 /*****************************************************************************/
122 /* osl_createSuspendedThread */
123 /*****************************************************************************/
osl_createSuspendedThread(oslWorkerFunction pWorker,void * pThreadData)124 oslThread SAL_CALL osl_createSuspendedThread(oslWorkerFunction pWorker,
125                                              void* pThreadData)
126 {
127     return oslCreateThread(pWorker, pThreadData, CREATE_SUSPENDED);
128 }
129 
130 /*****************************************************************************/
131 /* osl_getThreadIdentifier */
132 /*****************************************************************************/
osl_getThreadIdentifier(oslThread Thread)133 oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread)
134 {
135 	osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
136 
137 	if (pThreadImpl != NULL)
138 		return ((oslThreadIdentifier)pThreadImpl->m_ThreadId);
139 	else
140 		return ((oslThreadIdentifier)GetCurrentThreadId());
141 }
142 
143 /*****************************************************************************/
144 /* osl_destroyThread */
145 /*****************************************************************************/
osl_destroyThread(oslThread Thread)146 void SAL_CALL osl_destroyThread(oslThread Thread)
147 {
148 	osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
149 
150 	if (Thread == 0) /* valid ptr? */
151 	{
152 		/* thread already destroyed or not created */
153 		return;
154 	}
155 
156     /* !!!! _exitthreadex does _not_ call CloseHandle !!! */
157     CloseHandle( pThreadImpl->m_hThread );
158 
159 	/* free memory */
160 	free(Thread);
161 }
162 
163 /*****************************************************************************/
164 /* osl_resumeThread */
165 /*****************************************************************************/
osl_resumeThread(oslThread Thread)166 void SAL_CALL osl_resumeThread(oslThread Thread)
167 {
168 	osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
169 
170 	OSL_ASSERT(pThreadImpl);		/* valid ptr? */
171 
172 	ResumeThread(pThreadImpl->m_hThread);
173 }
174 
175 /*****************************************************************************/
176 /* osl_suspendThread */
177 /*****************************************************************************/
osl_suspendThread(oslThread Thread)178 void SAL_CALL osl_suspendThread(oslThread Thread)
179 {
180 	osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
181 
182 	OSL_ASSERT(pThreadImpl);		/* valid ptr? */
183 
184 	SuspendThread(pThreadImpl->m_hThread);
185 }
186 
187 /*****************************************************************************/
188 /* osl_setThreadPriority */
189 /*****************************************************************************/
osl_setThreadPriority(oslThread Thread,oslThreadPriority Priority)190 void SAL_CALL osl_setThreadPriority(oslThread Thread,
191 						   oslThreadPriority Priority)
192 {
193 	int winPriority;
194 	osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
195 
196 	OSL_ASSERT(pThreadImpl);		/* valid ptr? */
197 
198 
199 	/*	map enum to WIN32 levels
200 		it would be faster and more elegant to preset
201 		the enums, but that would require an #ifdef in
202 		the exported header, which is not desired.
203 	*/
204 	switch(Priority) {
205 
206 	case osl_Thread_PriorityHighest:
207 		winPriority= THREAD_PRIORITY_HIGHEST;
208 		break;
209 
210 	case osl_Thread_PriorityAboveNormal:
211 		winPriority= THREAD_PRIORITY_ABOVE_NORMAL;
212 		break;
213 
214 	case osl_Thread_PriorityNormal:
215 		winPriority= THREAD_PRIORITY_NORMAL;
216 		break;
217 
218 	case osl_Thread_PriorityBelowNormal:
219 		winPriority= THREAD_PRIORITY_BELOW_NORMAL;
220 		break;
221 
222 	case osl_Thread_PriorityLowest:
223 		winPriority= THREAD_PRIORITY_LOWEST;
224 		break;
225 
226 	case osl_Thread_PriorityUnknown:
227 		OSL_ASSERT(FALSE);		/* only fools try this...*/
228 
229 		/* let release-version behave friendly */
230 		return;
231 
232 	default:
233 		OSL_ASSERT(FALSE);		/* enum expanded, but forgotten here...*/
234 
235 		/* let release-version behave friendly */
236 		return;
237 	}
238 
239 	SetThreadPriority(pThreadImpl->m_hThread, winPriority);
240 }
241 
242 /*****************************************************************************/
243 /* osl_getThreadPriority  */
244 /*****************************************************************************/
osl_getThreadPriority(const oslThread Thread)245 oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread)
246 {
247 	int winPriority;
248 	oslThreadPriority Priority;
249 
250 	osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
251 
252 	/* invalid arguments ?*/
253 	if(pThreadImpl==NULL || pThreadImpl->m_hThread==0)
254 	{
255 		return osl_Thread_PriorityUnknown;
256 	}
257 
258 	winPriority=
259 		GetThreadPriority(pThreadImpl->m_hThread);
260 
261 
262 	if(winPriority == THREAD_PRIORITY_ERROR_RETURN)
263 	{
264 		return osl_Thread_PriorityUnknown;
265 	}
266 
267 	/* map WIN32 priority to enum */
268 	switch(winPriority)
269 	{
270 	case THREAD_PRIORITY_TIME_CRITICAL:
271 	case THREAD_PRIORITY_HIGHEST:
272 		Priority= osl_Thread_PriorityHighest;
273 		break;
274 
275 	case THREAD_PRIORITY_ABOVE_NORMAL:
276 		Priority= osl_Thread_PriorityAboveNormal;
277 		break;
278 
279 	case THREAD_PRIORITY_NORMAL:
280 		Priority= osl_Thread_PriorityNormal;
281 		break;
282 
283 	case THREAD_PRIORITY_BELOW_NORMAL:
284 		Priority= osl_Thread_PriorityBelowNormal;
285 		break;
286 
287 	case THREAD_PRIORITY_IDLE:
288 	case THREAD_PRIORITY_LOWEST:
289 		Priority= osl_Thread_PriorityLowest;
290 		break;
291 
292 	default:
293 		OSL_ASSERT(FALSE);		/* WIN32 API changed, incorporate new prio-level! */
294 
295 		/* release-version behaves friendly */
296 		Priority= osl_Thread_PriorityUnknown;
297 	}
298 
299 	return Priority;
300 }
301 
302 /*****************************************************************************/
303 /* osl_isThreadRunning */
304 /*****************************************************************************/
osl_isThreadRunning(const oslThread Thread)305 sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread)
306 {
307 	osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
308 
309 	/* invalid arguments ?*/
310 	if(pThreadImpl==NULL || pThreadImpl->m_hThread==0)
311 	{
312 		return sal_False;
313 	}
314 
315 	return (sal_Bool)(WaitForSingleObject(pThreadImpl->m_hThread, 0) != WAIT_OBJECT_0);
316 }
317 
318 /*****************************************************************************/
319 /* osl_joinWithThread */
320 /*****************************************************************************/
osl_joinWithThread(oslThread Thread)321 void SAL_CALL osl_joinWithThread(oslThread Thread)
322 {
323 	osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
324 
325 	/* invalid arguments?*/
326 	if(pThreadImpl==NULL || pThreadImpl->m_hThread==0)
327 	{
328 		/* assume thread is not running */
329 		return;
330 	}
331 
332 	WaitForSingleObject(pThreadImpl->m_hThread, INFINITE);
333 }
334 
335 /*****************************************************************************/
336 /* osl_waitThread */
337 /*****************************************************************************/
osl_waitThread(const TimeValue * pDelay)338 void SAL_CALL osl_waitThread(const TimeValue* pDelay)
339 {
340 	if (pDelay)
341 	{
342 		DWORD millisecs = pDelay->Seconds * 1000L + pDelay->Nanosec / 1000000L;
343 
344 		Sleep(millisecs);
345 	}
346 }
347 
348 /*****************************************************************************/
349 /* osl_terminateThread */
350 /*****************************************************************************/
osl_terminateThread(oslThread Thread)351 void SAL_CALL osl_terminateThread(oslThread Thread)
352 {
353 	osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
354 
355 	/* invalid arguments?*/
356 	if (pThreadImpl==NULL || pThreadImpl->m_hThread==0)
357 	{
358 		/* assume thread is not running */
359 		return;
360 	}
361 
362     osl_incrementInterlockedCount(&(pThreadImpl->m_nTerminationRequested));
363 }
364 
365 
366 /*****************************************************************************/
367 /* osl_scheduleThread */
368 /*****************************************************************************/
osl_scheduleThread(oslThread Thread)369 sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread)
370 {
371 	osl_TThreadImpl* pThreadImpl= (osl_TThreadImpl*)Thread;
372 
373 	osl_yieldThread();
374 
375 	/* invalid arguments?*/
376 	if (pThreadImpl==NULL || pThreadImpl->m_hThread==0)
377 	{
378 		/* assume thread is not running */
379 		return sal_False;
380 	}
381 
382 	return (sal_Bool)(0 == pThreadImpl->m_nTerminationRequested);
383 }
384 
385 /*****************************************************************************/
386 /* osl_yieldThread */
387 /*****************************************************************************/
osl_yieldThread(void)388 void SAL_CALL osl_yieldThread(void)
389 {
390 	Sleep(0);
391 }
392 
osl_setThreadName(char const * name)393 void SAL_CALL osl_setThreadName(char const * name) {
394 #ifdef _MSC_VER
395     /* See <http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx>: */
396 #pragma pack(push, 8)
397     struct {
398         DWORD dwType;
399         LPCSTR szName;
400         DWORD dwThreadID;
401         DWORD dwFlags;
402     } info;
403 #pragma pack(pop)
404     info.dwType = 0x1000;
405     info.szName = name;
406     info.dwThreadID = (DWORD) -1;
407     info.dwFlags = 0;
408     __try {
409         RaiseException(
410             0x406D1388, 0, sizeof info / sizeof (ULONG_PTR),
411             (ULONG_PTR *) &info);
412     } __except (EXCEPTION_EXECUTE_HANDLER) {}
413 #else
414     (void) name;
415 #endif
416 }
417 
418 typedef struct _TLS
419 {
420 	DWORD							dwIndex;
421 	oslThreadKeyCallbackFunction	pfnCallback;
422 	struct _TLS						*pNext, *pPrev;
423 } TLS, *PTLS;
424 
425 static	PTLS		g_pThreadKeyList = NULL;
426 CRITICAL_SECTION	g_ThreadKeyListCS;
427 
AddKeyToList(PTLS pTls)428 static void AddKeyToList( PTLS pTls )
429 {
430 	if ( pTls )
431 	{
432 		EnterCriticalSection( &g_ThreadKeyListCS );
433 
434 		pTls->pNext = g_pThreadKeyList;
435 		pTls->pPrev = NULL;
436 
437 		if ( g_pThreadKeyList )
438 			g_pThreadKeyList->pPrev = pTls;
439 
440 		g_pThreadKeyList = pTls;
441 
442 		LeaveCriticalSection( &g_ThreadKeyListCS );
443 	}
444 }
445 
RemoveKeyFromList(PTLS pTls)446 static void RemoveKeyFromList( PTLS pTls )
447 {
448 	if ( pTls )
449 	{
450 		EnterCriticalSection( &g_ThreadKeyListCS );
451 		if ( pTls->pPrev )
452 			pTls->pPrev->pNext = pTls->pNext;
453 		else
454 		{
455 			OSL_ASSERT( pTls == g_pThreadKeyList );
456 			g_pThreadKeyList = pTls->pNext;
457 		}
458 
459 		if ( pTls->pNext )
460 			pTls->pNext->pPrev = pTls->pPrev;
461 		LeaveCriticalSection( &g_ThreadKeyListCS );
462 	}
463 }
464 
_osl_callThreadKeyCallbackOnThreadDetach(void)465 void SAL_CALL _osl_callThreadKeyCallbackOnThreadDetach(void)
466 {
467 	PTLS	pTls;
468 
469 
470 	EnterCriticalSection( &g_ThreadKeyListCS );
471 	pTls = g_pThreadKeyList;
472 	while ( pTls )
473 	{
474 		if ( pTls->pfnCallback )
475 		{
476 			void	*pValue	= TlsGetValue( pTls->dwIndex );
477 
478 			if ( pValue )
479 				pTls->pfnCallback( pValue );
480 		}
481 
482 		pTls = pTls->pNext;
483 	}
484 	LeaveCriticalSection( &g_ThreadKeyListCS );
485 }
486 
487 /*****************************************************************************/
488 /* osl_createThreadKey */
489 /*****************************************************************************/
osl_createThreadKey(oslThreadKeyCallbackFunction pCallback)490 oslThreadKey SAL_CALL osl_createThreadKey(oslThreadKeyCallbackFunction pCallback)
491 {
492 	PTLS	pTls = rtl_allocateMemory( sizeof(TLS) );
493 
494 	if ( pTls )
495 	{
496 		pTls->pfnCallback = pCallback;
497 		if ( (DWORD)-1 == (pTls->dwIndex = TlsAlloc()) )
498 		{
499 			rtl_freeMemory( pTls );
500 			pTls = NULL;
501 		}
502 		else
503 			AddKeyToList( pTls );
504 	}
505 
506 	return ((oslThreadKey)pTls);
507 }
508 
509 /*****************************************************************************/
510 /* osl_destroyThreadKey */
511 /*****************************************************************************/
osl_destroyThreadKey(oslThreadKey Key)512 void SAL_CALL osl_destroyThreadKey(oslThreadKey Key)
513 {
514 	if (Key != 0)
515 	{
516 		PTLS	pTls = (PTLS)Key;
517 
518 		RemoveKeyFromList( pTls );
519 		TlsFree( pTls->dwIndex );
520 		rtl_freeMemory( pTls );
521 	}
522 }
523 
524 /*****************************************************************************/
525 /* osl_getThreadKeyData */
526 /*****************************************************************************/
osl_getThreadKeyData(oslThreadKey Key)527 void* SAL_CALL osl_getThreadKeyData(oslThreadKey Key)
528 {
529 	if (Key != 0)
530 	{
531 		PTLS	pTls = (PTLS)Key;
532 
533 		return (TlsGetValue( pTls->dwIndex ));
534 	}
535 
536 	return (NULL);
537 }
538 
539 /*****************************************************************************/
540 /* osl_setThreadKeyData */
541 /*****************************************************************************/
osl_setThreadKeyData(oslThreadKey Key,void * pData)542 sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData)
543 {
544 	if (Key != 0)
545 	{
546 		PTLS	pTls = (PTLS)Key;
547 		void*	pOldData = NULL;
548 		BOOL	fSuccess;
549 
550 		if ( pTls->pfnCallback )
551 			pOldData = TlsGetValue( pTls->dwIndex );
552 
553 		fSuccess = TlsSetValue( pTls->dwIndex, pData );
554 
555 		if ( fSuccess && pTls->pfnCallback && pOldData )
556 			pTls->pfnCallback( pOldData );
557 
558 		return (sal_Bool)(fSuccess != FALSE);
559 	}
560 
561 	return (sal_False);
562 }
563 
564 
565 /*****************************************************************************/
566 /* osl_getThreadTextEncoding */
567 /*****************************************************************************/
568 
569 DWORD	g_dwTLSTextEncodingIndex = (DWORD)-1;
570 
571 
osl_getThreadTextEncoding(void)572 rtl_TextEncoding SAL_CALL osl_getThreadTextEncoding(void)
573 {
574 	DWORD				dwEncoding;
575 	rtl_TextEncoding	_encoding;
576 	BOOL				gotACP;
577 
578 	if ( (DWORD)-1 == g_dwTLSTextEncodingIndex )
579 		g_dwTLSTextEncodingIndex = TlsAlloc();
580 
581 	dwEncoding = (DWORD)TlsGetValue( g_dwTLSTextEncodingIndex );
582 	_encoding = LOWORD(dwEncoding);
583 	gotACP = HIWORD(dwEncoding);
584 
585 
586 	if ( !gotACP )
587 	{
588 		char	*pszEncoding;
589 
590 		if ( NULL != (pszEncoding = getenv( "SOLAR_USER_RTL_TEXTENCODING" )) )
591 			_encoding = (rtl_TextEncoding)atoi(pszEncoding);
592 		else
593 			_encoding = rtl_getTextEncodingFromWindowsCodePage( GetACP() );
594 
595 		TlsSetValue( g_dwTLSTextEncodingIndex, (LPVOID)MAKELONG( _encoding, TRUE ) );
596 	}
597 
598 	return _encoding;
599 }
600 
601 /*****************************************************************************/
602 /* osl_getThreadTextEncoding */
603 /*****************************************************************************/
osl_setThreadTextEncoding(rtl_TextEncoding Encoding)604 rtl_TextEncoding SAL_CALL osl_setThreadTextEncoding( rtl_TextEncoding Encoding )
605 {
606 	rtl_TextEncoding oldEncoding = osl_getThreadTextEncoding();
607 
608 	TlsSetValue( g_dwTLSTextEncodingIndex, (LPVOID)MAKELONG( Encoding, TRUE) );
609 
610 	return oldEncoding;
611 }
612 
613 
614 
615