fdkaac error strings: compactify
[vlc/gmpfix.git] / src / android / thread.c
blobdfbe9207ebc7eeb1a0f19eced44939390f8e45ad
1 /*****************************************************************************
2 * thread.c : android pthread back-end for LibVLC
3 *****************************************************************************
4 * Copyright (C) 1999-2012 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 <signal.h>
36 #include <errno.h>
37 #include <time.h>
38 #include <assert.h>
40 #include <sys/types.h>
41 #include <unistd.h> /* fsync() */
42 #include <pthread.h>
43 #include <sched.h>
45 #include <android/log.h>
46 #include <sys/syscall.h> /* __NR_gettid */
48 /* helper */
49 static struct timespec mtime_to_ts (mtime_t date)
51 lldiv_t d = lldiv (date, CLOCK_FREQ);
52 struct timespec ts = { d.quot, d.rem * (1000000000 / CLOCK_FREQ) };
54 return ts;
57 /* debug */
58 #define vlc_assert(x) do { \
59 if (unlikely(!x)) { \
60 __android_log_print(ANDROID_LOG_ERROR, "vlc", "assert failed %s:%d: %s", \
61 __FILE__, __LINE__, #x \
62 ); \
63 abort(); \
64 } \
65 } while(0)
67 #ifndef NDEBUG
68 static void
69 vlc_thread_fatal (const char *action, int error,
70 const char *function, const char *file, unsigned line)
72 char buf[1000];
73 const char *msg;
75 switch (strerror_r (error, buf, sizeof (buf)))
77 case 0:
78 msg = buf;
79 break;
80 case ERANGE: /* should never happen */
81 msg = "unknown (too big to display)";
82 break;
83 default:
84 msg = "unknown (invalid error number)";
85 break;
88 __android_log_print(ANDROID_LOG_ERROR, "vlc",
89 "LibVLC fatal error %s (%d) in thread %d "
90 "at %s:%u in %s\n Error message: %s\n",
91 action, error, syscall (__NR_gettid), file, line, function, msg);
93 abort ();
96 # define VLC_THREAD_ASSERT( action ) \
97 if (unlikely(val)) \
98 vlc_thread_fatal (action, val, __func__, __FILE__, __LINE__)
99 #else
100 # define VLC_THREAD_ASSERT( action ) ((void)val)
101 #endif
103 /* mutexes */
104 void vlc_mutex_init( vlc_mutex_t *p_mutex )
106 pthread_mutexattr_t attr;
108 pthread_mutexattr_init (&attr);
109 #ifdef NDEBUG
110 pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_DEFAULT);
111 #else
112 pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK);
113 #endif
114 pthread_mutex_init (p_mutex, &attr);
115 pthread_mutexattr_destroy( &attr );
118 void vlc_mutex_init_recursive( vlc_mutex_t *p_mutex )
120 pthread_mutexattr_t attr;
122 pthread_mutexattr_init (&attr);
123 pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
124 pthread_mutex_init (p_mutex, &attr);
125 pthread_mutexattr_destroy( &attr );
129 void vlc_mutex_destroy (vlc_mutex_t *p_mutex)
131 int val = pthread_mutex_destroy( p_mutex );
132 VLC_THREAD_ASSERT ("destroying mutex");
135 #ifndef NDEBUG
136 void vlc_assert_locked (vlc_mutex_t *p_mutex)
138 vlc_assert (pthread_mutex_lock (p_mutex) == EDEADLK);
140 #endif
142 void vlc_mutex_lock (vlc_mutex_t *p_mutex)
144 int val = pthread_mutex_lock( p_mutex );
145 VLC_THREAD_ASSERT ("locking mutex");
148 int vlc_mutex_trylock (vlc_mutex_t *p_mutex)
150 int val = pthread_mutex_trylock( p_mutex );
152 if (val != EBUSY)
153 VLC_THREAD_ASSERT ("locking mutex");
154 return val;
157 void vlc_mutex_unlock (vlc_mutex_t *p_mutex)
159 int val = pthread_mutex_unlock( p_mutex );
160 VLC_THREAD_ASSERT ("unlocking mutex");
163 struct vlc_thread
165 pthread_t thread;
166 pthread_cond_t *cond; /// Non-null if thread waiting on cond
167 vlc_mutex_t lock ; /// Protects cond
168 vlc_sem_t finished;
170 void *(*entry)(void*);
171 void *data;
173 atomic_bool killed;
174 bool killable;
177 static __thread struct vlc_thread *thread = NULL;
179 void vlc_threads_setup (libvlc_int_t *p_libvlc)
181 (void)p_libvlc;
184 /* cond */
186 void vlc_cond_init (vlc_cond_t *condvar)
188 if (unlikely(pthread_cond_init (&condvar->cond, NULL)))
189 abort ();
190 condvar->clock = CLOCK_MONOTONIC;
193 void vlc_cond_init_daytime (vlc_cond_t *condvar)
195 if (unlikely(pthread_cond_init (&condvar->cond, NULL)))
196 abort ();
197 condvar->clock = CLOCK_REALTIME;
200 void vlc_cond_destroy (vlc_cond_t *condvar)
202 int val = pthread_cond_destroy (&condvar->cond);
203 VLC_THREAD_ASSERT ("destroying condition");
206 void vlc_cond_signal (vlc_cond_t *condvar)
208 int val = pthread_cond_signal (&condvar->cond);
209 VLC_THREAD_ASSERT ("signaling condition variable");
212 void vlc_cond_broadcast (vlc_cond_t *condvar)
214 pthread_cond_broadcast (&condvar->cond);
217 void vlc_cond_wait (vlc_cond_t *condvar, vlc_mutex_t *p_mutex)
219 vlc_thread_t th = thread;
221 if (th != NULL)
223 vlc_testcancel ();
224 if (vlc_mutex_trylock (&th->lock) == 0)
226 th->cond = &condvar->cond;
227 vlc_mutex_unlock (&th->lock);
229 else
230 { /* The lock is already held by another thread.
231 * => That other thread has just cancelled this one. */
232 vlc_testcancel ();
233 /* Cancellation did not occur even though this thread is cancelled.
234 * => Cancellation is disabled. */
235 th = NULL;
239 int val = pthread_cond_wait (&condvar->cond, p_mutex);
240 VLC_THREAD_ASSERT ("waiting on condition");
242 if (th != NULL)
244 if (vlc_mutex_trylock (&th->lock) == 0)
246 thread->cond = NULL;
247 vlc_mutex_unlock (&th->lock);
249 /* Else: This thread was cancelled and is cancellable.
250 vlc_testcancel() will take of it right there: */
251 vlc_testcancel();
255 int vlc_cond_timedwait (vlc_cond_t *condvar, vlc_mutex_t *p_mutex,
256 mtime_t deadline)
258 struct timespec ts = mtime_to_ts (deadline);
259 vlc_thread_t th = thread;
260 int (*cb)(pthread_cond_t *, pthread_mutex_t *, const struct timespec *);
262 if (th != NULL)
264 vlc_testcancel ();
265 if (vlc_mutex_trylock (&th->lock) == 0)
267 th->cond = &condvar->cond;
268 vlc_mutex_unlock (&th->lock);
270 else
271 { /* The lock is already held by another thread.
272 * => That other thread has just cancelled this one. */
273 vlc_testcancel ();
274 /* Cancellation did not occur even though this thread is cancelled.
275 * => Cancellation is disabled. */
276 th = NULL;
280 switch (condvar->clock)
282 case CLOCK_REALTIME:
283 cb = pthread_cond_timedwait;
284 break;
285 case CLOCK_MONOTONIC:
286 cb = pthread_cond_timedwait_monotonic_np;
287 break;
288 default:
289 assert (0);
292 int val = cb (&condvar->cond, p_mutex, &ts);
293 if (val != ETIMEDOUT)
294 VLC_THREAD_ASSERT ("timed-waiting on condition");
296 if (th != NULL)
298 if (vlc_mutex_trylock (&th->lock) == 0)
300 thread->cond = NULL;
301 vlc_mutex_unlock (&th->lock);
303 /* Else: This thread was cancelled and is cancellable.
304 vlc_testcancel() will take of it right there: */
305 vlc_testcancel();
307 return val;
310 /* pthread */
311 static void clean_detached_thread(void *data)
313 struct vlc_thread *thread = data;
315 /* release thread handle */
316 vlc_mutex_destroy(&thread->lock);
317 free(thread);
320 static void *detached_thread(void *data)
322 vlc_thread_t th = data;
324 thread = th;
326 vlc_cleanup_push(clean_detached_thread, data);
327 th->entry(th->data);
328 vlc_cleanup_run();
330 return NULL;
333 static void finish_joinable_thread(void *data)
335 vlc_thread_t th = data;
337 vlc_sem_post(&th->finished);
340 static void *joinable_thread(void *data)
342 vlc_thread_t th = data;
343 void *ret;
345 vlc_cleanup_push(finish_joinable_thread, th);
346 thread = th;
347 ret = th->entry(th->data);
348 vlc_cleanup_run();
350 return ret;
353 static int vlc_clone_attr (vlc_thread_t *th, void *(*entry) (void *),
354 void *data, bool detach)
356 vlc_thread_t thread = malloc (sizeof (*thread));
357 if (unlikely(thread == NULL))
358 return ENOMEM;
360 int ret;
362 sigset_t oldset;
364 sigset_t set;
365 sigemptyset (&set);
366 sigdelset (&set, SIGHUP);
367 sigaddset (&set, SIGINT);
368 sigaddset (&set, SIGQUIT);
369 sigaddset (&set, SIGTERM);
371 sigaddset (&set, SIGPIPE); /* We don't want this one, really! */
372 pthread_sigmask (SIG_BLOCK, &set, &oldset);
376 vlc_sem_init(&thread->finished, 0);
377 atomic_store(&thread->killed, false);
378 thread->killable = true;
379 thread->cond = NULL;
380 thread->entry = entry;
381 thread->data = data;
382 vlc_mutex_init(&thread->lock);
384 pthread_attr_t attr;
385 pthread_attr_init (&attr);
386 pthread_attr_setdetachstate (&attr, detach ? PTHREAD_CREATE_DETACHED
387 : PTHREAD_CREATE_JOINABLE);
389 ret = pthread_create (&thread->thread, &attr,
390 detach ? detached_thread : joinable_thread, thread);
391 pthread_attr_destroy (&attr);
393 pthread_sigmask (SIG_SETMASK, &oldset, NULL);
394 *th = thread;
395 return ret;
398 int vlc_clone (vlc_thread_t *th, void *(*entry) (void *), void *data,
399 int priority)
401 (void) priority;
402 return vlc_clone_attr (th, entry, data, false);
405 void vlc_join (vlc_thread_t handle, void **result)
407 vlc_sem_wait (&handle->finished);
408 vlc_sem_destroy (&handle->finished);
410 int val = pthread_join (handle->thread, result);
411 VLC_THREAD_ASSERT ("joining thread");
412 vlc_mutex_destroy(&handle->lock);
413 free(handle);
416 int vlc_clone_detach (vlc_thread_t *th, void *(*entry) (void *), void *data,
417 int priority)
419 vlc_thread_t dummy;
420 if (th == NULL)
421 th = &dummy;
423 (void) priority;
424 return vlc_clone_attr (th, entry, data, true);
427 int vlc_set_priority (vlc_thread_t th, int priority)
429 (void) th; (void) priority;
430 return VLC_SUCCESS;
433 void vlc_cancel (vlc_thread_t thread_id)
435 pthread_cond_t *cond;
437 atomic_store(&thread_id->killed, true);
439 vlc_mutex_lock(&thread_id->lock);
440 cond = thread_id->cond;
441 if (cond)
442 pthread_cond_broadcast(cond);
443 vlc_mutex_unlock(&thread_id->lock);
446 int vlc_savecancel (void)
448 if (!thread) /* not created by VLC, can't be cancelled */
449 return true;
451 int oldstate = thread->killable;
452 thread->killable = false;
453 return oldstate;
456 void vlc_restorecancel (int state)
458 if (!thread) /* not created by VLC, can't be cancelled */
459 return;
461 thread->killable = state;
464 void vlc_testcancel (void)
466 if (!thread) /* not created by VLC, can't be cancelled */
467 return;
468 if (!thread->killable)
469 return;
470 if (!atomic_load(&thread->killed))
471 return;
473 pthread_exit(NULL);
476 /* threadvar */
478 int vlc_threadvar_create (vlc_threadvar_t *key, void (*destr) (void *))
480 return pthread_key_create (key, destr);
483 void vlc_threadvar_delete (vlc_threadvar_t *p_tls)
485 pthread_key_delete (*p_tls);
488 int vlc_threadvar_set (vlc_threadvar_t key, void *value)
490 return pthread_setspecific (key, value);
493 void *vlc_threadvar_get (vlc_threadvar_t key)
495 return pthread_getspecific (key);
498 /* time */
499 mtime_t mdate (void)
501 struct timespec ts;
503 if (unlikely(clock_gettime (CLOCK_MONOTONIC, &ts) != 0))
504 abort ();
506 return (INT64_C(1000000) * ts.tv_sec) + (ts.tv_nsec / 1000);
509 #undef mwait
510 void mwait (mtime_t deadline)
512 vlc_mutex_t lock;
513 vlc_cond_t wait;
515 vlc_mutex_init (&lock);
516 vlc_cond_init (&wait);
518 vlc_mutex_lock (&lock);
519 mutex_cleanup_push (&lock);
520 while (!vlc_cond_timedwait (&wait, &lock, deadline));
521 vlc_cleanup_run ();
523 vlc_cond_destroy (&wait);
524 vlc_mutex_destroy (&lock);
527 #undef msleep
528 void msleep (mtime_t delay)
530 mwait (mdate () + delay);
533 /* cpu */
535 unsigned vlc_GetCPUCount(void)
537 return sysconf(_SC_NPROCESSORS_CONF);