chroma: cvpx: always use cached copy
[vlc.git] / src / posix / thread.c
blobe849abc5bb1b6111be4e88978a09943291ad994e
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>
33 #include "libvlc.h"
34 #include <stdarg.h>
35 #include <stdatomic.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 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. */
407 if (!initialized)
409 if (var_InheritBool (p_libvlc, "rt-priority"))
411 rt_offset = var_InheritInteger (p_libvlc, "rt-offset");
412 rt_priorities = true;
414 initialized = 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)
423 int ret;
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.
435 sigset_t oldset;
437 sigset_t set;
438 sigemptyset (&set);
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)
451 if (rt_priorities)
453 struct sched_param sp = { .sched_priority = priority + rt_offset, };
454 int policy;
456 if (sp.sched_priority <= 0)
457 sp.sched_priority += sched_get_priority_max (policy = SCHED_OTHER);
458 else
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);
465 #else
466 (void) priority;
467 #endif
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)
483 #ifdef VLC_STACKSIZE
484 ret = pthread_attr_setstacksize (attr, VLC_STACKSIZE);
485 assert (ret == 0); /* fails iif VLC_STACKSIZE is invalid */
486 #endif
488 ret = pthread_create(&th->handle, attr, entry, data);
489 pthread_sigmask (SIG_SETMASK, &oldset, NULL);
490 pthread_attr_destroy (attr);
491 return ret;
494 int vlc_clone (vlc_thread_t *th, void *(*entry) (void *), void *data,
495 int priority)
497 pthread_attr_t attr;
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
513 * reclaimed).
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,
540 int priority)
542 vlc_thread_t dummy;
543 pthread_attr_t attr;
545 if (th == NULL)
546 th = &dummy;
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() };
556 return thread;
559 VLC_WEAK unsigned long vlc_thread_id(void)
561 return -1;
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)
569 if (rt_priorities)
571 struct sched_param sp = { .sched_priority = priority + rt_offset, };
572 int policy;
574 if (sp.sched_priority <= 0)
575 sp.sched_priority += sched_get_priority_max (policy = SCHED_OTHER);
576 else
577 sp.sched_priority += sched_get_priority_min (policy = SCHED_RR);
579 if (pthread_setschedparam(th.handle, policy, &sp))
580 return VLC_EGENERIC;
582 #else
583 (void) th; (void) priority;
584 #endif
585 return VLC_SUCCESS;
588 void vlc_cancel(vlc_thread_t th)
590 pthread_cancel(th.handle);
593 int vlc_savecancel (void)
595 int state;
596 int val = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &state);
598 VLC_THREAD_ASSERT ("saving cancellation");
599 return state;
602 void vlc_restorecancel (int state)
604 #ifndef NDEBUG
605 int oldstate, val;
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__);
614 #else
615 pthread_setcancelstate (state, NULL);
616 #endif
619 void vlc_testcancel (void)
621 pthread_testcancel ();
624 void vlc_control_cancel (int cmd, ...)
626 (void) cmd;
627 vlc_assert_unreachable ();
630 mtime_t mdate (void)
632 #if (_POSIX_TIMERS > 0)
633 struct timespec ts;
635 vlc_clock_setup ();
636 if (unlikely(clock_gettime (vlc_clock_id, &ts) != 0))
637 abort ();
639 return (INT64_C(1000000) * ts.tv_sec) + (ts.tv_nsec / 1000);
641 #else
642 struct timeval tv;
644 if (unlikely(gettimeofday (&tv, NULL) != 0))
645 abort ();
646 return (INT64_C(1000000) * tv.tv_sec) + tv.tv_usec;
648 #endif
651 #undef mwait
652 void mwait (mtime_t deadline)
654 #if (_POSIX_CLOCK_SELECTION > 0)
655 vlc_clock_setup ();
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);
664 #else
665 deadline -= mdate ();
666 if (deadline > 0)
667 msleep (deadline);
669 #endif
672 #undef msleep
673 void msleep (mtime_t delay)
675 struct timespec ts = mtime_to_ts (delay);
677 #if (_POSIX_CLOCK_SELECTION > 0)
678 vlc_clock_setup ();
679 while (clock_nanosleep (vlc_clock_id, 0, &ts, &ts) == EINTR);
681 #else
682 while (nanosleep (&ts, &ts) == -1)
683 assert (errno == EINTR);
685 #endif
688 unsigned vlc_GetCPUCount(void)
690 #if defined(HAVE_SCHED_GETAFFINITY)
691 cpu_set_t cpu;
693 CPU_ZERO(&cpu);
694 if (sched_getaffinity (0, sizeof (cpu), &cpu) < 0)
695 return 1;
697 return CPU_COUNT (&cpu);
699 #elif defined(__SunOS)
700 unsigned count = 0;
701 int type;
702 u_int numcpus;
703 processor_info_t cpuinfo;
705 processorid_t *cpulist = vlc_alloc (sysconf(_SC_NPROCESSORS_MAX), sizeof (*cpulist));
706 if (unlikely(cpulist == NULL))
707 return 1;
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);
715 else
716 count = sysconf (_SC_NPROCESSORS_ONLN);
717 free (cpulist);
718 return count ? count : 1;
719 #elif defined(_SC_NPROCESSORS_CONF)
720 return sysconf(_SC_NPROCESSORS_CONF);
721 #else
722 # warning "vlc_GetCPUCount is not implemented for your platform"
723 return 1;
724 #endif