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