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