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