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