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>
32 #include <vlc_atomic.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 int vlc_threadvar_create (vlc_threadvar_t
*key
, void (*destr
) (void *))
372 return pthread_key_create (key
, destr
);
375 void vlc_threadvar_delete (vlc_threadvar_t
*p_tls
)
377 pthread_key_delete (*p_tls
);
380 int vlc_threadvar_set (vlc_threadvar_t key
, void *value
)
382 return pthread_setspecific (key
, value
);
385 void *vlc_threadvar_get (vlc_threadvar_t key
)
387 return pthread_getspecific (key
);
390 static bool rt_priorities
= false;
391 static int rt_offset
;
393 void vlc_threads_setup (libvlc_int_t
*p_libvlc
)
395 static vlc_mutex_t lock
= VLC_STATIC_MUTEX
;
396 static bool initialized
= false;
398 vlc_mutex_lock (&lock
);
399 /* Initializes real-time priorities before any thread is created,
400 * just once per process. */
403 if (var_InheritBool (p_libvlc
, "rt-priority"))
405 rt_offset
= var_InheritInteger (p_libvlc
, "rt-offset");
406 rt_priorities
= true;
410 vlc_mutex_unlock (&lock
);
414 static int vlc_clone_attr (vlc_thread_t
*th
, pthread_attr_t
*attr
,
415 void *(*entry
) (void *), void *data
, int priority
)
419 /* Block the signals that signals interface plugin handles.
420 * If the LibVLC caller wants to handle some signals by itself, it should
421 * block these before whenever invoking LibVLC. And it must obviously not
422 * start the VLC signals interface plugin.
424 * LibVLC will normally ignore any interruption caused by an asynchronous
425 * signal during a system call. But there may well be some buggy cases
426 * where it fails to handle EINTR (bug reports welcome). Some underlying
427 * libraries might also not handle EINTR properly.
433 sigdelset (&set
, SIGHUP
);
434 sigaddset (&set
, SIGINT
);
435 sigaddset (&set
, SIGQUIT
);
436 sigaddset (&set
, SIGTERM
);
438 sigaddset (&set
, SIGPIPE
); /* We don't want this one, really! */
439 pthread_sigmask (SIG_BLOCK
, &set
, &oldset
);
442 #if defined (_POSIX_PRIORITY_SCHEDULING) && (_POSIX_PRIORITY_SCHEDULING >= 0) \
443 && defined (_POSIX_THREAD_PRIORITY_SCHEDULING) \
444 && (_POSIX_THREAD_PRIORITY_SCHEDULING >= 0)
447 struct sched_param sp
= { .sched_priority
= priority
+ rt_offset
, };
450 if (sp
.sched_priority
<= 0)
451 sp
.sched_priority
+= sched_get_priority_max (policy
= SCHED_OTHER
);
453 sp
.sched_priority
+= sched_get_priority_min (policy
= SCHED_RR
);
455 pthread_attr_setschedpolicy (attr
, policy
);
456 pthread_attr_setschedparam (attr
, &sp
);
457 pthread_attr_setinheritsched (attr
, PTHREAD_EXPLICIT_SCHED
);
463 /* The thread stack size.
464 * The lower the value, the less address space per thread, the highest
465 * maximum simultaneous threads per process. Too low values will cause
466 * stack overflows and weird crashes. Set with caution. Also keep in mind
467 * that 64-bits platforms consume more stack than 32-bits one.
469 * Thanks to on-demand paging, thread stack size only affects address space
470 * consumption. In terms of memory, threads only use what they need
471 * (rounded up to the page boundary).
473 * For example, on Linux i386, the default is 2 mega-bytes, which supports
474 * about 320 threads per processes. */
475 #define VLC_STACKSIZE (128 * sizeof (void *) * 1024)
478 ret
= pthread_attr_setstacksize (attr
, VLC_STACKSIZE
);
479 assert (ret
== 0); /* fails iif VLC_STACKSIZE is invalid */
482 ret
= pthread_create(&th
->handle
, attr
, entry
, data
);
483 pthread_sigmask (SIG_SETMASK
, &oldset
, NULL
);
484 pthread_attr_destroy (attr
);
488 int vlc_clone (vlc_thread_t
*th
, void *(*entry
) (void *), void *data
,
493 pthread_attr_init (&attr
);
494 return vlc_clone_attr (th
, &attr
, entry
, data
, priority
);
497 void vlc_join(vlc_thread_t th
, void **result
)
499 int val
= pthread_join(th
.handle
, result
);
500 VLC_THREAD_ASSERT ("joining thread");
504 * Creates and starts new detached thread.
505 * A detached thread cannot be joined. Its resources will be automatically
506 * released whenever the thread exits (in particular, its call stack will be
509 * Detached thread are particularly useful when some work needs to be done
510 * asynchronously, that is likely to be completed much earlier than the thread
511 * can practically be joined. In this case, thread detach can spare memory.
513 * A detached thread may be cancelled, so as to expedite its termination.
514 * Be extremely careful if you do this: while a normal joinable thread can
515 * safely be cancelled after it has already exited, cancelling an already
516 * exited detached thread is undefined: The thread handle would is destroyed
517 * immediately when the detached thread exits. So you need to ensure that the
518 * detached thread is still running before cancellation is attempted.
520 * @warning Care must be taken that any resources used by the detached thread
521 * remains valid until the thread completes.
523 * @note A detached thread must eventually exit just like another other
524 * thread. In practice, LibVLC will wait for detached threads to exit before
525 * it unloads the plugins.
527 * @param th [OUT] pointer to hold the thread handle, or NULL
528 * @param entry entry point for the thread
529 * @param data data parameter given to the entry point
530 * @param priority thread priority value
531 * @return 0 on success, a standard error code on error.
533 int vlc_clone_detach (vlc_thread_t
*th
, void *(*entry
) (void *), void *data
,
542 pthread_attr_init (&attr
);
543 pthread_attr_setdetachstate (&attr
, PTHREAD_CREATE_DETACHED
);
544 return vlc_clone_attr (th
, &attr
, entry
, data
, priority
);
547 vlc_thread_t
vlc_thread_self (void)
549 vlc_thread_t thread
= { pthread_self() };
553 #if !defined (__linux__)
554 unsigned long vlc_thread_id (void)
560 int vlc_set_priority (vlc_thread_t th
, int priority
)
562 #if defined (_POSIX_PRIORITY_SCHEDULING) && (_POSIX_PRIORITY_SCHEDULING >= 0) \
563 && defined (_POSIX_THREAD_PRIORITY_SCHEDULING) \
564 && (_POSIX_THREAD_PRIORITY_SCHEDULING >= 0)
567 struct sched_param sp
= { .sched_priority
= priority
+ rt_offset
, };
570 if (sp
.sched_priority
<= 0)
571 sp
.sched_priority
+= sched_get_priority_max (policy
= SCHED_OTHER
);
573 sp
.sched_priority
+= sched_get_priority_min (policy
= SCHED_RR
);
575 if (pthread_setschedparam(th
.handle
, policy
, &sp
))
579 (void) th
; (void) priority
;
584 void vlc_cancel(vlc_thread_t th
)
586 pthread_cancel(th
.handle
);
589 int vlc_savecancel (void)
592 int val
= pthread_setcancelstate (PTHREAD_CANCEL_DISABLE
, &state
);
594 VLC_THREAD_ASSERT ("saving cancellation");
598 void vlc_restorecancel (int state
)
603 val
= pthread_setcancelstate (state
, &oldstate
);
604 /* This should fail if an invalid value for given for state */
605 VLC_THREAD_ASSERT ("restoring cancellation");
607 if (unlikely(oldstate
!= PTHREAD_CANCEL_DISABLE
))
608 vlc_thread_fatal ("restoring cancellation while not disabled", EINVAL
,
609 __func__
, __FILE__
, __LINE__
);
611 pthread_setcancelstate (state
, NULL
);
615 void vlc_testcancel (void)
617 pthread_testcancel ();
620 void vlc_control_cancel (int cmd
, ...)
623 vlc_assert_unreachable ();
628 #if (_POSIX_TIMERS > 0)
632 if (unlikely(clock_gettime (vlc_clock_id
, &ts
) != 0))
635 return (INT64_C(1000000) * ts
.tv_sec
) + (ts
.tv_nsec
/ 1000);
640 if (unlikely(gettimeofday (&tv
, NULL
) != 0))
642 return (INT64_C(1000000) * tv
.tv_sec
) + tv
.tv_usec
;
648 void mwait (mtime_t deadline
)
650 #if (_POSIX_CLOCK_SELECTION > 0)
652 /* If the deadline is already elapsed, or within the clock precision,
653 * do not even bother the system timer. */
654 deadline
-= vlc_clock_prec
;
656 struct timespec ts
= mtime_to_ts (deadline
);
658 while (clock_nanosleep (vlc_clock_id
, TIMER_ABSTIME
, &ts
, NULL
) == EINTR
);
661 deadline
-= mdate ();
669 void msleep (mtime_t delay
)
671 struct timespec ts
= mtime_to_ts (delay
);
673 #if (_POSIX_CLOCK_SELECTION > 0)
675 while (clock_nanosleep (vlc_clock_id
, 0, &ts
, &ts
) == EINTR
);
678 while (nanosleep (&ts
, &ts
) == -1)
679 assert (errno
== EINTR
);
684 unsigned vlc_GetCPUCount(void)
686 #if defined(HAVE_SCHED_GETAFFINITY)
690 if (sched_getaffinity (0, sizeof (cpu
), &cpu
) < 0)
693 return CPU_COUNT (&cpu
);
695 #elif defined(__SunOS)
699 processor_info_t cpuinfo
;
701 processorid_t
*cpulist
= vlc_alloc (sysconf(_SC_NPROCESSORS_MAX
), sizeof (*cpulist
));
702 if (unlikely(cpulist
== NULL
))
705 if (pset_info(PS_MYID
, &type
, &numcpus
, cpulist
) == 0)
707 for (u_int i
= 0; i
< numcpus
; i
++)
708 if (processor_info (cpulist
[i
], &cpuinfo
) == 0)
709 count
+= (cpuinfo
.pi_state
== P_ONLINE
);
712 count
= sysconf (_SC_NPROCESSORS_ONLN
);
714 return count
? count
: 1;
715 #elif defined(_SC_NPROCESSORS_CONF)
716 return sysconf(_SC_NPROCESSORS_CONF
);
718 # warning "vlc_GetCPUCount is not implemented for your platform"