Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <sal/config.h>
21 :
22 : #include <cassert>
23 : #include "system.hxx"
24 : #include <string.h>
25 : #if defined(OPENBSD)
26 : #include <sched.h>
27 : #endif
28 : #include <config_options.h>
29 : #include <osl/thread.h>
30 : #include <osl/nlsupport.h>
31 : #include <rtl/textenc.h>
32 : #include <rtl/alloc.h>
33 : #include <sal/log.hxx>
34 : #include <sal/macros.h>
35 : #ifdef ANDROID
36 : #include <jni.h>
37 : #include <android/log.h>
38 : #include <osl/detail/android-bootstrap.h>
39 : #endif
40 :
41 : #if defined LINUX && ! defined __FreeBSD_kernel__
42 : #include <sys/prctl.h>
43 : #ifndef PR_SET_NAME
44 : #define PR_SET_NAME 15
45 : #endif
46 : #endif
47 :
48 : /****************************************************************************
49 : * @@@ TODO @@@
50 : *
51 : * (1) 'osl_thread_priority_init_Impl()'
52 : * - insane assumption that initializing caller is main thread
53 : * - use _POSIX_THREAD_PRIORITY_SCHEDULING, not NO_PTHREAD_PRIORITY (?)
54 : * - POSIX doesn't require defined prio's for SCHED_OTHER (!)
55 : * - use SCHED_RR instead of SCHED_OTHER for defined behaviour (?)
56 : * (2) 'oslThreadIdentifier' and '{insert|remove|lookup}ThreadId()'
57 : * - cannot reliably be applied to 'alien' threads;
58 : * - memory leak for 'alien' thread 'HashEntry's;
59 : * - use 'PTHREAD_VALUE(pthread_t)' as identifier instead (?)
60 : * - if yes, change 'oslThreadIdentifier' to 'intptr_t' or similar
61 : * (3) 'oslSigAlarmHandler()' (#71232#)
62 : * - [Under Solaris we get SIGALRM in e.g. pthread_join which terminates
63 : * the process. So we initialize our signal handling module and do
64 : * register a SIGALRM Handler which catches and ignores it]
65 : * - should this still happen, 'signal.c' needs to be fixed instead.
66 : *
67 : ****************************************************************************/
68 :
69 : /*****************************************************************************/
70 : /* Internal data structures and functions */
71 : /*****************************************************************************/
72 :
73 : #define THREADIMPL_FLAGS_TERMINATE 0x00001
74 : #define THREADIMPL_FLAGS_STARTUP 0x00002
75 : #define THREADIMPL_FLAGS_SUSPENDED 0x00004
76 : #define THREADIMPL_FLAGS_ACTIVE 0x00008
77 : #define THREADIMPL_FLAGS_ATTACHED 0x00010
78 : #define THREADIMPL_FLAGS_DESTROYED 0x00020
79 :
80 : typedef struct osl_thread_impl_st
81 : {
82 : pthread_t m_hThread;
83 : sal_uInt16 m_Ident; /* @@@ see TODO @@@ */
84 : short m_Flags;
85 : oslWorkerFunction m_WorkerFunction;
86 : void* m_pData;
87 : pthread_mutex_t m_Lock;
88 : pthread_cond_t m_Cond;
89 : } Thread_Impl;
90 :
91 : struct osl_thread_priority_st
92 : {
93 : int m_Highest;
94 : int m_Above_Normal;
95 : int m_Normal;
96 : int m_Below_Normal;
97 : int m_Lowest;
98 : };
99 :
100 : #define OSL_THREAD_PRIORITY_INITIALIZER { 127, 96, 64, 32, 0 }
101 : static void osl_thread_priority_init_Impl();
102 :
103 : struct osl_thread_textencoding_st
104 : {
105 : pthread_key_t m_key; /* key to store thread local text encoding */
106 : rtl_TextEncoding m_default; /* the default text encoding */
107 : };
108 :
109 : #define OSL_THREAD_TEXTENCODING_INITIALIZER { 0, RTL_TEXTENCODING_DONTKNOW }
110 : static void osl_thread_textencoding_init_Impl();
111 :
112 : struct osl_thread_global_st
113 : {
114 : pthread_once_t m_once;
115 : struct osl_thread_priority_st m_priority;
116 : struct osl_thread_textencoding_st m_textencoding;
117 : };
118 :
119 : static struct osl_thread_global_st g_thread =
120 : {
121 : PTHREAD_ONCE_INIT,
122 : OSL_THREAD_PRIORITY_INITIALIZER,
123 : OSL_THREAD_TEXTENCODING_INITIALIZER
124 : };
125 :
126 : static void osl_thread_init_Impl();
127 :
128 : static Thread_Impl* osl_thread_construct_Impl();
129 : static void osl_thread_destruct_Impl (Thread_Impl ** ppImpl);
130 :
131 : static void* osl_thread_start_Impl (void * pData);
132 : static void osl_thread_cleanup_Impl (Thread_Impl * pImpl);
133 :
134 : static oslThread osl_thread_create_Impl (
135 : oslWorkerFunction pWorker, void * pThreadData, short nFlags);
136 :
137 : /* @@@ see TODO @@@ */
138 : static sal_uInt16 insertThreadId (pthread_t hThread);
139 : static sal_uInt16 lookupThreadId (pthread_t hThread);
140 : static void removeThreadId (pthread_t hThread);
141 :
142 1909 : static void osl_thread_init_Impl()
143 : {
144 1909 : osl_thread_priority_init_Impl();
145 1909 : osl_thread_textencoding_init_Impl();
146 1909 : }
147 :
148 6675 : Thread_Impl* osl_thread_construct_Impl()
149 : {
150 6675 : Thread_Impl* pImpl = new Thread_Impl;
151 6675 : if (pImpl)
152 : {
153 6675 : memset (pImpl, 0, sizeof(Thread_Impl));
154 :
155 6675 : pthread_mutex_init (&(pImpl->m_Lock), PTHREAD_MUTEXATTR_DEFAULT);
156 6675 : pthread_cond_init (&(pImpl->m_Cond), PTHREAD_CONDATTR_DEFAULT);
157 : }
158 6675 : return pImpl;
159 : }
160 :
161 6473 : static void osl_thread_destruct_Impl (Thread_Impl ** ppImpl)
162 : {
163 : assert(ppImpl);
164 6473 : if (*ppImpl)
165 : {
166 6472 : pthread_cond_destroy (&((*ppImpl)->m_Cond));
167 6473 : pthread_mutex_destroy (&((*ppImpl)->m_Lock));
168 :
169 6473 : delete *ppImpl;
170 6473 : (*ppImpl) = 0;
171 : }
172 6474 : }
173 :
174 6653 : static void osl_thread_cleanup_Impl (Thread_Impl * pImpl)
175 : {
176 : pthread_t thread;
177 : bool attached;
178 : bool destroyed;
179 :
180 6653 : pthread_mutex_lock (&(pImpl->m_Lock));
181 :
182 6653 : thread = pImpl->m_hThread;
183 6653 : attached = (pImpl->m_Flags & THREADIMPL_FLAGS_ATTACHED) != 0;
184 6653 : destroyed = (pImpl->m_Flags & THREADIMPL_FLAGS_DESTROYED) != 0;
185 6653 : pImpl->m_Flags &= ~(THREADIMPL_FLAGS_ACTIVE | THREADIMPL_FLAGS_ATTACHED);
186 :
187 6653 : pthread_mutex_unlock (&(pImpl->m_Lock));
188 :
189 : /* release oslThreadIdentifier @@@ see TODO @@@ */
190 6653 : removeThreadId (thread);
191 :
192 6653 : if (attached)
193 : {
194 4611 : pthread_detach (thread);
195 : }
196 :
197 6653 : if (destroyed)
198 : {
199 2582 : osl_thread_destruct_Impl (&pImpl);
200 : }
201 6653 : }
202 :
203 6675 : static void* osl_thread_start_Impl (void* pData)
204 : {
205 : bool terminate;
206 6675 : Thread_Impl* pImpl= static_cast<Thread_Impl*>(pData);
207 :
208 : assert(pImpl);
209 :
210 6675 : pthread_mutex_lock (&(pImpl->m_Lock));
211 :
212 : /* request oslThreadIdentifier @@@ see TODO @@@ */
213 6675 : pImpl->m_Ident = insertThreadId (pImpl->m_hThread);
214 :
215 : /* signal change from STARTUP to ACTIVE state */
216 6675 : pImpl->m_Flags &= ~THREADIMPL_FLAGS_STARTUP;
217 6675 : pImpl->m_Flags |= THREADIMPL_FLAGS_ACTIVE;
218 6675 : pthread_cond_signal (&(pImpl->m_Cond));
219 :
220 : /* Check if thread is started in SUSPENDED state */
221 19071 : while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
222 : {
223 : /* wait until SUSPENDED flag is cleared */
224 5721 : pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
225 : }
226 :
227 : /* check for SUSPENDED to TERMINATE state change */
228 6675 : terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0);
229 :
230 6675 : pthread_mutex_unlock (&(pImpl->m_Lock));
231 :
232 6675 : if (!terminate)
233 : {
234 : #ifdef ANDROID
235 : JNIEnv* env = 0;
236 : int res = (*lo_get_javavm()).AttachCurrentThread(&env, NULL);
237 : __android_log_print(ANDROID_LOG_INFO, "LibreOffice", "New sal thread started and attached res=%d", res);
238 : #endif
239 : /* call worker function */
240 6675 : pImpl->m_WorkerFunction(pImpl->m_pData);
241 :
242 : #ifdef ANDROID
243 : res = (*lo_get_javavm()).DetachCurrentThread();
244 : __android_log_print(ANDROID_LOG_INFO, "LibreOffice", "Detached finished sal thread res=%d", res);
245 : #endif
246 : }
247 :
248 6653 : osl_thread_cleanup_Impl (pImpl);
249 6653 : return 0;
250 : }
251 :
252 6675 : static oslThread osl_thread_create_Impl (
253 : oslWorkerFunction pWorker,
254 : void* pThreadData,
255 : short nFlags)
256 : {
257 : Thread_Impl* pImpl;
258 : #if defined OPENBSD || ((defined MACOSX || defined LINUX) && !ENABLE_RUNTIME_OPTIMIZATIONS)
259 : pthread_attr_t attr;
260 : size_t stacksize;
261 : #endif
262 6675 : int nRet=0;
263 :
264 6675 : pImpl = osl_thread_construct_Impl();
265 6675 : if (!pImpl)
266 0 : return 0; /* ENOMEM */
267 :
268 6675 : pImpl->m_WorkerFunction = pWorker;
269 6675 : pImpl->m_pData = pThreadData;
270 6675 : pImpl->m_Flags = nFlags | THREADIMPL_FLAGS_STARTUP;
271 :
272 6675 : pthread_mutex_lock (&(pImpl->m_Lock));
273 :
274 : #if defined OPENBSD || ((defined MACOSX || defined LINUX) && !ENABLE_RUNTIME_OPTIMIZATIONS)
275 : if (pthread_attr_init(&attr) != 0)
276 : return 0;
277 :
278 : #if defined OPENBSD
279 : stacksize = 262144;
280 : #elif defined LINUX
281 : stacksize = 12 * 1024 * 1024; // 8MB is not enough for ASAN on x86-64
282 : #else
283 : stacksize = 100 * PTHREAD_STACK_MIN;
284 : #endif
285 : if (pthread_attr_setstacksize(&attr, stacksize) != 0) {
286 : pthread_attr_destroy(&attr);
287 : return 0;
288 : }
289 : #endif
290 :
291 13350 : if ((nRet = pthread_create (
292 : &(pImpl->m_hThread),
293 : #if defined OPENBSD || ((defined MACOSX || defined LINUX) && !ENABLE_RUNTIME_OPTIMIZATIONS)
294 : &attr,
295 : #else
296 : PTHREAD_ATTR_DEFAULT,
297 : #endif
298 : osl_thread_start_Impl,
299 13350 : static_cast<void*>(pImpl))) != 0)
300 : {
301 : SAL_WARN(
302 : "sal.osl",
303 : "pthread_create failed with " << nRet << " \"" << strerror(nRet)
304 : << "\"");
305 :
306 0 : pthread_mutex_unlock (&(pImpl->m_Lock));
307 0 : osl_thread_destruct_Impl (&pImpl);
308 :
309 0 : return 0;
310 : }
311 :
312 : #if defined OPENBSD || ((defined MACOSX || defined LINUX) && !ENABLE_RUNTIME_OPTIMIZATIONS)
313 : pthread_attr_destroy(&attr);
314 : #endif
315 :
316 : /* wait for change from STARTUP to ACTIVE state */
317 20025 : while (pImpl->m_Flags & THREADIMPL_FLAGS_STARTUP)
318 : {
319 : /* wait until STARTUP flag is cleared */
320 6675 : pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
321 : }
322 :
323 6675 : pthread_mutex_unlock (&(pImpl->m_Lock));
324 :
325 6675 : return static_cast<oslThread>(pImpl);
326 : }
327 :
328 954 : oslThread osl_createThread (
329 : oslWorkerFunction pWorker,
330 : void * pThreadData)
331 : {
332 : return osl_thread_create_Impl (
333 : pWorker,
334 : pThreadData,
335 954 : THREADIMPL_FLAGS_ATTACHED);
336 : }
337 :
338 5721 : oslThread osl_createSuspendedThread (
339 : oslWorkerFunction pWorker,
340 : void * pThreadData)
341 : {
342 : return osl_thread_create_Impl (
343 : pWorker,
344 : pThreadData,
345 : THREADIMPL_FLAGS_ATTACHED |
346 5721 : THREADIMPL_FLAGS_SUSPENDED );
347 : }
348 :
349 8822 : void SAL_CALL osl_destroyThread(oslThread Thread)
350 : {
351 8822 : if (Thread != NULL) {
352 6487 : Thread_Impl * impl = static_cast<Thread_Impl *>(Thread);
353 : bool active;
354 6487 : pthread_mutex_lock(&impl->m_Lock);
355 6487 : active = (impl->m_Flags & THREADIMPL_FLAGS_ACTIVE) != 0;
356 6487 : impl->m_Flags |= THREADIMPL_FLAGS_DESTROYED;
357 6487 : pthread_mutex_unlock(&impl->m_Lock);
358 6487 : if (!active) {
359 3891 : osl_thread_destruct_Impl(&impl);
360 : }
361 : }
362 8822 : }
363 :
364 5726 : void SAL_CALL osl_resumeThread(oslThread Thread)
365 : {
366 5726 : Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);
367 :
368 5726 : if (!pImpl)
369 : {
370 : SAL_WARN("sal.osl", "invalid osl_resumeThread(nullptr) call");
371 5726 : return; /* EINVAL */
372 : }
373 :
374 5726 : pthread_mutex_lock (&(pImpl->m_Lock));
375 :
376 5726 : if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
377 : {
378 : /* clear SUSPENDED flag */
379 5721 : pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED;
380 5721 : pthread_cond_signal (&(pImpl->m_Cond));
381 : }
382 :
383 5726 : pthread_mutex_unlock (&(pImpl->m_Lock));
384 : }
385 :
386 0 : void SAL_CALL osl_suspendThread(oslThread Thread)
387 : {
388 0 : Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);
389 :
390 0 : if (!pImpl)
391 : {
392 : SAL_WARN("sal.osl", "invalid osl_suspendThread(nullptr) call");
393 0 : return; /* EINVAL */
394 : }
395 :
396 0 : pthread_mutex_lock (&(pImpl->m_Lock));
397 :
398 0 : pImpl->m_Flags |= THREADIMPL_FLAGS_SUSPENDED;
399 :
400 0 : if (pthread_equal (pthread_self(), pImpl->m_hThread))
401 : {
402 : /* self suspend */
403 0 : while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
404 : {
405 : /* wait until SUSPENDED flag is cleared */
406 0 : pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
407 : }
408 : }
409 :
410 0 : pthread_mutex_unlock (&(pImpl->m_Lock));
411 : }
412 :
413 18 : sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread)
414 : {
415 : bool active;
416 18 : Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);
417 :
418 18 : if (!pImpl)
419 0 : return sal_False;
420 :
421 18 : pthread_mutex_lock (&(pImpl->m_Lock));
422 18 : active = ((pImpl->m_Flags & THREADIMPL_FLAGS_ACTIVE) > 0);
423 18 : pthread_mutex_unlock (&(pImpl->m_Lock));
424 :
425 18 : return active;
426 : }
427 :
428 8816 : void SAL_CALL osl_joinWithThread(oslThread Thread)
429 : {
430 : pthread_t thread;
431 : bool attached;
432 8816 : Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);
433 :
434 8816 : if (!pImpl)
435 4758 : return;
436 :
437 4058 : pthread_mutex_lock (&(pImpl->m_Lock));
438 :
439 4058 : if (pthread_equal (pthread_self(), pImpl->m_hThread))
440 : {
441 : /* self join */
442 129 : pthread_mutex_unlock (&(pImpl->m_Lock));
443 129 : return; /* EDEADLK */
444 : }
445 :
446 3929 : thread = pImpl->m_hThread;
447 3929 : attached = ((pImpl->m_Flags & THREADIMPL_FLAGS_ATTACHED) > 0);
448 3929 : pImpl->m_Flags &= ~THREADIMPL_FLAGS_ATTACHED;
449 :
450 3929 : pthread_mutex_unlock (&(pImpl->m_Lock));
451 :
452 3929 : if (attached)
453 : {
454 2042 : pthread_join (thread, NULL);
455 : }
456 : }
457 :
458 6 : void SAL_CALL osl_terminateThread(oslThread Thread)
459 : {
460 6 : Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);
461 :
462 6 : if (!pImpl)
463 : {
464 : SAL_WARN("sal.osl", "invalid osl_terminateThread(nullptr) call");
465 6 : return; /* EINVAL */
466 : }
467 :
468 6 : pthread_mutex_lock (&(pImpl->m_Lock));
469 :
470 6 : if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
471 : {
472 : /* clear SUSPENDED flag */
473 0 : pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED;
474 0 : pthread_cond_signal (&(pImpl->m_Cond));
475 : }
476 :
477 6 : pImpl->m_Flags |= THREADIMPL_FLAGS_TERMINATE;
478 :
479 6 : pthread_mutex_unlock (&(pImpl->m_Lock));
480 : }
481 :
482 43 : sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread)
483 : {
484 : bool terminate;
485 43 : Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);
486 :
487 43 : if (!pImpl)
488 : {
489 : SAL_WARN("sal.osl", "invalid osl_scheduleThread(nullptr) call");
490 0 : return sal_False; /* EINVAL */
491 : }
492 :
493 43 : if (!(pthread_equal (pthread_self(), pImpl->m_hThread)))
494 : {
495 : SAL_WARN("sal.osl", "invalid osl_scheduleThread(non-self) call");
496 0 : return sal_False; /* EINVAL */
497 : }
498 :
499 43 : pthread_mutex_lock (&(pImpl->m_Lock));
500 :
501 86 : while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
502 : {
503 : /* wait until SUSPENDED flag is cleared */
504 0 : pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
505 : }
506 :
507 43 : terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0);
508 :
509 43 : pthread_mutex_unlock(&(pImpl->m_Lock));
510 :
511 43 : return !terminate;
512 : }
513 :
514 83 : void SAL_CALL osl_waitThread(const TimeValue* pDelay)
515 : {
516 83 : if (pDelay)
517 : {
518 : struct timespec delay;
519 :
520 83 : SET_TIMESPEC(delay, pDelay->Seconds, pDelay->Nanosec);
521 :
522 83 : SLEEP_TIMESPEC(delay);
523 : }
524 82 : }
525 :
526 : /*****************************************************************************/
527 : /* osl_yieldThread */
528 : /*
529 : Note that POSIX scheduling _really_ requires threads to call this
530 : function, since a thread only reschedules to other thread, when
531 : it blocks (sleep, blocking I/O) OR calls sched_yield().
532 : */
533 : /*****************************************************************************/
534 0 : void SAL_CALL osl_yieldThread()
535 : {
536 0 : sched_yield();
537 0 : }
538 :
539 8562 : void SAL_CALL osl_setThreadName(char const * name) {
540 : #if defined LINUX && ! defined __FreeBSD_kernel__
541 8562 : if (prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(name), 0, 0, 0) != 0) {
542 0 : int e = errno;
543 : SAL_WARN("sal.osl", "prctl(PR_SET_NAME) failed with errno " << e);
544 : }
545 : #else
546 : (void) name;
547 : #endif
548 8562 : }
549 :
550 : /*****************************************************************************/
551 : /* osl_getThreadIdentifier @@@ see TODO @@@ */
552 : /*****************************************************************************/
553 :
554 : #define HASHID(x) ((unsigned long)PTHREAD_VALUE(x) % HashSize)
555 :
556 : typedef struct _HashEntry
557 : {
558 : pthread_t Handle;
559 : sal_uInt16 Ident;
560 : struct _HashEntry *Next;
561 : } HashEntry;
562 :
563 : static HashEntry* HashTable[31];
564 : static int HashSize = SAL_N_ELEMENTS(HashTable);
565 :
566 : static pthread_mutex_t HashLock = PTHREAD_MUTEX_INITIALIZER;
567 :
568 : static sal_uInt16 LastIdent = 0;
569 :
570 125306422 : static sal_uInt16 lookupThreadId (pthread_t hThread)
571 : {
572 : HashEntry *pEntry;
573 :
574 125306422 : pthread_mutex_lock(&HashLock);
575 :
576 125306505 : pEntry = HashTable[HASHID(hThread)];
577 265029082 : while (pEntry != NULL)
578 : {
579 139722068 : if (pthread_equal(pEntry->Handle, hThread))
580 : {
581 125305996 : pthread_mutex_unlock(&HashLock);
582 125305995 : return pEntry->Ident;
583 : }
584 14416072 : pEntry = pEntry->Next;
585 : }
586 :
587 509 : pthread_mutex_unlock(&HashLock);
588 :
589 509 : return 0;
590 : }
591 :
592 7184 : static sal_uInt16 insertThreadId (pthread_t hThread)
593 : {
594 7184 : HashEntry *pEntry, *pInsert = NULL;
595 :
596 7184 : pthread_mutex_lock(&HashLock);
597 :
598 7184 : pEntry = HashTable[HASHID(hThread)];
599 :
600 16773 : while (pEntry != NULL)
601 : {
602 2405 : if (pthread_equal(pEntry->Handle, hThread))
603 0 : break;
604 :
605 2405 : pInsert = pEntry;
606 2405 : pEntry = pEntry->Next;
607 : }
608 :
609 7184 : if (pEntry == NULL)
610 : {
611 7184 : pEntry = static_cast<HashEntry*>(calloc(sizeof(HashEntry), 1));
612 :
613 7184 : pEntry->Handle = hThread;
614 :
615 7184 : ++ LastIdent;
616 :
617 7184 : if ( LastIdent == 0 )
618 0 : LastIdent = 1;
619 :
620 7184 : pEntry->Ident = LastIdent;
621 :
622 7184 : if (pInsert)
623 2276 : pInsert->Next = pEntry;
624 : else
625 4908 : HashTable[HASHID(hThread)] = pEntry;
626 : }
627 :
628 7184 : pthread_mutex_unlock(&HashLock);
629 :
630 7184 : return pEntry->Ident;
631 : }
632 :
633 6653 : static void removeThreadId (pthread_t hThread)
634 : {
635 6653 : HashEntry *pEntry, *pRemove = NULL;
636 :
637 6653 : pthread_mutex_lock(&HashLock);
638 :
639 6653 : pEntry = HashTable[HASHID(hThread)];
640 15623 : while (pEntry != NULL)
641 : {
642 8970 : if (pthread_equal(pEntry->Handle, hThread))
643 6653 : break;
644 :
645 2317 : pRemove = pEntry;
646 2317 : pEntry = pEntry->Next;
647 : }
648 :
649 6653 : if (pEntry != NULL)
650 : {
651 6653 : if (pRemove)
652 2194 : pRemove->Next = pEntry->Next;
653 : else
654 4459 : HashTable[HASHID(hThread)] = pEntry->Next;
655 :
656 6653 : free(pEntry);
657 : }
658 :
659 6653 : pthread_mutex_unlock(&HashLock);
660 6653 : }
661 :
662 125306570 : oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread)
663 : {
664 125306570 : Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);
665 : sal_uInt16 Ident;
666 :
667 125306570 : if (pImpl)
668 138 : Ident = pImpl->m_Ident;
669 : else
670 : {
671 : /* current thread */
672 125306432 : pthread_t current = pthread_self();
673 :
674 125306428 : Ident = lookupThreadId (current);
675 125306503 : if (Ident == 0)
676 : /* @@@ see TODO: alien pthread_self() @@@ */
677 509 : Ident = insertThreadId (current);
678 : }
679 :
680 125306634 : return (oslThreadIdentifier)Ident;
681 : }
682 :
683 : /*****************************************************************************
684 : @@@ see TODO @@@
685 : osl_thread_priority_init_Impl
686 :
687 : set the base-priority of the main-thread to
688 : oslThreadPriorityNormal (64) since 0 (lowest) is
689 : the system default. This behaviour collides with
690 : our enum-priority definition (highest..normal..lowest).
691 : A normaluser will expect the main-thread of an app.
692 : to have the "normal" priority.
693 :
694 : *****************************************************************************/
695 1909 : static void osl_thread_priority_init_Impl()
696 : {
697 : #ifndef NO_PTHREAD_PRIORITY
698 : struct sched_param param;
699 : int policy=0;
700 : int nRet=0;
701 :
702 : /* @@@ see TODO: calling thread may not be main thread @@@ */
703 :
704 : if ((nRet = pthread_getschedparam(pthread_self(), &policy, ¶m)) != 0)
705 : {
706 : SAL_WARN(
707 : "sal.osl",
708 : "pthread_getschedparam failed with " << nRet << " \""
709 : << strerror(nRet) << "\"");
710 : return;
711 : }
712 :
713 : #if defined (SOLARIS)
714 : if ( policy >= _SCHED_NEXT)
715 : {
716 : /* mfe: pthread_getschedparam on Solaris has a possible Bug */
717 : /* one gets 959917873 as the policy */
718 : /* so set the policy to a default one */
719 : policy=SCHED_OTHER;
720 : }
721 : #endif /* SOLARIS */
722 :
723 : if ((nRet = sched_get_priority_min(policy) ) != -1)
724 : {
725 : SAL_INFO(
726 : "sal.osl", "Min Prioriy for policy " << policy << " == " << nRet);
727 : g_thread.m_priority.m_Lowest=nRet;
728 : }
729 : else
730 : {
731 : int e = errno;
732 : SAL_WARN(
733 : "sal.osl",
734 : "sched_get_priority_min failed with " << e << " \"" << strerror(e)
735 : << "\"");
736 : }
737 :
738 : if ((nRet = sched_get_priority_max(policy) ) != -1)
739 : {
740 : SAL_INFO(
741 : "sal.osl", "Max Prioriy for policy " << policy << " == " << nRet);
742 : g_thread.m_priority.m_Highest=nRet;
743 : }
744 : else
745 : {
746 : int e = errno;
747 : SAL_WARN(
748 : "sal.osl",
749 : "sched_get_priority_max failed with " << e << " \"" << strerror(e)
750 : << "\"");
751 : }
752 :
753 : g_thread.m_priority.m_Normal =
754 : (g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Highest) / 2;
755 : g_thread.m_priority.m_Below_Normal =
756 : (g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Normal) / 2;
757 : g_thread.m_priority.m_Above_Normal =
758 : (g_thread.m_priority.m_Normal + g_thread.m_priority.m_Highest) / 2;
759 :
760 : /* @@@ set prio of calling (not main) thread (?) @@@ */
761 :
762 : param.sched_priority= g_thread.m_priority.m_Normal;
763 :
764 : if ((nRet = pthread_setschedparam(pthread_self(), policy, ¶m)) != 0)
765 : {
766 : SAL_WARN(
767 : "sal.osl",
768 : "pthread_setschedparam failed with " << nRet << " \""
769 : << strerror(nRet) << "\"");
770 : SAL_INFO(
771 : "sal.osl",
772 : "Thread ID " << pthread_self() << ", Policy " << policy
773 : << ", Priority " << param.sched_priority);
774 : }
775 :
776 : #endif /* NO_PTHREAD_PRIORITY */
777 1909 : }
778 :
779 : /*****************************************************************************/
780 : /* osl_setThreadPriority */
781 : /*
782 : Impl-Notes: contrary to solaris-docu, which claims
783 : valid priority-levels from 0 .. INT_MAX, only the
784 : range 0..127 is accepted. (0 lowest, 127 highest)
785 : */
786 : /*****************************************************************************/
787 0 : void SAL_CALL osl_setThreadPriority (
788 : oslThread Thread,
789 : oslThreadPriority Priority)
790 : {
791 : #ifndef NO_PTHREAD_PRIORITY
792 :
793 : struct sched_param Param;
794 : int policy;
795 : int nRet;
796 :
797 : #endif /* NO_PTHREAD_PRIORITY */
798 :
799 0 : Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);
800 :
801 0 : if (!pImpl)
802 : {
803 : SAL_WARN("sal.osl", "invalid osl_setThreadPriority(nullptr, ...) call");
804 0 : return; /* EINVAL */
805 : }
806 :
807 : #ifdef NO_PTHREAD_PRIORITY
808 : (void) Priority; /* unused */
809 : #else /* NO_PTHREAD_PRIORITY */
810 :
811 : if (pthread_getschedparam(pImpl->m_hThread, &policy, &Param) != 0)
812 : return; /* ESRCH */
813 :
814 : #if defined (SOLARIS)
815 : if ( policy >= _SCHED_NEXT)
816 : {
817 : /* mfe: pthread_getschedparam on Solaris has a possible Bug */
818 : /* one gets 959917873 as the policy */
819 : /* so set the policy to a default one */
820 : policy=SCHED_OTHER;
821 : }
822 : #endif /* SOLARIS */
823 :
824 : pthread_once (&(g_thread.m_once), osl_thread_init_Impl);
825 :
826 : switch(Priority)
827 : {
828 : case osl_Thread_PriorityHighest:
829 : Param.sched_priority= g_thread.m_priority.m_Highest;
830 : break;
831 :
832 : case osl_Thread_PriorityAboveNormal:
833 : Param.sched_priority= g_thread.m_priority.m_Above_Normal;
834 : break;
835 :
836 : case osl_Thread_PriorityNormal:
837 : Param.sched_priority= g_thread.m_priority.m_Normal;
838 : break;
839 :
840 : case osl_Thread_PriorityBelowNormal:
841 : Param.sched_priority= g_thread.m_priority.m_Below_Normal;
842 : break;
843 :
844 : case osl_Thread_PriorityLowest:
845 : Param.sched_priority= g_thread.m_priority.m_Lowest;
846 : break;
847 :
848 : case osl_Thread_PriorityUnknown:
849 : SAL_WARN(
850 : "sal.osl",
851 : "invalid osl_setThreadPriority(..., osl_Thread_PriorityUnknown)"
852 : " call");
853 : return;
854 :
855 : default:
856 : SAL_WARN(
857 : "sal.osl",
858 : "invalid osl_setThreadPriority(..., " << Priority << ") call");
859 : return;
860 : }
861 :
862 : if ((nRet = pthread_setschedparam(pImpl->m_hThread, policy, &Param)) != 0)
863 : {
864 : SAL_WARN(
865 : "sal.osl",
866 : "pthread_setschedparam failed with " << nRet << " \""
867 : << strerror(nRet) << "\"");
868 : }
869 :
870 : #endif /* NO_PTHREAD_PRIORITY */
871 : }
872 :
873 0 : oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread)
874 : {
875 : #ifndef NO_PTHREAD_PRIORITY
876 :
877 : struct sched_param Param;
878 : int Policy;
879 :
880 : #endif /* NO_PTHREAD_PRIORITY */
881 :
882 0 : oslThreadPriority Priority = osl_Thread_PriorityNormal;
883 0 : Thread_Impl* pImpl= static_cast<Thread_Impl*>(Thread);
884 :
885 0 : if (!pImpl)
886 : {
887 : SAL_WARN("sal.osl", "invalid osl_getThreadPriority(nullptr) call");
888 0 : return osl_Thread_PriorityUnknown; /* EINVAL */
889 : }
890 :
891 : #ifndef NO_PTHREAD_PRIORITY
892 :
893 : if (pthread_getschedparam(pImpl->m_hThread, &Policy, &Param) != 0)
894 : return osl_Thread_PriorityUnknown; /* ESRCH */
895 :
896 : pthread_once (&(g_thread.m_once), osl_thread_init_Impl);
897 :
898 : /* map pthread priority to enum */
899 : if (Param.sched_priority==g_thread.m_priority.m_Highest)
900 : {
901 : /* 127 - highest */
902 : Priority= osl_Thread_PriorityHighest;
903 : }
904 : else if (Param.sched_priority > g_thread.m_priority.m_Normal)
905 : {
906 : /* 65..126 - above normal */
907 : Priority= osl_Thread_PriorityAboveNormal;
908 : }
909 : else if (Param.sched_priority == g_thread.m_priority.m_Normal)
910 : {
911 : /* normal */
912 : Priority= osl_Thread_PriorityNormal;
913 : }
914 : else if (Param.sched_priority > g_thread.m_priority.m_Lowest)
915 : {
916 : /* 63..1 -below normal */
917 : Priority= osl_Thread_PriorityBelowNormal;
918 : }
919 : else if (Param.sched_priority == g_thread.m_priority.m_Lowest)
920 : {
921 : /* 0 - lowest */
922 : Priority= osl_Thread_PriorityLowest;
923 : }
924 : else
925 : {
926 : /* unknown */
927 : Priority= osl_Thread_PriorityUnknown;
928 : }
929 :
930 : #endif /* NO_PTHREAD_PRIORITY */
931 :
932 0 : return Priority;
933 : }
934 :
935 : typedef struct _wrapper_pthread_key
936 : {
937 : pthread_key_t m_key;
938 : oslThreadKeyCallbackFunction pfnCallback;
939 : } wrapper_pthread_key;
940 :
941 261 : oslThreadKey SAL_CALL osl_createThreadKey( oslThreadKeyCallbackFunction pCallback )
942 : {
943 261 : wrapper_pthread_key *pKey = static_cast<wrapper_pthread_key*>(rtl_allocateMemory(sizeof(wrapper_pthread_key)));
944 :
945 261 : if (pKey)
946 : {
947 261 : pKey->pfnCallback = pCallback;
948 :
949 261 : if (pthread_key_create(&(pKey->m_key), pKey->pfnCallback) != 0)
950 : {
951 0 : rtl_freeMemory(pKey);
952 0 : pKey = 0;
953 : }
954 : }
955 :
956 261 : return static_cast<oslThreadKey>(pKey);
957 : }
958 :
959 260 : void SAL_CALL osl_destroyThreadKey(oslThreadKey Key)
960 : {
961 260 : wrapper_pthread_key *pKey = static_cast<wrapper_pthread_key*>(Key);
962 260 : if (pKey)
963 : {
964 260 : pthread_key_delete(pKey->m_key);
965 260 : rtl_freeMemory(pKey);
966 : }
967 260 : }
968 :
969 1097621 : void* SAL_CALL osl_getThreadKeyData(oslThreadKey Key)
970 : {
971 1097621 : wrapper_pthread_key *pKey = static_cast<wrapper_pthread_key*>(Key);
972 1097621 : return pKey ? pthread_getspecific(pKey->m_key) : NULL;
973 : }
974 :
975 1118 : sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData)
976 : {
977 : bool bRet;
978 1118 : void *pOldData = NULL;
979 1118 : wrapper_pthread_key *pKey = static_cast<wrapper_pthread_key*>(Key);
980 1118 : if (!pKey)
981 0 : return sal_False;
982 :
983 1118 : if (pKey->pfnCallback)
984 1116 : pOldData = pthread_getspecific(pKey->m_key);
985 :
986 1118 : bRet = (pthread_setspecific(pKey->m_key, pData) == 0);
987 :
988 1118 : if (bRet && pKey->pfnCallback && pOldData)
989 4 : pKey->pfnCallback(pOldData);
990 :
991 1118 : return bRet;
992 : }
993 :
994 : /*****************************************************************************/
995 : /* Thread Local Text Encoding */
996 : /*****************************************************************************/
997 1909 : static void osl_thread_textencoding_init_Impl()
998 : {
999 : rtl_TextEncoding defaultEncoding;
1000 :
1001 : /* create thread specific data key */
1002 1909 : pthread_key_create (&(g_thread.m_textencoding.m_key), NULL);
1003 :
1004 : /* determine default text encoding */
1005 1909 : defaultEncoding = osl_getTextEncodingFromLocale(NULL);
1006 : // Tools string functions call abort() on an unknown encoding so ASCII is a
1007 : // meaningfull fallback:
1008 1909 : if ( RTL_TEXTENCODING_DONTKNOW == defaultEncoding )
1009 : {
1010 : SAL_WARN("sal.osl", "RTL_TEXTENCODING_DONTKNOW -> _ASCII_US");
1011 0 : defaultEncoding = RTL_TEXTENCODING_ASCII_US;
1012 : }
1013 :
1014 1909 : g_thread.m_textencoding.m_default = defaultEncoding;
1015 1909 : }
1016 :
1017 2551680 : rtl_TextEncoding SAL_CALL osl_getThreadTextEncoding()
1018 : {
1019 : rtl_TextEncoding threadEncoding;
1020 :
1021 2551680 : pthread_once (&(g_thread.m_once), osl_thread_init_Impl);
1022 :
1023 : /* check for thread specific encoding, use default if not set */
1024 : threadEncoding = static_cast<rtl_TextEncoding>(
1025 2551680 : reinterpret_cast<sal_uIntPtr>(pthread_getspecific(g_thread.m_textencoding.m_key)));
1026 2551680 : if (0 == threadEncoding)
1027 2551680 : threadEncoding = g_thread.m_textencoding.m_default;
1028 :
1029 2551680 : return threadEncoding;
1030 : }
1031 :
1032 0 : rtl_TextEncoding osl_setThreadTextEncoding(rtl_TextEncoding Encoding)
1033 : {
1034 0 : rtl_TextEncoding oldThreadEncoding = osl_getThreadTextEncoding();
1035 :
1036 : /* save encoding in thread local storage */
1037 : pthread_setspecific (
1038 : g_thread.m_textencoding.m_key,
1039 0 : reinterpret_cast<void*>(static_cast<sal_uIntPtr>(Encoding)));
1040 :
1041 0 : return oldThreadEncoding;
1042 : }
1043 :
1044 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|