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) = 0;
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",
302 nRet, strerror(nRet));
303
304 pthread_mutex_unlock (&(pImpl->m_Lock));
305 osl_thread_destruct_Impl (&pImpl);
306
307 return (0);
308 }
309
310 /* wait for change from STARTUP to ACTIVE state */
311 while (pImpl->m_Flags & THREADIMPL_FLAGS_STARTUP)
312 {
313 /* wait until STARTUP flag is cleared */
314 pthread_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock));
315 pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
316 pthread_cleanup_pop (0);
317 }
318
319 pthread_mutex_unlock (&(pImpl->m_Lock));
320
321 return ((oslThread)(pImpl));
322 }
323
324 /*****************************************************************************/
325 /* osl_createThread */
326 /*****************************************************************************/
osl_createThread(oslWorkerFunction pWorker,void * pThreadData)327 oslThread osl_createThread (
328 oslWorkerFunction pWorker,
329 void * pThreadData)
330 {
331 return osl_thread_create_Impl (
332 pWorker,
333 pThreadData,
334 THREADIMPL_FLAGS_ATTACHED);
335 }
336
337 /*****************************************************************************/
338 /* osl_createSuspendedThread */
339 /*****************************************************************************/
osl_createSuspendedThread(oslWorkerFunction pWorker,void * pThreadData)340 oslThread osl_createSuspendedThread (
341 oslWorkerFunction pWorker,
342 void * pThreadData)
343 {
344 return osl_thread_create_Impl (
345 pWorker,
346 pThreadData,
347 THREADIMPL_FLAGS_ATTACHED |
348 THREADIMPL_FLAGS_SUSPENDED );
349 }
350
351 /*****************************************************************************/
352 /* osl_destroyThread */
353 /*****************************************************************************/
osl_destroyThread(oslThread Thread)354 void SAL_CALL osl_destroyThread(oslThread Thread)
355 {
356 if (Thread != NULL) {
357 Thread_Impl * impl = (Thread_Impl *) Thread;
358 int active;
359 pthread_mutex_lock(&impl->m_Lock);
360 active = (impl->m_Flags & THREADIMPL_FLAGS_ACTIVE) != 0;
361 impl->m_Flags |= THREADIMPL_FLAGS_DESTROYED;
362 pthread_mutex_unlock(&impl->m_Lock);
363 if (!active) {
364 osl_thread_destruct_Impl(&impl);
365 }
366 }
367 }
368
369 /*****************************************************************************/
370 /* osl_resumeThread */
371 /*****************************************************************************/
osl_resumeThread(oslThread Thread)372 void SAL_CALL osl_resumeThread(oslThread Thread)
373 {
374 Thread_Impl* pImpl= (Thread_Impl*)Thread;
375
376 OSL_ASSERT(pImpl);
377 if (!pImpl)
378 return; /* EINVAL */
379
380 pthread_mutex_lock (&(pImpl->m_Lock));
381
382 if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
383 {
384 /* clear SUSPENDED flag */
385 pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED;
386 pthread_cond_signal (&(pImpl->m_Cond));
387 }
388
389 pthread_mutex_unlock (&(pImpl->m_Lock));
390 }
391
392 /*****************************************************************************/
393 /* osl_suspendThread */
394 /*****************************************************************************/
osl_suspendThread(oslThread Thread)395 void SAL_CALL osl_suspendThread(oslThread Thread)
396 {
397 Thread_Impl* pImpl= (Thread_Impl*)Thread;
398
399 OSL_ASSERT(pImpl);
400 if (!pImpl)
401 return; /* EINVAL */
402
403 pthread_mutex_lock (&(pImpl->m_Lock));
404
405 pImpl->m_Flags |= THREADIMPL_FLAGS_SUSPENDED;
406
407 if (pthread_equal (pthread_self(), pImpl->m_hThread))
408 {
409 /* self suspend */
410 while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
411 {
412 /* wait until SUSPENDED flag is cleared */
413 pthread_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock));
414 pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
415 pthread_cleanup_pop (0);
416 }
417 }
418
419 pthread_mutex_unlock (&(pImpl->m_Lock));
420 }
421
422 /*****************************************************************************/
423 /* osl_isThreadRunning */
424 /*****************************************************************************/
osl_isThreadRunning(const oslThread Thread)425 sal_Bool SAL_CALL osl_isThreadRunning(const oslThread Thread)
426 {
427 sal_Bool active;
428 Thread_Impl* pImpl= (Thread_Impl*)Thread;
429
430 if (!pImpl)
431 return sal_False;
432
433 pthread_mutex_lock (&(pImpl->m_Lock));
434 active = ((pImpl->m_Flags & THREADIMPL_FLAGS_ACTIVE) > 0);
435 pthread_mutex_unlock (&(pImpl->m_Lock));
436
437 return (active);
438 }
439
440 /*****************************************************************************/
441 /* osl_joinWithThread */
442 /*****************************************************************************/
osl_joinWithThread(oslThread Thread)443 void SAL_CALL osl_joinWithThread(oslThread Thread)
444 {
445 pthread_t thread;
446 int attached;
447 Thread_Impl* pImpl= (Thread_Impl*)Thread;
448
449 if (!pImpl)
450 return;
451
452 pthread_mutex_lock (&(pImpl->m_Lock));
453
454 if (pthread_equal (pthread_self(), pImpl->m_hThread))
455 {
456 /* self join */
457 pthread_mutex_unlock (&(pImpl->m_Lock));
458 return; /* EDEADLK */
459 }
460
461 thread = pImpl->m_hThread;
462 attached = ((pImpl->m_Flags & THREADIMPL_FLAGS_ATTACHED) > 0);
463 pImpl->m_Flags &= ~THREADIMPL_FLAGS_ATTACHED;
464
465 pthread_mutex_unlock (&(pImpl->m_Lock));
466
467 if (attached)
468 {
469 /* install cleanup handler to ensure consistent flags and state */
470 pthread_cleanup_push (
471 osl_thread_join_cleanup_Impl, (void*)thread);
472
473 /* join */
474 pthread_join (thread, NULL);
475
476 /* remove cleanup handler */
477 pthread_cleanup_pop (0);
478 }
479 }
480
481 /*****************************************************************************/
482 /* osl_terminateThread */
483 /*****************************************************************************/
osl_terminateThread(oslThread Thread)484 void SAL_CALL osl_terminateThread(oslThread Thread)
485 {
486 Thread_Impl* pImpl= (Thread_Impl*)Thread;
487
488 OSL_ASSERT(pImpl);
489 if (!pImpl)
490 return; /* EINVAL */
491
492 pthread_mutex_lock (&(pImpl->m_Lock));
493
494 if (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
495 {
496 /* clear SUSPENDED flag */
497 pImpl->m_Flags &= ~THREADIMPL_FLAGS_SUSPENDED;
498 pthread_cond_signal (&(pImpl->m_Cond));
499 }
500
501 pImpl->m_Flags |= THREADIMPL_FLAGS_TERMINATE;
502
503 pthread_mutex_unlock (&(pImpl->m_Lock));
504 }
505
506 /*****************************************************************************/
507 /* osl_scheduleThread */
508 /*****************************************************************************/
osl_scheduleThread(oslThread Thread)509 sal_Bool SAL_CALL osl_scheduleThread(oslThread Thread)
510 {
511 int terminate;
512 Thread_Impl* pImpl= (Thread_Impl*)Thread;
513
514 OSL_ASSERT(pImpl);
515 if (!pImpl)
516 return sal_False; /* EINVAL */
517
518 OSL_ASSERT(pthread_equal (pthread_self(), pImpl->m_hThread));
519 if (!(pthread_equal (pthread_self(), pImpl->m_hThread)))
520 return sal_False; /* EINVAL */
521
522 pthread_testcancel();
523 pthread_mutex_lock (&(pImpl->m_Lock));
524
525 while (pImpl->m_Flags & THREADIMPL_FLAGS_SUSPENDED)
526 {
527 /* wait until SUSPENDED flag is cleared */
528 pthread_cleanup_push (osl_thread_wait_cleanup_Impl, &(pImpl->m_Lock));
529 pthread_cond_wait (&(pImpl->m_Cond), &(pImpl->m_Lock));
530 pthread_cleanup_pop (0);
531 }
532
533 terminate = ((pImpl->m_Flags & THREADIMPL_FLAGS_TERMINATE) > 0);
534
535 pthread_mutex_unlock(&(pImpl->m_Lock));
536 pthread_testcancel();
537
538 return (terminate == 0);
539 }
540
541 /*****************************************************************************/
542 /* osl_waitThread */
543 /*****************************************************************************/
osl_waitThread(const TimeValue * pDelay)544 void SAL_CALL osl_waitThread(const TimeValue* pDelay)
545 {
546 if (pDelay)
547 {
548 struct timespec delay;
549
550 SET_TIMESPEC(delay, pDelay->Seconds, pDelay->Nanosec);
551
552 SLEEP_TIMESPEC(delay);
553 }
554 }
555
556 /*****************************************************************************/
557 /* osl_yieldThread */
558 /*
559 Note that POSIX scheduling _really_ requires threads to call this
560 functions, since a thread only reschedules to other thread, when
561 it blocks (sleep, blocking I/O) OR calls sched_yield().
562 */
563 /*****************************************************************************/
osl_yieldThread()564 void SAL_CALL osl_yieldThread()
565 {
566 sched_yield();
567 }
568
osl_setThreadName(char const * name)569 void SAL_CALL osl_setThreadName(char const * name) {
570 #if defined LINUX
571 if (prctl(PR_SET_NAME, (unsigned long) name, 0, 0, 0) != 0) {
572 OSL_TRACE(
573 "%s prctl(PR_SET_NAME) failed with errno %d", OSL_LOG_PREFIX,
574 errno);
575 }
576 #else
577 (void) name;
578 #endif
579 }
580
581 /*****************************************************************************/
582 /* osl_getThreadIdentifier @@@ see TODO @@@ */
583 /*****************************************************************************/
584
585 #define HASHID(x) ((unsigned int)PTHREAD_VALUE(x) % HashSize)
586
587 typedef struct _HashEntry
588 {
589 pthread_t Handle;
590 sal_uInt16 Ident;
591 struct _HashEntry *Next;
592 } HashEntry;
593
594 static HashEntry* HashTable[31];
595 static int HashSize = sizeof(HashTable) / sizeof(HashTable[0]);
596
597 static pthread_mutex_t HashLock = PTHREAD_MUTEX_INITIALIZER;
598
599 static sal_uInt16 LastIdent = 0;
600
lookupThreadId(pthread_t hThread)601 static sal_uInt16 lookupThreadId (pthread_t hThread)
602 {
603 HashEntry *pEntry;
604
605 pthread_mutex_lock(&HashLock);
606
607 pEntry = HashTable[HASHID(hThread)];
608 while (pEntry != NULL)
609 {
610 if (pthread_equal(pEntry->Handle, hThread))
611 {
612 pthread_mutex_unlock(&HashLock);
613 return (pEntry->Ident);
614 }
615 pEntry = pEntry->Next;
616 }
617
618 pthread_mutex_unlock(&HashLock);
619
620 return (0);
621 }
622
insertThreadId(pthread_t hThread)623 static sal_uInt16 insertThreadId (pthread_t hThread)
624 {
625 HashEntry *pEntry, *pInsert = NULL;
626
627 pthread_mutex_lock(&HashLock);
628
629 pEntry = HashTable[HASHID(hThread)];
630
631 while (pEntry != NULL)
632 {
633 if (pthread_equal(pEntry->Handle, hThread))
634 break;
635
636 pInsert = pEntry;
637 pEntry = pEntry->Next;
638 }
639
640 if (pEntry == NULL)
641 {
642 pEntry = (HashEntry*) calloc(sizeof(HashEntry), 1);
643
644 pEntry->Handle = hThread;
645
646 ++ LastIdent;
647
648 if ( LastIdent == 0 )
649 LastIdent = 1;
650
651 pEntry->Ident = LastIdent;
652
653 if (pInsert)
654 pInsert->Next = pEntry;
655 else
656 HashTable[HASHID(hThread)] = pEntry;
657 }
658
659 pthread_mutex_unlock(&HashLock);
660
661 return (pEntry->Ident);
662 }
663
removeThreadId(pthread_t hThread)664 static void removeThreadId (pthread_t hThread)
665 {
666 HashEntry *pEntry, *pRemove = NULL;
667
668 pthread_mutex_lock(&HashLock);
669
670 pEntry = HashTable[HASHID(hThread)];
671 while (pEntry != NULL)
672 {
673 if (pthread_equal(pEntry->Handle, hThread))
674 break;
675
676 pRemove = pEntry;
677 pEntry = pEntry->Next;
678 }
679
680 if (pEntry != NULL)
681 {
682 if (pRemove)
683 pRemove->Next = pEntry->Next;
684 else
685 HashTable[HASHID(hThread)] = pEntry->Next;
686
687 free(pEntry);
688 }
689
690 pthread_mutex_unlock(&HashLock);
691 }
692
osl_getThreadIdentifier(oslThread Thread)693 oslThreadIdentifier SAL_CALL osl_getThreadIdentifier(oslThread Thread)
694 {
695 Thread_Impl* pImpl= (Thread_Impl*)Thread;
696 sal_uInt16 Ident;
697
698 if (pImpl)
699 Ident = pImpl->m_Ident;
700 else
701 {
702 /* current thread */
703 pthread_t current = pthread_self();
704
705 Ident = lookupThreadId (current);
706 if (Ident == 0)
707 /* @@@ see TODO: alien pthread_self() @@@ */
708 Ident = insertThreadId (current);
709 }
710
711 return ((oslThreadIdentifier)(Ident));
712 }
713
714 /*****************************************************************************
715 @@@ see TODO @@@
716 osl_thread_priority_init_Impl
717
718 set the base-priority of the main-thread to
719 oslThreadPriorityNormal (64) since 0 (lowest) is
720 the system default. This behaviour collides with
721 our enum-priority definition (highest..normal..lowest).
722 A normaluser will expect the main-thread of an app.
723 to have the "normal" priority.
724
725 *****************************************************************************/
osl_thread_priority_init_Impl(void)726 static void osl_thread_priority_init_Impl (void)
727 {
728 #ifndef NO_PTHREAD_PRIORITY
729 struct sched_param param;
730 int policy=0;
731 int nRet=0;
732
733 /* @@@ see TODO: calling thread may not be main thread @@@ */
734
735 if ((nRet = pthread_getschedparam(pthread_self(), &policy, ¶m)) != 0)
736 {
737 OSL_TRACE("failed to get priority of thread [%s]\n",strerror(nRet));
738 return;
739 }
740
741 #if defined (SOLARIS)
742 if ( policy >= _SCHED_NEXT)
743 {
744 /* mfe: pthread_getschedparam on Solaris has a possible Bug */
745 /* one gets 959917873 as the policy */
746 /* so set the policy to a default one */
747 policy=SCHED_OTHER;
748 }
749 #endif /* SOLARIS */
750
751 if ((nRet = sched_get_priority_min(policy) ) != -1)
752 {
753 OSL_TRACE("Min Prioriy for policy '%i' == '%i'\n",policy,nRet);
754 g_thread.m_priority.m_Lowest=nRet;
755 }
756 #if OSL_DEBUG_LEVEL > 1
757 else
758 {
759 fprintf(stderr,"failed to get min sched param [%s]\n",strerror(errno));
760 }
761 #endif /* OSL_DEBUG_LEVEL */
762
763 if ((nRet = sched_get_priority_max(policy) ) != -1)
764 {
765 OSL_TRACE("Max Prioriy for policy '%i' == '%i'\n",policy,nRet);
766 g_thread.m_priority.m_Highest=nRet;
767 }
768 #if OSL_DEBUG_LEVEL > 1
769 else
770 {
771 fprintf(stderr,"failed to get max sched param [%s]\n",strerror(errno));
772 }
773 #endif /* OSL_DEBUG_LEVEL */
774
775 g_thread.m_priority.m_Normal =
776 (g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Highest) / 2;
777 g_thread.m_priority.m_Below_Normal =
778 (g_thread.m_priority.m_Lowest + g_thread.m_priority.m_Normal) / 2;
779 g_thread.m_priority.m_Above_Normal =
780 (g_thread.m_priority.m_Normal + g_thread.m_priority.m_Highest) / 2;
781
782 /* @@@ set prio of calling (not main) thread (?) @@@ */
783
784 param.sched_priority= g_thread.m_priority.m_Normal;
785
786 if ((nRet = pthread_setschedparam(pthread_self(), policy, ¶m)) != 0)
787 {
788 OSL_TRACE("failed to change base priority of thread [%s]\n",strerror(nRet));
789 OSL_TRACE("Thread ID '%i', Policy '%i', Priority '%i'\n",pthread_self(),policy,param.sched_priority);
790 }
791
792 #endif /* NO_PTHREAD_PRIORITY */
793 }
794
795 /*****************************************************************************/
796 /* osl_setThreadPriority */
797 /*
798 Impl-Notes: contrary to solaris-docu, which claims
799 valid priority-levels from 0 .. INT_MAX, only the
800 range 0..127 is accepted. (0 lowest, 127 highest)
801 */
802 /*****************************************************************************/
osl_setThreadPriority(oslThread Thread,oslThreadPriority Priority)803 void SAL_CALL osl_setThreadPriority (
804 oslThread Thread,
805 oslThreadPriority Priority)
806 {
807 #ifndef NO_PTHREAD_PRIORITY
808
809 struct sched_param Param;
810 int policy;
811 int nRet;
812
813 #endif /* NO_PTHREAD_PRIORITY */
814
815 Thread_Impl* pImpl= (Thread_Impl*)Thread;
816
817 OSL_ASSERT(pImpl);
818 if (!pImpl)
819 return; /* EINVAL */
820
821 #ifdef NO_PTHREAD_PRIORITY
822 (void) Priority; /* unused */
823 #else /* NO_PTHREAD_PRIORITY */
824
825 if (pthread_getschedparam(pImpl->m_hThread, &policy, &Param) != 0)
826 return; /* ESRCH */
827
828 #if defined (SOLARIS)
829 if ( policy >= _SCHED_NEXT)
830 {
831 /* mfe: pthread_getschedparam on Solaris has a possible Bug */
832 /* one gets 959917873 as the policy */
833 /* so set the policy to a default one */
834 policy=SCHED_OTHER;
835 }
836 #endif /* SOLARIS */
837
838 pthread_once (&(g_thread.m_once), osl_thread_init_Impl);
839
840 switch(Priority)
841 {
842 case osl_Thread_PriorityHighest:
843 Param.sched_priority= g_thread.m_priority.m_Highest;
844 break;
845
846 case osl_Thread_PriorityAboveNormal:
847 Param.sched_priority= g_thread.m_priority.m_Above_Normal;
848 break;
849
850 case osl_Thread_PriorityNormal:
851 Param.sched_priority= g_thread.m_priority.m_Normal;
852 break;
853
854 case osl_Thread_PriorityBelowNormal:
855 Param.sched_priority= g_thread.m_priority.m_Below_Normal;
856 break;
857
858 case osl_Thread_PriorityLowest:
859 Param.sched_priority= g_thread.m_priority.m_Lowest;
860 break;
861
862 case osl_Thread_PriorityUnknown:
863 OSL_ASSERT(sal_False); /* only fools try this...*/
864
865 /* let release-version behave friendly */
866 return;
867
868 default:
869 /* enum expanded, but forgotten here...*/
870 OSL_ENSURE(sal_False,"osl_setThreadPriority : unknown priority\n");
871
872 /* let release-version behave friendly */
873 return;
874 }
875
876 if ((nRet = pthread_setschedparam(pImpl->m_hThread, policy, &Param)) != 0)
877 {
878 OSL_TRACE("failed to change thread priority [%s]\n",strerror(nRet));
879 }
880
881 #endif /* NO_PTHREAD_PRIORITY */
882 }
883
884 /*****************************************************************************/
885 /* osl_getThreadPriority */
886 /*****************************************************************************/
osl_getThreadPriority(const oslThread Thread)887 oslThreadPriority SAL_CALL osl_getThreadPriority(const oslThread Thread)
888 {
889 #ifndef NO_PTHREAD_PRIORITY
890
891 struct sched_param Param;
892 int Policy;
893
894 #endif /* NO_PTHREAD_PRIORITY */
895
896 oslThreadPriority Priority = osl_Thread_PriorityNormal;
897 Thread_Impl* pImpl= (Thread_Impl*)Thread;
898
899 OSL_ASSERT(pImpl);
900 if (!pImpl)
901 return osl_Thread_PriorityUnknown; /* EINVAL */
902
903 #ifndef NO_PTHREAD_PRIORITY
904
905 if (pthread_getschedparam(pImpl->m_hThread, &Policy, &Param) != 0)
906 return osl_Thread_PriorityUnknown; /* ESRCH */
907
908 pthread_once (&(g_thread.m_once), osl_thread_init_Impl);
909
910 /* map pthread priority to enum */
911 if (Param.sched_priority==g_thread.m_priority.m_Highest)
912 {
913 /* 127 - highest */
914 Priority= osl_Thread_PriorityHighest;
915 }
916 else if (Param.sched_priority > g_thread.m_priority.m_Normal)
917 {
918 /* 65..126 - above normal */
919 Priority= osl_Thread_PriorityAboveNormal;
920 }
921 else if (Param.sched_priority == g_thread.m_priority.m_Normal)
922 {
923 /* normal */
924 Priority= osl_Thread_PriorityNormal;
925 }
926 else if (Param.sched_priority > g_thread.m_priority.m_Lowest)
927 {
928 /* 63..1 -below normal */
929 Priority= osl_Thread_PriorityBelowNormal;
930 }
931 else if (Param.sched_priority == g_thread.m_priority.m_Lowest)
932 {
933 /* 0 - lowest */
934 Priority= osl_Thread_PriorityLowest;
935 }
936 else
937 {
938 /* unknown */
939 Priority= osl_Thread_PriorityUnknown;
940 }
941
942 #endif /* NO_PTHREAD_PRIORITY */
943
944 return Priority;
945 }
946
947 /*****************************************************************************/
948 /* osl_createThreadKey */
949 /*****************************************************************************/
osl_createThreadKey(oslThreadKeyCallbackFunction pCallback)950 oslThreadKey SAL_CALL osl_createThreadKey( oslThreadKeyCallbackFunction pCallback )
951 {
952 pthread_key_t key;
953
954 if (pthread_key_create(&key, pCallback) != 0)
955 key = 0;
956
957 return ((oslThreadKey)key);
958 }
959
960 /*****************************************************************************/
961 /* osl_destroyThreadKey */
962 /*****************************************************************************/
osl_destroyThreadKey(oslThreadKey Key)963 void SAL_CALL osl_destroyThreadKey(oslThreadKey Key)
964 {
965 pthread_key_delete((pthread_key_t)Key);
966 }
967
968 /*****************************************************************************/
969 /* osl_getThreadKeyData */
970 /*****************************************************************************/
osl_getThreadKeyData(oslThreadKey Key)971 void* SAL_CALL osl_getThreadKeyData(oslThreadKey Key)
972 {
973 return (pthread_getspecific((pthread_key_t)Key));
974 }
975
976 /*****************************************************************************/
977 /* osl_setThreadKeyData */
978 /*****************************************************************************/
osl_setThreadKeyData(oslThreadKey Key,void * pData)979 sal_Bool SAL_CALL osl_setThreadKeyData(oslThreadKey Key, void *pData)
980 {
981 return (pthread_setspecific((pthread_key_t)Key, pData) == 0);
982 }
983
984 /*****************************************************************************/
985 /* Thread Local Text Encoding */
986 /*****************************************************************************/
osl_thread_textencoding_init_Impl(void)987 static void osl_thread_textencoding_init_Impl (void)
988 {
989 rtl_TextEncoding defaultEncoding;
990 const char * pszEncoding;
991
992 /* create thread specific data key */
993 pthread_key_create (&(g_thread.m_textencoding.m_key), NULL);
994
995 /* determine default text encoding */
996 pszEncoding = getenv ("SOLAR_USER_RTL_TEXTENCODING");
997 if (pszEncoding)
998 defaultEncoding = atoi(pszEncoding);
999 else
1000 defaultEncoding = osl_getTextEncodingFromLocale(NULL);
1001
1002 OSL_ASSERT(defaultEncoding != RTL_TEXTENCODING_DONTKNOW);
1003
1004 /*
1005 Tools string functions call abort() on an unknown encoding so ASCII
1006 is a meaningfull fallback regardless wether the assertion makes sense.
1007 */
1008
1009 if ( RTL_TEXTENCODING_DONTKNOW == defaultEncoding )
1010 defaultEncoding = RTL_TEXTENCODING_ASCII_US;
1011
1012 g_thread.m_textencoding.m_default = defaultEncoding;
1013 }
1014
1015 /*****************************************************************************/
1016 /* osl_getThreadTextEncoding */
1017 /*****************************************************************************/
osl_getThreadTextEncoding()1018 rtl_TextEncoding SAL_CALL osl_getThreadTextEncoding()
1019 {
1020 rtl_TextEncoding threadEncoding;
1021
1022 pthread_once (&(g_thread.m_once), osl_thread_init_Impl);
1023
1024 /* check for thread specific encoding, use default if not set */
1025 threadEncoding = SAL_INT_CAST(
1026 rtl_TextEncoding,
1027 (sal_uIntPtr) pthread_getspecific(g_thread.m_textencoding.m_key));
1028 if (0 == threadEncoding)
1029 threadEncoding = g_thread.m_textencoding.m_default;
1030
1031 return threadEncoding;
1032 }
1033
1034 /*****************************************************************************/
1035 /* osl_setThreadTextEncoding */
1036 /*****************************************************************************/
osl_setThreadTextEncoding(rtl_TextEncoding Encoding)1037 rtl_TextEncoding osl_setThreadTextEncoding(rtl_TextEncoding Encoding)
1038 {
1039 rtl_TextEncoding oldThreadEncoding = osl_getThreadTextEncoding();
1040
1041 /* save encoding in thread local storage */
1042 pthread_setspecific (
1043 g_thread.m_textencoding.m_key,
1044 (void*) SAL_INT_CAST(sal_uIntPtr, Encoding));
1045
1046 return oldThreadEncoding;
1047 }
1048