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