lok: vcl: fix multiple floatwin removal case more robustly.
[LibreOffice.git] / sal / osl / w32 / thread.cxx
bloba0f46b7e5229dde9ece3719d0ff9d243a3695b5b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "system.h"
21 #include "thread.hxx"
23 #include <osl/diagnose.h>
24 #include <osl/thread.h>
25 #include <rtl/alloc.h>
26 #include <osl/time.h>
27 #include <osl/interlck.h>
28 #include <rtl/tencinfo.h>
29 #include <errno.h>
31 /**
32 Thread-data structure hidden behind oslThread:
34 typedef struct
36 HANDLE m_hThread; /* OS-handle used for all thread-functions */
37 unsigned m_ThreadId; /* identifier for this thread */
38 sal_Int32 m_nTerminationRequested;
39 oslWorkerFunction m_WorkerFunction;
40 void* m_pData;
42 } osl_TThreadImpl;
44 static unsigned __stdcall oslWorkerWrapperFunction(void* pData);
45 static oslThread oslCreateThread(oslWorkerFunction pWorker, void* pThreadData, sal_uInt32 nFlags);
47 static unsigned __stdcall oslWorkerWrapperFunction(void* pData)
49 osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(pData);
51 /* Initialize COM - Multi Threaded Apartment (MTA) for all threads */
52 CoInitializeEx(nullptr, COINIT_MULTITHREADED); /* spawned by oslCreateThread */
54 /* call worker-function with data */
56 pThreadImpl->m_WorkerFunction(pThreadImpl->m_pData);
58 CoUninitialize();
60 return 0;
63 static oslThread oslCreateThread(oslWorkerFunction pWorker,
64 void* pThreadData,
65 sal_uInt32 nFlags)
67 osl_TThreadImpl* pThreadImpl;
69 /* alloc mem. for our internal data structure */
70 pThreadImpl= static_cast<osl_TThreadImpl *>(malloc(sizeof(osl_TThreadImpl)));
72 OSL_ASSERT(pThreadImpl);
74 if ( pThreadImpl == nullptr )
76 return nullptr;
79 pThreadImpl->m_WorkerFunction= pWorker;
80 pThreadImpl->m_pData= pThreadData;
81 pThreadImpl->m_nTerminationRequested= 0;
83 pThreadImpl->m_hThread=
84 reinterpret_cast<HANDLE>(_beginthreadex(nullptr, /* no security */
85 0, /* default stack-size */
86 oslWorkerWrapperFunction, /* worker-function */
87 pThreadImpl, /* provide worker-function with data */
88 nFlags, /* start thread immediately or suspended */
89 &pThreadImpl->m_ThreadId));
91 if(pThreadImpl->m_hThread == nullptr)
93 switch (errno)
95 case EAGAIN:
96 fprintf(stderr, "_beginthreadex errno EAGAIN\n");
97 break;
98 case EINVAL:
99 fprintf(stderr, "_beginthreadex errno EINVAL\n");
100 break;
101 case EACCES:
102 fprintf(stderr, "_beginthreadex errno EACCES\n");
103 break;
104 case ENOMEM:
105 fprintf(stderr, "_beginthreadex undocumented errno ENOMEM - this means not enough VM for stack\n");
106 break;
107 default:
108 fprintf(stderr, "_beginthreadex unexpected errno %d\n", errno);
109 break;
112 /* create failed */
113 free(pThreadImpl);
114 return nullptr;
117 return pThreadImpl;
120 oslThread SAL_CALL osl_createThread(oslWorkerFunction pWorker,
121 void* pThreadData)
123 return oslCreateThread(pWorker, pThreadData, 0);
126 oslThread SAL_CALL osl_createSuspendedThread(oslWorkerFunction pWorker,
127 void* pThreadData)
129 return oslCreateThread(pWorker, pThreadData, CREATE_SUSPENDED);
132 oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread)
134 osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(Thread);
136 if (pThreadImpl != nullptr)
137 return static_cast<oslThreadIdentifier>(pThreadImpl->m_ThreadId);
138 else
139 return static_cast<oslThreadIdentifier>(GetCurrentThreadId());
142 void SAL_CALL osl_destroyThread(oslThread Thread)
144 osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(Thread);
146 if (Thread == nullptr) /* valid ptr? */
148 /* thread already destroyed or not created */
149 return;
152 /* !!!! _exitthreadex does _not_ call CloseHandle !!! */
153 CloseHandle( pThreadImpl->m_hThread );
155 /* free memory */
156 free(Thread);
159 void SAL_CALL osl_resumeThread(oslThread Thread)
161 osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(Thread);
163 OSL_ASSERT(pThreadImpl); /* valid ptr? */
165 ResumeThread(pThreadImpl->m_hThread);
168 void SAL_CALL osl_suspendThread(oslThread Thread)
170 osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(Thread);
172 OSL_ASSERT(pThreadImpl); /* valid ptr? */
174 SuspendThread(pThreadImpl->m_hThread);
177 void SAL_CALL osl_setThreadPriority(oslThread Thread,
178 oslThreadPriority Priority)
180 int winPriority;
181 osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(Thread);
183 OSL_ASSERT(pThreadImpl); /* valid ptr? */
185 /* map enum to WIN32 levels
186 it would be faster and more elegant to preset
187 the enums, but that would require an #ifdef in
188 the exported header, which is not desired.
190 switch(Priority) {
192 case osl_Thread_PriorityHighest:
193 winPriority= THREAD_PRIORITY_HIGHEST;
194 break;
196 case osl_Thread_PriorityAboveNormal:
197 winPriority= THREAD_PRIORITY_ABOVE_NORMAL;
198 break;
200 case osl_Thread_PriorityNormal:
201 winPriority= THREAD_PRIORITY_NORMAL;
202 break;
204 case osl_Thread_PriorityBelowNormal:
205 winPriority= THREAD_PRIORITY_BELOW_NORMAL;
206 break;
208 case osl_Thread_PriorityLowest:
209 winPriority= THREAD_PRIORITY_LOWEST;
210 break;
212 case osl_Thread_PriorityUnknown:
213 OSL_ASSERT(FALSE); /* only fools try this...*/
215 /* let release-version behave friendly */
216 return;
218 default:
219 OSL_ASSERT(FALSE); /* enum expanded, but forgotten here...*/
221 /* let release-version behave friendly */
222 return;
225 SetThreadPriority(pThreadImpl->m_hThread, winPriority);
228 oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread)
230 int winPriority;
231 oslThreadPriority Priority;
233 osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(Thread);
235 /* invalid arguments ?*/
236 if(pThreadImpl==nullptr || pThreadImpl->m_hThread==nullptr)
238 return osl_Thread_PriorityUnknown;
241 winPriority=
242 GetThreadPriority(pThreadImpl->m_hThread);
244 if(winPriority == THREAD_PRIORITY_ERROR_RETURN)
246 return osl_Thread_PriorityUnknown;
249 /* map WIN32 priority to enum */
250 switch(winPriority)
252 case THREAD_PRIORITY_TIME_CRITICAL:
253 case THREAD_PRIORITY_HIGHEST:
254 Priority= osl_Thread_PriorityHighest;
255 break;
257 case THREAD_PRIORITY_ABOVE_NORMAL:
258 Priority= osl_Thread_PriorityAboveNormal;
259 break;
261 case THREAD_PRIORITY_NORMAL:
262 Priority= osl_Thread_PriorityNormal;
263 break;
265 case THREAD_PRIORITY_BELOW_NORMAL:
266 Priority= osl_Thread_PriorityBelowNormal;
267 break;
269 case THREAD_PRIORITY_IDLE:
270 case THREAD_PRIORITY_LOWEST:
271 Priority= osl_Thread_PriorityLowest;
272 break;
274 default:
275 OSL_ASSERT(FALSE); /* WIN32 API changed, incorporate new prio-level! */
277 /* release-version behaves friendly */
278 Priority= osl_Thread_PriorityUnknown;
281 return Priority;
284 sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread)
286 osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(Thread);
288 /* invalid arguments ?*/
289 if(pThreadImpl==nullptr || pThreadImpl->m_hThread==nullptr)
291 return false;
294 return WaitForSingleObject(pThreadImpl->m_hThread, 0) != WAIT_OBJECT_0;
297 void SAL_CALL osl_joinWithThread(oslThread Thread)
299 osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(Thread);
301 /* invalid arguments?*/
302 if(pThreadImpl==nullptr || pThreadImpl->m_hThread==nullptr)
304 /* assume thread is not running */
305 return;
308 WaitForSingleObject(pThreadImpl->m_hThread, INFINITE);
311 void SAL_CALL osl_waitThread(const TimeValue* pDelay)
313 if (pDelay)
315 DWORD millisecs = pDelay->Seconds * 1000L + pDelay->Nanosec / 1000000L;
317 Sleep(millisecs);
321 void SAL_CALL osl_terminateThread(oslThread Thread)
323 osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(Thread);
325 /* invalid arguments?*/
326 if (pThreadImpl==nullptr || pThreadImpl->m_hThread==nullptr)
328 /* assume thread is not running */
329 return;
332 osl_atomic_increment(&(pThreadImpl->m_nTerminationRequested));
335 sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread)
337 osl_TThreadImpl* pThreadImpl= static_cast<osl_TThreadImpl*>(Thread);
339 osl_yieldThread();
341 /* invalid arguments?*/
342 if (pThreadImpl==nullptr || pThreadImpl->m_hThread==nullptr)
344 /* assume thread is not running */
345 return false;
348 return 0 == pThreadImpl->m_nTerminationRequested;
351 void SAL_CALL osl_yieldThread(void)
353 Sleep(0);
356 void SAL_CALL osl_setThreadName(char const * name) {
357 #ifdef _MSC_VER
358 /* See <http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx>: */
359 #pragma pack(push, 8)
360 struct {
361 DWORD dwType;
362 LPCSTR szName;
363 DWORD dwThreadID;
364 DWORD dwFlags;
365 } info;
366 #pragma pack(pop)
367 info.dwType = 0x1000;
368 info.szName = name;
369 info.dwThreadID = DWORD(-1);
370 info.dwFlags = 0;
371 __try {
372 RaiseException(
373 0x406D1388, 0, sizeof info / sizeof (ULONG_PTR),
374 reinterpret_cast<ULONG_PTR *>(&info));
375 } __except (EXCEPTION_EXECUTE_HANDLER) {}
376 #else
377 (void) name;
378 #endif
381 typedef struct TLS_
383 DWORD dwIndex;
384 oslThreadKeyCallbackFunction pfnCallback;
385 struct TLS_ *pNext, *pPrev;
386 } TLS, *PTLS;
388 static PTLS g_pThreadKeyList = nullptr;
389 CRITICAL_SECTION g_ThreadKeyListCS;
391 static void AddKeyToList( PTLS pTls )
393 if ( pTls )
395 EnterCriticalSection( &g_ThreadKeyListCS );
397 pTls->pNext = g_pThreadKeyList;
398 pTls->pPrev = nullptr;
400 if ( g_pThreadKeyList )
401 g_pThreadKeyList->pPrev = pTls;
403 g_pThreadKeyList = pTls;
405 LeaveCriticalSection( &g_ThreadKeyListCS );
409 static void RemoveKeyFromList( PTLS pTls )
411 if ( pTls )
413 EnterCriticalSection( &g_ThreadKeyListCS );
414 if ( pTls->pPrev )
415 pTls->pPrev->pNext = pTls->pNext;
416 else
418 OSL_ASSERT( pTls == g_pThreadKeyList );
419 g_pThreadKeyList = pTls->pNext;
422 if ( pTls->pNext )
423 pTls->pNext->pPrev = pTls->pPrev;
424 LeaveCriticalSection( &g_ThreadKeyListCS );
428 void osl_callThreadKeyCallbackOnThreadDetach(void)
430 PTLS pTls;
432 EnterCriticalSection( &g_ThreadKeyListCS );
433 pTls = g_pThreadKeyList;
434 while ( pTls )
436 if ( pTls->pfnCallback )
438 void *pValue = TlsGetValue( pTls->dwIndex );
440 if ( pValue )
441 pTls->pfnCallback( pValue );
444 pTls = pTls->pNext;
446 LeaveCriticalSection( &g_ThreadKeyListCS );
449 oslThreadKey SAL_CALL osl_createThreadKey(oslThreadKeyCallbackFunction pCallback)
451 PTLS pTls = static_cast<PTLS>(malloc( sizeof(TLS) ));
453 if ( pTls )
455 pTls->pfnCallback = pCallback;
456 if ( DWORD(-1) == (pTls->dwIndex = TlsAlloc()) )
458 free( pTls );
459 pTls = nullptr;
461 else
462 AddKeyToList( pTls );
465 return pTls;
468 void SAL_CALL osl_destroyThreadKey(oslThreadKey Key)
470 if (Key != nullptr)
472 PTLS pTls = static_cast<PTLS>(Key);
474 RemoveKeyFromList( pTls );
475 TlsFree( pTls->dwIndex );
476 free( pTls );
480 void* SAL_CALL osl_getThreadKeyData(oslThreadKey Key)
482 if (Key != nullptr)
484 PTLS pTls = static_cast<PTLS>(Key);
486 return TlsGetValue( pTls->dwIndex );
489 return nullptr;
492 sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData)
494 if (Key != nullptr)
496 PTLS pTls = static_cast<PTLS>(Key);
497 void* pOldData = nullptr;
498 BOOL fSuccess;
500 if ( pTls->pfnCallback )
501 pOldData = TlsGetValue( pTls->dwIndex );
503 fSuccess = TlsSetValue( pTls->dwIndex, pData );
505 if ( fSuccess && pTls->pfnCallback && pOldData )
506 pTls->pfnCallback( pOldData );
508 return fSuccess != FALSE;
511 return false;
514 DWORD g_dwTLSTextEncodingIndex = DWORD(-1);
516 rtl_TextEncoding SAL_CALL osl_getThreadTextEncoding(void)
518 DWORD_PTR dwEncoding;
519 rtl_TextEncoding _encoding;
520 BOOL gotACP;
522 if ( DWORD(-1) == g_dwTLSTextEncodingIndex )
523 g_dwTLSTextEncodingIndex = TlsAlloc();
525 dwEncoding = reinterpret_cast<DWORD_PTR>(TlsGetValue( g_dwTLSTextEncodingIndex ));
526 _encoding = LOWORD(dwEncoding);
527 gotACP = HIWORD(dwEncoding);
529 if ( !gotACP )
531 _encoding = rtl_getTextEncodingFromWindowsCodePage( GetACP() );
532 TlsSetValue( g_dwTLSTextEncodingIndex, reinterpret_cast<LPVOID>(static_cast<DWORD_PTR>(MAKELONG( _encoding, TRUE ))) );
535 return _encoding;
538 rtl_TextEncoding SAL_CALL osl_setThreadTextEncoding( rtl_TextEncoding Encoding )
540 rtl_TextEncoding oldEncoding = osl_getThreadTextEncoding();
542 TlsSetValue( g_dwTLSTextEncodingIndex, reinterpret_cast<LPVOID>(static_cast<DWORD_PTR>(MAKELONG( Encoding, TRUE))) );
544 return oldEncoding;
547 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */