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