mp4: check STTS size before allocation
[vlc.git] / src / posix / thread.c
blobdab8b71f973fa66fd4654960ecde1ebf48275c61
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>
9 * Clément Sténac
10 * Rémi Denis-Courmont
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 *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
31 #include <vlc_common.h>
32 #include <vlc_atomic.h>
34 #include "libvlc.h"
35 #include <stdarg.h>
36 #include <signal.h>
37 #include <errno.h>
38 #include <time.h>
39 #include <assert.h>
41 #include <sys/types.h>
42 #include <unistd.h> /* fsync() */
43 #include <pthread.h>
44 #include <sched.h>
46 #ifdef HAVE_EXECINFO_H
47 # include <execinfo.h>
48 #endif
49 #if defined(__SunOS)
50 # include <sys/processor.h>
51 # include <sys/pset.h>
52 #endif
54 #if !defined (_POSIX_TIMERS)
55 # define _POSIX_TIMERS (-1)
56 #endif
57 #if !defined (_POSIX_CLOCK_SELECTION)
58 /* Clock selection was defined in 2001 and became mandatory in 2008. */
59 # define _POSIX_CLOCK_SELECTION (-1)
60 #endif
61 #if !defined (_POSIX_MONOTONIC_CLOCK)
62 # define _POSIX_MONOTONIC_CLOCK (-1)
63 #endif
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;
76 # else
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);
87 assert (val != 0);
88 vlc_clock_id = (val < 0) ? CLOCK_REALTIME : CLOCK_MONOTONIC;
89 # endif
91 struct timespec res;
92 if (unlikely(clock_getres (vlc_clock_id, &res) != 0 || res.tv_sec != 0))
93 abort ();
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) };
115 return ts;
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
126 void *stack[20];
127 int len = backtrace (stack, sizeof (stack) / sizeof (stack[0]));
128 backtrace_symbols_fd (stack, len, 2);
129 #endif
130 fsync (2);
133 #ifndef NDEBUG
135 * Reports a fatal error from the threading layer, for debugging purposes.
137 static void
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");
146 fflush (stderr);
148 vlc_restorecancel (canc);
149 abort ();
152 # define VLC_THREAD_ASSERT( action ) \
153 if (unlikely(val)) \
154 vlc_thread_fatal (action, val, __func__, __FILE__, __LINE__)
155 #else
156 # define VLC_THREAD_ASSERT( action ) ((void)val)
157 #endif
159 void vlc_mutex_init( vlc_mutex_t *p_mutex )
161 pthread_mutexattr_t attr;
163 if (unlikely(pthread_mutexattr_init (&attr)))
164 abort();
165 #ifdef NDEBUG
166 pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_DEFAULT);
167 #else
168 pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK);
169 #endif
170 if (unlikely(pthread_mutex_init (p_mutex, &attr)))
171 abort();
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)))
180 abort();
181 pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
182 if (unlikely(pthread_mutex_init (p_mutex, &attr)))
183 abort();
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");
193 #ifndef NDEBUG
194 # ifdef HAVE_VALGRIND_VALGRIND_H
195 # include <valgrind/valgrind.h>
196 # else
197 # define RUNNING_ON_VALGRIND (0)
198 # endif
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)
206 return;
207 assert (pthread_mutex_lock (p_mutex) == EDEADLK);
209 #endif
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 );
221 if (val != EBUSY)
222 VLC_THREAD_ASSERT ("locking mutex");
223 return val;
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)))
237 abort ();
238 #if (_POSIX_CLOCK_SELECTION > 0)
239 vlc_clock_setup ();
240 pthread_condattr_setclock (&attr, vlc_clock_id);
241 #endif
242 if (unlikely(pthread_cond_init (p_condvar, &attr)))
243 abort ();
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)))
250 abort ();
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,
277 mtime_t deadline)
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");
283 return val;
286 int vlc_cond_timedwait_daytime (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
287 time_t deadline)
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");
293 return val;
296 void vlc_sem_init (vlc_sem_t *sem, unsigned value)
298 if (unlikely(sem_init (sem, 0, value)))
299 abort ();
302 void vlc_sem_destroy (vlc_sem_t *sem)
304 int val;
306 if (likely(sem_destroy (sem) == 0))
307 return;
309 val = errno;
311 VLC_THREAD_ASSERT ("destroying semaphore");
314 int vlc_sem_post (vlc_sem_t *sem)
316 int val;
318 if (likely(sem_post (sem) == 0))
319 return 0;
321 val = errno;
323 if (unlikely(val != EOVERFLOW))
324 VLC_THREAD_ASSERT ("unlocking semaphore");
325 return val;
328 void vlc_sem_wait (vlc_sem_t *sem)
330 int val;
333 if (likely(sem_wait (sem) == 0))
334 return;
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)))
343 abort ();
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. */
401 if (!initialized)
403 if (var_InheritBool (p_libvlc, "rt-priority"))
405 rt_offset = var_InheritInteger (p_libvlc, "rt-offset");
406 rt_priorities = true;
408 initialized = 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)
417 int ret;
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.
429 sigset_t oldset;
431 sigset_t set;
432 sigemptyset (&set);
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)
445 if (rt_priorities)
447 struct sched_param sp = { .sched_priority = priority + rt_offset, };
448 int policy;
450 if (sp.sched_priority <= 0)
451 sp.sched_priority += sched_get_priority_max (policy = SCHED_OTHER);
452 else
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);
459 #else
460 (void) priority;
461 #endif
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)
477 #ifdef VLC_STACKSIZE
478 ret = pthread_attr_setstacksize (attr, VLC_STACKSIZE);
479 assert (ret == 0); /* fails iif VLC_STACKSIZE is invalid */
480 #endif
482 ret = pthread_create(&th->handle, attr, entry, data);
483 pthread_sigmask (SIG_SETMASK, &oldset, NULL);
484 pthread_attr_destroy (attr);
485 return ret;
488 int vlc_clone (vlc_thread_t *th, void *(*entry) (void *), void *data,
489 int priority)
491 pthread_attr_t attr;
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
507 * reclaimed).
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,
534 int priority)
536 vlc_thread_t dummy;
537 pthread_attr_t attr;
539 if (th == NULL)
540 th = &dummy;
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() };
550 return thread;
553 #if !defined (__linux__)
554 unsigned long vlc_thread_id (void)
556 return -1;
558 #endif
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)
565 if (rt_priorities)
567 struct sched_param sp = { .sched_priority = priority + rt_offset, };
568 int policy;
570 if (sp.sched_priority <= 0)
571 sp.sched_priority += sched_get_priority_max (policy = SCHED_OTHER);
572 else
573 sp.sched_priority += sched_get_priority_min (policy = SCHED_RR);
575 if (pthread_setschedparam(th.handle, policy, &sp))
576 return VLC_EGENERIC;
578 #else
579 (void) th; (void) priority;
580 #endif
581 return VLC_SUCCESS;
584 void vlc_cancel(vlc_thread_t th)
586 pthread_cancel(th.handle);
589 int vlc_savecancel (void)
591 int state;
592 int val = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &state);
594 VLC_THREAD_ASSERT ("saving cancellation");
595 return state;
598 void vlc_restorecancel (int state)
600 #ifndef NDEBUG
601 int oldstate, val;
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__);
610 #else
611 pthread_setcancelstate (state, NULL);
612 #endif
615 void vlc_testcancel (void)
617 pthread_testcancel ();
620 void vlc_control_cancel (int cmd, ...)
622 (void) cmd;
623 vlc_assert_unreachable ();
626 mtime_t mdate (void)
628 #if (_POSIX_TIMERS > 0)
629 struct timespec ts;
631 vlc_clock_setup ();
632 if (unlikely(clock_gettime (vlc_clock_id, &ts) != 0))
633 abort ();
635 return (INT64_C(1000000) * ts.tv_sec) + (ts.tv_nsec / 1000);
637 #else
638 struct timeval tv;
640 if (unlikely(gettimeofday (&tv, NULL) != 0))
641 abort ();
642 return (INT64_C(1000000) * tv.tv_sec) + tv.tv_usec;
644 #endif
647 #undef mwait
648 void mwait (mtime_t deadline)
650 #if (_POSIX_CLOCK_SELECTION > 0)
651 vlc_clock_setup ();
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);
660 #else
661 deadline -= mdate ();
662 if (deadline > 0)
663 msleep (deadline);
665 #endif
668 #undef msleep
669 void msleep (mtime_t delay)
671 struct timespec ts = mtime_to_ts (delay);
673 #if (_POSIX_CLOCK_SELECTION > 0)
674 vlc_clock_setup ();
675 while (clock_nanosleep (vlc_clock_id, 0, &ts, &ts) == EINTR);
677 #else
678 while (nanosleep (&ts, &ts) == -1)
679 assert (errno == EINTR);
681 #endif
684 unsigned vlc_GetCPUCount(void)
686 #if defined(HAVE_SCHED_GETAFFINITY)
687 cpu_set_t cpu;
689 CPU_ZERO(&cpu);
690 if (sched_getaffinity (0, sizeof (cpu), &cpu) < 0)
691 return 1;
693 return CPU_COUNT (&cpu);
695 #elif defined(__SunOS)
696 unsigned count = 0;
697 int type;
698 u_int numcpus;
699 processor_info_t cpuinfo;
701 processorid_t *cpulist = vlc_alloc (sysconf(_SC_NPROCESSORS_MAX), sizeof (*cpulist));
702 if (unlikely(cpulist == NULL))
703 return 1;
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);
711 else
712 count = sysconf (_SC_NPROCESSORS_ONLN);
713 free (cpulist);
714 return count ? count : 1;
715 #elif defined(_SC_NPROCESSORS_CONF)
716 return sysconf(_SC_NPROCESSORS_CONF);
717 #else
718 # warning "vlc_GetCPUCount is not implemented for your platform"
719 return 1;
720 #endif