1 /*****************************************************************************
2 * thread.c : pthread back-end for LibVLC
3 *****************************************************************************
4 * Copyright (C) 1999-2009 VLC authors and VideoLAN
6 * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
7 * Samuel Hocevar <sam@zoy.org>
8 * Gildas Bazin <gbazin@netcourrier.com>
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU Lesser General Public License as published by
14 * the Free Software Foundation; either version 2.1 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public License
23 * along with this program; if not, write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
31 #include <vlc_common.h>
35 #include <stdatomic.h>
41 #include <sys/types.h>
42 #include <unistd.h> /* fsync() */
46 #ifdef HAVE_EXECINFO_H
47 # include <execinfo.h>
50 # include <sys/processor.h>
51 # include <sys/pset.h>
54 #if !defined (_POSIX_TIMERS)
55 # define _POSIX_TIMERS (-1)
57 #if !defined (_POSIX_CLOCK_SELECTION)
58 /* Clock selection was defined in 2001 and became mandatory in 2008. */
59 # define _POSIX_CLOCK_SELECTION (-1)
61 #if !defined (_POSIX_MONOTONIC_CLOCK)
62 # define _POSIX_MONOTONIC_CLOCK (-1)
65 #if (_POSIX_TIMERS > 0)
66 static unsigned vlc_clock_prec
;
68 # if (_POSIX_MONOTONIC_CLOCK > 0) && (_POSIX_CLOCK_SELECTION > 0)
69 /* Compile-time POSIX monotonic clock support */
70 # define vlc_clock_id (CLOCK_MONOTONIC)
72 # elif (_POSIX_MONOTONIC_CLOCK == 0) && (_POSIX_CLOCK_SELECTION > 0)
73 /* Run-time POSIX monotonic clock support (see clock_setup() below) */
74 static clockid_t vlc_clock_id
;
77 /* No POSIX monotonic clock support */
78 # define vlc_clock_id (CLOCK_REALTIME)
79 # warning Monotonic clock not available. Expect timing issues.
81 # endif /* _POSIX_MONOTONIC_CLOKC */
83 static void vlc_clock_setup_once (void)
85 # if (_POSIX_MONOTONIC_CLOCK == 0)
86 long val
= sysconf (_SC_MONOTONIC_CLOCK
);
88 vlc_clock_id
= (val
< 0) ? CLOCK_REALTIME
: CLOCK_MONOTONIC
;
92 if (unlikely(clock_getres (vlc_clock_id
, &res
) != 0 || res
.tv_sec
!= 0))
94 vlc_clock_prec
= (res
.tv_nsec
+ 500) / 1000;
97 static pthread_once_t vlc_clock_once
= PTHREAD_ONCE_INIT
;
99 # define vlc_clock_setup() \
100 pthread_once(&vlc_clock_once, vlc_clock_setup_once)
102 #else /* _POSIX_TIMERS */
104 # include <sys/time.h> /* gettimeofday() */
106 # define vlc_clock_setup() (void)0
107 # warning Monotonic clock not available. Expect timing issues.
108 #endif /* _POSIX_TIMERS */
110 static struct timespec
mtime_to_ts (mtime_t date
)
112 lldiv_t d
= lldiv (date
, CLOCK_FREQ
);
113 struct timespec ts
= { d
.quot
, d
.rem
* (1000000000 / CLOCK_FREQ
) };
119 * Print a backtrace to the standard error for debugging purpose.
121 void vlc_trace (const char *fn
, const char *file
, unsigned line
)
123 fprintf (stderr
, "at %s:%u in %s\n", file
, line
, fn
);
124 fflush (stderr
); /* needed before switch to low-level I/O */
125 #ifdef HAVE_BACKTRACE
127 int len
= backtrace (stack
, sizeof (stack
) / sizeof (stack
[0]));
128 backtrace_symbols_fd (stack
, len
, 2);
135 * Reports a fatal error from the threading layer, for debugging purposes.
138 vlc_thread_fatal (const char *action
, int error
,
139 const char *function
, const char *file
, unsigned line
)
141 int canc
= vlc_savecancel ();
142 fprintf (stderr
, "LibVLC fatal error %s (%d) in thread %lu ",
143 action
, error
, vlc_thread_id ());
144 vlc_trace (function
, file
, line
);
145 perror ("Thread error");
148 vlc_restorecancel (canc
);
152 # define VLC_THREAD_ASSERT( action ) \
154 vlc_thread_fatal (action, val, __func__, __FILE__, __LINE__)
156 # define VLC_THREAD_ASSERT( action ) ((void)val)
159 void vlc_mutex_init( vlc_mutex_t
*p_mutex
)
161 pthread_mutexattr_t attr
;
163 if (unlikely(pthread_mutexattr_init (&attr
)))
166 pthread_mutexattr_settype (&attr
, PTHREAD_MUTEX_DEFAULT
);
168 pthread_mutexattr_settype (&attr
, PTHREAD_MUTEX_ERRORCHECK
);
170 if (unlikely(pthread_mutex_init (p_mutex
, &attr
)))
172 pthread_mutexattr_destroy( &attr
);
175 void vlc_mutex_init_recursive( vlc_mutex_t
*p_mutex
)
177 pthread_mutexattr_t attr
;
179 if (unlikely(pthread_mutexattr_init (&attr
)))
181 pthread_mutexattr_settype (&attr
, PTHREAD_MUTEX_RECURSIVE
);
182 if (unlikely(pthread_mutex_init (p_mutex
, &attr
)))
184 pthread_mutexattr_destroy( &attr
);
187 void vlc_mutex_destroy (vlc_mutex_t
*p_mutex
)
189 int val
= pthread_mutex_destroy( p_mutex
);
190 VLC_THREAD_ASSERT ("destroying mutex");
194 # ifdef HAVE_VALGRIND_VALGRIND_H
195 # include <valgrind/valgrind.h>
197 # define RUNNING_ON_VALGRIND (0)
201 * Asserts that a mutex is locked by the calling thread.
203 void vlc_assert_locked (vlc_mutex_t
*p_mutex
)
205 if (RUNNING_ON_VALGRIND
> 0)
207 assert (pthread_mutex_lock (p_mutex
) == EDEADLK
);
211 void vlc_mutex_lock (vlc_mutex_t
*p_mutex
)
213 int val
= pthread_mutex_lock( p_mutex
);
214 VLC_THREAD_ASSERT ("locking mutex");
217 int vlc_mutex_trylock (vlc_mutex_t
*p_mutex
)
219 int val
= pthread_mutex_trylock( p_mutex
);
222 VLC_THREAD_ASSERT ("locking mutex");
226 void vlc_mutex_unlock (vlc_mutex_t
*p_mutex
)
228 int val
= pthread_mutex_unlock( p_mutex
);
229 VLC_THREAD_ASSERT ("unlocking mutex");
232 void vlc_cond_init (vlc_cond_t
*p_condvar
)
234 pthread_condattr_t attr
;
236 if (unlikely(pthread_condattr_init (&attr
)))
238 #if (_POSIX_CLOCK_SELECTION > 0)
240 pthread_condattr_setclock (&attr
, vlc_clock_id
);
242 if (unlikely(pthread_cond_init (p_condvar
, &attr
)))
244 pthread_condattr_destroy (&attr
);
247 void vlc_cond_init_daytime (vlc_cond_t
*p_condvar
)
249 if (unlikely(pthread_cond_init (p_condvar
, NULL
)))
253 void vlc_cond_destroy (vlc_cond_t
*p_condvar
)
255 int val
= pthread_cond_destroy( p_condvar
);
256 VLC_THREAD_ASSERT ("destroying condition");
259 void vlc_cond_signal (vlc_cond_t
*p_condvar
)
261 int val
= pthread_cond_signal( p_condvar
);
262 VLC_THREAD_ASSERT ("signaling condition variable");
265 void vlc_cond_broadcast (vlc_cond_t
*p_condvar
)
267 pthread_cond_broadcast (p_condvar
);
270 void vlc_cond_wait (vlc_cond_t
*p_condvar
, vlc_mutex_t
*p_mutex
)
272 int val
= pthread_cond_wait( p_condvar
, p_mutex
);
273 VLC_THREAD_ASSERT ("waiting on condition");
276 int vlc_cond_timedwait (vlc_cond_t
*p_condvar
, vlc_mutex_t
*p_mutex
,
279 struct timespec ts
= mtime_to_ts (deadline
);
280 int val
= pthread_cond_timedwait (p_condvar
, p_mutex
, &ts
);
281 if (val
!= ETIMEDOUT
)
282 VLC_THREAD_ASSERT ("timed-waiting on condition");
286 int vlc_cond_timedwait_daytime (vlc_cond_t
*p_condvar
, vlc_mutex_t
*p_mutex
,
289 struct timespec ts
= { deadline
, 0 };
290 int val
= pthread_cond_timedwait (p_condvar
, p_mutex
, &ts
);
291 if (val
!= ETIMEDOUT
)
292 VLC_THREAD_ASSERT ("timed-waiting on condition");
296 void vlc_sem_init (vlc_sem_t
*sem
, unsigned value
)
298 if (unlikely(sem_init (sem
, 0, value
)))
302 void vlc_sem_destroy (vlc_sem_t
*sem
)
306 if (likely(sem_destroy (sem
) == 0))
311 VLC_THREAD_ASSERT ("destroying semaphore");
314 int vlc_sem_post (vlc_sem_t
*sem
)
318 if (likely(sem_post (sem
) == 0))
323 if (unlikely(val
!= EOVERFLOW
))
324 VLC_THREAD_ASSERT ("unlocking semaphore");
328 void vlc_sem_wait (vlc_sem_t
*sem
)
333 if (likely(sem_wait (sem
) == 0))
335 while ((val
= errno
) == EINTR
);
337 VLC_THREAD_ASSERT ("locking semaphore");
340 void vlc_rwlock_init (vlc_rwlock_t
*lock
)
342 if (unlikely(pthread_rwlock_init (lock
, NULL
)))
346 void vlc_rwlock_destroy (vlc_rwlock_t
*lock
)
348 int val
= pthread_rwlock_destroy (lock
);
349 VLC_THREAD_ASSERT ("destroying R/W lock");
352 void vlc_rwlock_rdlock (vlc_rwlock_t
*lock
)
354 int val
= pthread_rwlock_rdlock (lock
);
355 VLC_THREAD_ASSERT ("acquiring R/W lock for reading");
358 void vlc_rwlock_wrlock (vlc_rwlock_t
*lock
)
360 int val
= pthread_rwlock_wrlock (lock
);
361 VLC_THREAD_ASSERT ("acquiring R/W lock for writing");
364 void vlc_rwlock_unlock (vlc_rwlock_t
*lock
)
366 int val
= pthread_rwlock_unlock (lock
);
367 VLC_THREAD_ASSERT ("releasing R/W lock");
370 void vlc_once(vlc_once_t
*once
, void (*cb
)(void))
372 int val
= pthread_once(once
, cb
);
373 VLC_THREAD_ASSERT("initializing once");
376 int vlc_threadvar_create (vlc_threadvar_t
*key
, void (*destr
) (void *))
378 return pthread_key_create (key
, destr
);
381 void vlc_threadvar_delete (vlc_threadvar_t
*p_tls
)
383 pthread_key_delete (*p_tls
);
386 int vlc_threadvar_set (vlc_threadvar_t key
, void *value
)
388 return pthread_setspecific (key
, value
);
391 void *vlc_threadvar_get (vlc_threadvar_t key
)
393 return pthread_getspecific (key
);
396 static bool rt_priorities
= false;
397 static int rt_offset
;
399 void vlc_threads_setup (libvlc_int_t
*p_libvlc
)
401 static vlc_mutex_t lock
= VLC_STATIC_MUTEX
;
402 static bool initialized
= false;
404 vlc_mutex_lock (&lock
);
405 /* Initializes real-time priorities before any thread is created,
406 * just once per process. */
409 if (var_InheritBool (p_libvlc
, "rt-priority"))
411 rt_offset
= var_InheritInteger (p_libvlc
, "rt-offset");
412 rt_priorities
= true;
416 vlc_mutex_unlock (&lock
);
420 static int vlc_clone_attr (vlc_thread_t
*th
, pthread_attr_t
*attr
,
421 void *(*entry
) (void *), void *data
, int priority
)
425 /* Block the signals that signals interface plugin handles.
426 * If the LibVLC caller wants to handle some signals by itself, it should
427 * block these before whenever invoking LibVLC. And it must obviously not
428 * start the VLC signals interface plugin.
430 * LibVLC will normally ignore any interruption caused by an asynchronous
431 * signal during a system call. But there may well be some buggy cases
432 * where it fails to handle EINTR (bug reports welcome). Some underlying
433 * libraries might also not handle EINTR properly.
439 sigdelset (&set
, SIGHUP
);
440 sigaddset (&set
, SIGINT
);
441 sigaddset (&set
, SIGQUIT
);
442 sigaddset (&set
, SIGTERM
);
444 sigaddset (&set
, SIGPIPE
); /* We don't want this one, really! */
445 pthread_sigmask (SIG_BLOCK
, &set
, &oldset
);
448 #if defined (_POSIX_PRIORITY_SCHEDULING) && (_POSIX_PRIORITY_SCHEDULING >= 0) \
449 && defined (_POSIX_THREAD_PRIORITY_SCHEDULING) \
450 && (_POSIX_THREAD_PRIORITY_SCHEDULING >= 0)
453 struct sched_param sp
= { .sched_priority
= priority
+ rt_offset
, };
456 if (sp
.sched_priority
<= 0)
457 sp
.sched_priority
+= sched_get_priority_max (policy
= SCHED_OTHER
);
459 sp
.sched_priority
+= sched_get_priority_min (policy
= SCHED_RR
);
461 pthread_attr_setschedpolicy (attr
, policy
);
462 pthread_attr_setschedparam (attr
, &sp
);
463 pthread_attr_setinheritsched (attr
, PTHREAD_EXPLICIT_SCHED
);
469 /* The thread stack size.
470 * The lower the value, the less address space per thread, the highest
471 * maximum simultaneous threads per process. Too low values will cause
472 * stack overflows and weird crashes. Set with caution. Also keep in mind
473 * that 64-bits platforms consume more stack than 32-bits one.
475 * Thanks to on-demand paging, thread stack size only affects address space
476 * consumption. In terms of memory, threads only use what they need
477 * (rounded up to the page boundary).
479 * For example, on Linux i386, the default is 2 mega-bytes, which supports
480 * about 320 threads per processes. */
481 #define VLC_STACKSIZE (128 * sizeof (void *) * 1024)
484 ret
= pthread_attr_setstacksize (attr
, VLC_STACKSIZE
);
485 assert (ret
== 0); /* fails iif VLC_STACKSIZE is invalid */
488 ret
= pthread_create(&th
->handle
, attr
, entry
, data
);
489 pthread_sigmask (SIG_SETMASK
, &oldset
, NULL
);
490 pthread_attr_destroy (attr
);
494 int vlc_clone (vlc_thread_t
*th
, void *(*entry
) (void *), void *data
,
499 pthread_attr_init (&attr
);
500 return vlc_clone_attr (th
, &attr
, entry
, data
, priority
);
503 void vlc_join(vlc_thread_t th
, void **result
)
505 int val
= pthread_join(th
.handle
, result
);
506 VLC_THREAD_ASSERT ("joining thread");
510 * Creates and starts new detached thread.
511 * A detached thread cannot be joined. Its resources will be automatically
512 * released whenever the thread exits (in particular, its call stack will be
515 * Detached thread are particularly useful when some work needs to be done
516 * asynchronously, that is likely to be completed much earlier than the thread
517 * can practically be joined. In this case, thread detach can spare memory.
519 * A detached thread may be cancelled, so as to expedite its termination.
520 * Be extremely careful if you do this: while a normal joinable thread can
521 * safely be cancelled after it has already exited, cancelling an already
522 * exited detached thread is undefined: The thread handle would is destroyed
523 * immediately when the detached thread exits. So you need to ensure that the
524 * detached thread is still running before cancellation is attempted.
526 * @warning Care must be taken that any resources used by the detached thread
527 * remains valid until the thread completes.
529 * @note A detached thread must eventually exit just like another other
530 * thread. In practice, LibVLC will wait for detached threads to exit before
531 * it unloads the plugins.
533 * @param th [OUT] pointer to hold the thread handle, or NULL
534 * @param entry entry point for the thread
535 * @param data data parameter given to the entry point
536 * @param priority thread priority value
537 * @return 0 on success, a standard error code on error.
539 int vlc_clone_detach (vlc_thread_t
*th
, void *(*entry
) (void *), void *data
,
548 pthread_attr_init (&attr
);
549 pthread_attr_setdetachstate (&attr
, PTHREAD_CREATE_DETACHED
);
550 return vlc_clone_attr (th
, &attr
, entry
, data
, priority
);
553 vlc_thread_t
vlc_thread_self (void)
555 vlc_thread_t thread
= { pthread_self() };
559 VLC_WEAK
unsigned long vlc_thread_id(void)
564 int vlc_set_priority (vlc_thread_t th
, int priority
)
566 #if defined (_POSIX_PRIORITY_SCHEDULING) && (_POSIX_PRIORITY_SCHEDULING >= 0) \
567 && defined (_POSIX_THREAD_PRIORITY_SCHEDULING) \
568 && (_POSIX_THREAD_PRIORITY_SCHEDULING >= 0)
571 struct sched_param sp
= { .sched_priority
= priority
+ rt_offset
, };
574 if (sp
.sched_priority
<= 0)
575 sp
.sched_priority
+= sched_get_priority_max (policy
= SCHED_OTHER
);
577 sp
.sched_priority
+= sched_get_priority_min (policy
= SCHED_RR
);
579 if (pthread_setschedparam(th
.handle
, policy
, &sp
))
583 (void) th
; (void) priority
;
588 void vlc_cancel(vlc_thread_t th
)
590 pthread_cancel(th
.handle
);
593 int vlc_savecancel (void)
596 int val
= pthread_setcancelstate (PTHREAD_CANCEL_DISABLE
, &state
);
598 VLC_THREAD_ASSERT ("saving cancellation");
602 void vlc_restorecancel (int state
)
607 val
= pthread_setcancelstate (state
, &oldstate
);
608 /* This should fail if an invalid value for given for state */
609 VLC_THREAD_ASSERT ("restoring cancellation");
611 if (unlikely(oldstate
!= PTHREAD_CANCEL_DISABLE
))
612 vlc_thread_fatal ("restoring cancellation while not disabled", EINVAL
,
613 __func__
, __FILE__
, __LINE__
);
615 pthread_setcancelstate (state
, NULL
);
619 void vlc_testcancel (void)
621 pthread_testcancel ();
624 void vlc_control_cancel (int cmd
, ...)
627 vlc_assert_unreachable ();
632 #if (_POSIX_TIMERS > 0)
636 if (unlikely(clock_gettime (vlc_clock_id
, &ts
) != 0))
639 return (INT64_C(1000000) * ts
.tv_sec
) + (ts
.tv_nsec
/ 1000);
644 if (unlikely(gettimeofday (&tv
, NULL
) != 0))
646 return (INT64_C(1000000) * tv
.tv_sec
) + tv
.tv_usec
;
652 void mwait (mtime_t deadline
)
654 #if (_POSIX_CLOCK_SELECTION > 0)
656 /* If the deadline is already elapsed, or within the clock precision,
657 * do not even bother the system timer. */
658 deadline
-= vlc_clock_prec
;
660 struct timespec ts
= mtime_to_ts (deadline
);
662 while (clock_nanosleep (vlc_clock_id
, TIMER_ABSTIME
, &ts
, NULL
) == EINTR
);
665 deadline
-= mdate ();
673 void msleep (mtime_t delay
)
675 struct timespec ts
= mtime_to_ts (delay
);
677 #if (_POSIX_CLOCK_SELECTION > 0)
679 while (clock_nanosleep (vlc_clock_id
, 0, &ts
, &ts
) == EINTR
);
682 while (nanosleep (&ts
, &ts
) == -1)
683 assert (errno
== EINTR
);
688 unsigned vlc_GetCPUCount(void)
690 #if defined(HAVE_SCHED_GETAFFINITY)
694 if (sched_getaffinity (0, sizeof (cpu
), &cpu
) < 0)
697 return CPU_COUNT (&cpu
);
699 #elif defined(__SunOS)
703 processor_info_t cpuinfo
;
705 processorid_t
*cpulist
= vlc_alloc (sysconf(_SC_NPROCESSORS_MAX
), sizeof (*cpulist
));
706 if (unlikely(cpulist
== NULL
))
709 if (pset_info(PS_MYID
, &type
, &numcpus
, cpulist
) == 0)
711 for (u_int i
= 0; i
< numcpus
; i
++)
712 if (processor_info (cpulist
[i
], &cpuinfo
) == 0)
713 count
+= (cpuinfo
.pi_state
== P_ONLINE
);
716 count
= sysconf (_SC_NPROCESSORS_ONLN
);
718 return count
? count
: 1;
719 #elif defined(_SC_NPROCESSORS_CONF)
720 return sysconf(_SC_NPROCESSORS_CONF
);
722 # warning "vlc_GetCPUCount is not implemented for your platform"