]> git.sesse.net Git - vlc/blob - include/vlc_threads_funcs.h
vlc_mutex_init_recursive: remove useless parameter
[vlc] / include / vlc_threads_funcs.h
1 /*****************************************************************************
2  * vlc_threads_funcs.h : threads implementation for the VideoLAN client
3  * This header provides a portable threads implementation.
4  *****************************************************************************
5  * Copyright (C) 1999-2007 the VideoLAN team
6  * $Id$
7  *
8  * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
9  *          Samuel Hocevar <sam@via.ecp.fr>
10  *          Gildas Bazin <gbazin@netcourrier.com>
11  *          Christophe Massiot <massiot@via.ecp.fr>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27
28 #if !defined( __LIBVLC__ )
29   #error You are not libvlc or one of its plugins. You cannot include this file
30 #endif
31
32 #ifndef _VLC_THREADFUNCS_H_
33 #define _VLC_THREADFUNCS_H_
34
35 #if defined( WIN32 ) && !defined ETIMEDOUT
36 #  define ETIMEDOUT 10060 /* This is the value in winsock.h. */
37 #endif
38
39 /*****************************************************************************
40  * Function definitions
41  *****************************************************************************/
42 VLC_EXPORT( int,  __vlc_mutex_init,    ( vlc_mutex_t * ) );
43 VLC_EXPORT( int,  __vlc_mutex_init_recursive, ( vlc_mutex_t * ) );
44 VLC_EXPORT( void,  __vlc_mutex_destroy, ( const char *, int, vlc_mutex_t * ) );
45 VLC_EXPORT( int,  __vlc_cond_init,     ( vlc_cond_t * ) );
46 VLC_EXPORT( void,  __vlc_cond_destroy,  ( const char *, int, vlc_cond_t * ) );
47 VLC_EXPORT( int, __vlc_threadvar_create, (vlc_threadvar_t * ) );
48 VLC_EXPORT( int,  __vlc_thread_create, ( vlc_object_t *, const char *, int, const char *, void * ( * ) ( void * ), int, bool ) );
49 VLC_EXPORT( int,  __vlc_thread_set_priority, ( vlc_object_t *, const char *, int, int ) );
50 VLC_EXPORT( void, __vlc_thread_ready,  ( vlc_object_t * ) );
51 VLC_EXPORT( void, __vlc_thread_join,   ( vlc_object_t *, const char *, int ) );
52
53 /*****************************************************************************
54  * vlc_mutex_init: initialize a mutex
55  *****************************************************************************/
56 #define vlc_mutex_init( P_MUTEX )                                   \
57     __vlc_mutex_init( P_MUTEX )
58
59 /*****************************************************************************
60  * vlc_mutex_init: initialize a recursive mutex (Don't use it)
61  *****************************************************************************/
62 #define vlc_mutex_init_recursive( P_MUTEX )                         \
63     __vlc_mutex_init_recursive( P_MUTEX )
64
65 /*****************************************************************************
66  * vlc_mutex_lock: lock a mutex
67  *****************************************************************************/
68 #define vlc_mutex_lock( P_MUTEX )                                           \
69     __vlc_mutex_lock( __FILE__, __LINE__, P_MUTEX )
70
71 #if defined(LIBVLC_USE_PTHREAD)
72 VLC_EXPORT(void, vlc_pthread_fatal, (const char *action, int error, const char *file, unsigned line));
73
74 # define VLC_THREAD_ASSERT( action ) \
75     if (val) \
76         vlc_pthread_fatal (action, val, psz_file, i_line)
77 #else
78 # define VLC_THREAD_ASSERT (void)0
79 #endif
80
81 static inline void __vlc_mutex_lock( const char * psz_file, int i_line,
82                                     vlc_mutex_t * p_mutex )
83 {
84 #if defined( UNDER_CE )
85     VLC_UNUSED( psz_file); VLC_UNUSED( i_line );
86
87     EnterCriticalSection( &p_mutex->csection );
88
89 #elif defined( WIN32 )
90     VLC_UNUSED( psz_file); VLC_UNUSED( i_line );
91
92     WaitForSingleObject( *p_mutex, INFINITE );
93
94 #elif defined( HAVE_KERNEL_SCHEDULER_H )
95     acquire_sem( p_mutex->lock );
96
97 #elif defined(LIBVLC_USE_PTHREAD)
98 #   define vlc_assert_locked( m ) \
99            assert (pthread_mutex_lock (m) == EDEADLK)
100     int val = pthread_mutex_lock( p_mutex );
101     VLC_THREAD_ASSERT ("locking mutex");
102
103 #endif
104 }
105
106 #ifndef vlc_assert_locked
107 # define vlc_assert_locked( m ) (void)0
108 #endif
109
110 /*****************************************************************************
111  * vlc_mutex_unlock: unlock a mutex
112  *****************************************************************************/
113 #define vlc_mutex_unlock( P_MUTEX )                                         \
114     __vlc_mutex_unlock( __FILE__, __LINE__, P_MUTEX )
115
116 static inline void __vlc_mutex_unlock( const char * psz_file, int i_line,
117                                       vlc_mutex_t *p_mutex )
118 {
119 #if defined( UNDER_CE )
120     VLC_UNUSED( psz_file); VLC_UNUSED( i_line );
121
122     LeaveCriticalSection( &p_mutex->csection );
123
124 #elif defined( WIN32 )
125     VLC_UNUSED( psz_file); VLC_UNUSED( i_line );
126
127     ReleaseMutex( *p_mutex );
128
129 #elif defined( HAVE_KERNEL_SCHEDULER_H )
130     release_sem( p_mutex->lock );
131
132 #elif defined(LIBVLC_USE_PTHREAD)
133     int val = pthread_mutex_unlock( p_mutex );
134     VLC_THREAD_ASSERT ("unlocking mutex");
135
136 #endif
137 }
138
139 /*****************************************************************************
140  * vlc_mutex_destroy: destroy a mutex
141  *****************************************************************************/
142 #define vlc_mutex_destroy( P_MUTEX )                                        \
143     __vlc_mutex_destroy( __FILE__, __LINE__, P_MUTEX )
144
145 /*****************************************************************************
146  * vlc_cond_init: initialize a condition
147  *****************************************************************************/
148 #define vlc_cond_init( P_THIS, P_COND )                                     \
149     __vlc_cond_init( P_COND )
150
151 /*****************************************************************************
152  * vlc_cond_signal: start a thread on condition completion
153  *****************************************************************************/
154 #define vlc_cond_signal( P_COND )                                           \
155     __vlc_cond_signal( __FILE__, __LINE__, P_COND )
156
157 static inline void __vlc_cond_signal( const char * psz_file, int i_line,
158                                       vlc_cond_t *p_condvar )
159 {
160 #if defined( UNDER_CE ) || defined( WIN32 )
161     VLC_UNUSED( psz_file); VLC_UNUSED( i_line );
162
163     /* Release one waiting thread if one is available. */
164     /* For this trick to work properly, the vlc_cond_signal must be surrounded
165      * by a mutex. This will prevent another thread from stealing the signal */
166     /* PulseEvent() only works if none of the waiting threads is suspended.
167      * This is particularily problematic under a debug session.
168      * as documented in http://support.microsoft.com/kb/q173260/ */
169     PulseEvent( p_condvar->event );
170
171 #elif defined( HAVE_KERNEL_SCHEDULER_H )
172     while( p_condvar->thread != -1 )
173     {
174         thread_info info;
175         if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
176             return;
177
178         if( info.state != B_THREAD_SUSPENDED )
179         {
180             /* The  waiting thread is not suspended so it could
181              * have been interrupted beetwen the unlock and the
182              * suspend_thread line. That is why we sleep a little
183              * before retesting p_condver->thread. */
184             snooze( 10000 );
185         }
186         else
187         {
188             /* Ok, we have to wake up that thread */
189             resume_thread( p_condvar->thread );
190         }
191     }
192
193 #elif defined(LIBVLC_USE_PTHREAD)
194     int val = pthread_cond_signal( p_condvar );
195     VLC_THREAD_ASSERT ("signaling condition variable");
196
197 #endif
198 }
199
200 /*****************************************************************************
201  * vlc_cond_wait: wait until condition completion
202  *****************************************************************************/
203 #define vlc_cond_wait( P_COND, P_MUTEX )                                     \
204     __vlc_cond_wait( __FILE__, __LINE__, P_COND, P_MUTEX  )
205
206 static inline void __vlc_cond_wait( const char * psz_file, int i_line,
207                                     vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex )
208 {
209 #if defined( UNDER_CE )
210     p_condvar->i_waiting_threads++;
211     LeaveCriticalSection( &p_mutex->csection );
212     WaitForSingleObject( p_condvar->event, INFINITE );
213     p_condvar->i_waiting_threads--;
214
215     /* Reacquire the mutex before returning. */
216     vlc_mutex_lock( p_mutex );
217
218 #elif defined( WIN32 )
219     VLC_UNUSED( psz_file); VLC_UNUSED( i_line );
220
221     /* Increase our wait count */
222     p_condvar->i_waiting_threads++;
223     SignalObjectAndWait( *p_mutex, p_condvar->event, INFINITE, FALSE );
224     p_condvar->i_waiting_threads--;
225
226     /* Reacquire the mutex before returning. */
227     vlc_mutex_lock( p_mutex );
228
229 #elif defined( HAVE_KERNEL_SCHEDULER_H )
230     /* The p_condvar->thread var is initialized before the unlock because
231      * it enables to identify when the thread is interrupted beetwen the
232      * unlock line and the suspend_thread line */
233     p_condvar->thread = find_thread( NULL );
234     vlc_mutex_unlock( p_mutex );
235     suspend_thread( p_condvar->thread );
236     p_condvar->thread = -1;
237
238     vlc_mutex_lock( p_mutex );
239
240 #elif defined(LIBVLC_USE_PTHREAD)
241     int val = pthread_cond_wait( p_condvar, p_mutex );
242     VLC_THREAD_ASSERT ("waiting on condition");
243
244 #endif
245 }
246
247
248 /*****************************************************************************
249  * vlc_cond_timedwait: wait until condition completion or expiration
250  *****************************************************************************
251  * Returns 0 if object signaled, an error code in case of timeout or error.
252  *****************************************************************************/
253 #define vlc_cond_timedwait( P_COND, P_MUTEX, DEADLINE )                      \
254     __vlc_cond_timedwait( __FILE__, __LINE__, P_COND, P_MUTEX, DEADLINE  )
255
256 static inline int __vlc_cond_timedwait( const char * psz_file, int i_line,
257                                         vlc_cond_t *p_condvar,
258                                         vlc_mutex_t *p_mutex,
259                                         mtime_t deadline )
260 {
261 #if defined( UNDER_CE )
262     mtime_t delay_ms = (deadline - mdate())/1000;
263
264     DWORD result;
265     if( delay_ms < 0 )
266         delay_ms = 0;
267
268     p_condvar->i_waiting_threads++;
269     LeaveCriticalSection( &p_mutex->csection );
270     result = WaitForSingleObject( p_condvar->event, delay_ms );
271     p_condvar->i_waiting_threads--;
272
273     /* Reacquire the mutex before returning. */
274     vlc_mutex_lock( p_mutex );
275
276     if(result == WAIT_TIMEOUT)
277        return ETIMEDOUT; /* this error is perfectly normal */
278
279 #elif defined( WIN32 )
280     VLC_UNUSED( psz_file); VLC_UNUSED( i_line );
281
282     DWORD result;
283
284     mtime_t delay_ms = (deadline - mdate())/1000;
285     if( delay_ms < 0 )
286         delay_ms = 0;
287
288     /* Increase our wait count */
289     p_condvar->i_waiting_threads++;
290     result = SignalObjectAndWait( *p_mutex, p_condvar->event,
291                                   delay_ms, FALSE );
292     p_condvar->i_waiting_threads--;
293
294     /* Reacquire the mutex before returning. */
295     vlc_mutex_lock( p_mutex );
296     if(result == WAIT_TIMEOUT)
297        return ETIMEDOUT; /* this error is perfectly normal */
298
299 #elif defined( HAVE_KERNEL_SCHEDULER_H )
300 #   error Unimplemented
301
302 #elif defined(LIBVLC_USE_PTHREAD)
303     lldiv_t d = lldiv( deadline, 1000000 );
304     struct timespec ts = { d.quot, d.rem * 1000 };
305
306     int val = pthread_cond_timedwait (p_condvar, p_mutex, &ts);
307     if (val == ETIMEDOUT)
308         return ETIMEDOUT; /* this error is perfectly normal */
309     VLC_THREAD_ASSERT ("timed-waiting on condition");
310
311 #endif
312
313     return 0;
314 }
315
316 /*****************************************************************************
317  * vlc_cond_destroy: destroy a condition
318  *****************************************************************************/
319 #define vlc_cond_destroy( P_COND )                                          \
320     __vlc_cond_destroy( __FILE__, __LINE__, P_COND )
321
322 /*****************************************************************************
323  * vlc_threadvar_create: create a thread-local variable
324  *****************************************************************************/
325 #define vlc_threadvar_create( PTHIS, P_TLS )                                 \
326    __vlc_threadvar_create( P_TLS )
327
328 /*****************************************************************************
329  * vlc_threadvar_set: create: set the value of a thread-local variable
330  *****************************************************************************/
331 static inline int vlc_threadvar_set( vlc_threadvar_t * p_tls, void *p_value )
332 {
333     int i_ret;
334
335 #if defined( HAVE_KERNEL_SCHEDULER_H )
336     i_ret = EINVAL;
337
338 #elif defined( UNDER_CE ) || defined( WIN32 )
339     i_ret = TlsSetValue( *p_tls, p_value ) ? EINVAL : 0;
340
341 #elif defined(LIBVLC_USE_PTHREAD)
342     i_ret = pthread_setspecific( *p_tls, p_value );
343
344 #endif
345
346     return i_ret;
347 }
348
349 /*****************************************************************************
350  * vlc_threadvar_get: create: get the value of a thread-local variable
351  *****************************************************************************/
352 static inline void* vlc_threadvar_get( vlc_threadvar_t * p_tls )
353 {
354     void *p_ret;
355
356 #if defined( HAVE_KERNEL_SCHEDULER_H )
357     p_ret = NULL;
358
359 #elif defined( UNDER_CE ) || defined( WIN32 )
360     p_ret = TlsGetValue( *p_tls );
361
362 #elif defined(LIBVLC_USE_PTHREAD)
363     p_ret = pthread_getspecific( *p_tls );
364
365 #endif
366
367     return p_ret;
368 }
369
370 # if defined (_POSIX_SPIN_LOCKS) && ((_POSIX_SPIN_LOCKS - 0) > 0)
371 typedef struct
372 {
373     pthread_spinlock_t  spin;
374 } vlc_spinlock_t;
375
376 /**
377  * Initializes a spinlock.
378  */
379 static inline int vlc_spin_init (vlc_spinlock_t *spin)
380 {
381     return pthread_spin_init (&spin->spin, PTHREAD_PROCESS_PRIVATE);
382 }
383
384 /**
385  * Acquires a spinlock.
386  */
387 static inline void vlc_spin_lock (vlc_spinlock_t *spin)
388 {
389     int val = pthread_spin_lock (&spin->spin);
390     assert (val == 0);
391     (void)val;
392 }
393
394 /**
395  * Releases a spinlock.
396  */
397 static inline void vlc_spin_unlock (vlc_spinlock_t *spin)
398 {
399     int val = pthread_spin_unlock (&spin->spin);
400     assert (val == 0);
401     (void)val;
402 }
403
404 /**
405  * Deinitializes a spinlock.
406  */
407 static inline void vlc_spin_destroy (vlc_spinlock_t *spin)
408 {
409     int val = pthread_spin_destroy (&spin->spin);
410     assert (val == 0);
411     (void)val;
412 }
413
414 #elif defined( WIN32 )
415
416 typedef CRITICAL_SECTION vlc_spinlock_t;
417
418 /**
419  * Initializes a spinlock.
420  */
421 static inline int vlc_spin_init (vlc_spinlock_t *spin)
422 {
423     return !InitializeCriticalSectionAndSpinCount(spin, 4000);
424 }
425
426 /**
427  * Acquires a spinlock.
428  */
429 static inline void vlc_spin_lock (vlc_spinlock_t *spin)
430 {
431     EnterCriticalSection(spin);
432 }
433
434 /**
435  * Releases a spinlock.
436  */
437 static inline void vlc_spin_unlock (vlc_spinlock_t *spin)
438 {
439     LeaveCriticalSection(spin);
440 }
441
442 /**
443  * Deinitializes a spinlock.
444  */
445 static inline void vlc_spin_destroy (vlc_spinlock_t *spin)
446 {
447     DeleteCriticalSection(spin);
448 }
449
450
451 #else
452
453 /* Fallback to plain mutexes if spinlocks are not available */
454 typedef vlc_mutex_t vlc_spinlock_t;
455
456 static inline int vlc_spin_init (vlc_spinlock_t *spin)
457 {
458     return __vlc_mutex_init (spin);
459 }
460
461 # define vlc_spin_lock    vlc_mutex_lock
462 # define vlc_spin_unlock  vlc_mutex_unlock
463 # define vlc_spin_destroy vlc_mutex_destroy
464 #endif
465
466 /*****************************************************************************
467  * vlc_thread_create: create a thread
468  *****************************************************************************/
469 #define vlc_thread_create( P_THIS, PSZ_NAME, FUNC, PRIORITY, WAIT )         \
470     __vlc_thread_create( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PSZ_NAME, (void * ( * ) ( void * ))FUNC, PRIORITY, WAIT )
471
472 /*****************************************************************************
473  * vlc_thread_set_priority: set the priority of the calling thread
474  *****************************************************************************/
475 #define vlc_thread_set_priority( P_THIS, PRIORITY )                         \
476     __vlc_thread_set_priority( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PRIORITY )
477
478 /*****************************************************************************
479  * vlc_thread_ready: tell the parent thread we were successfully spawned
480  *****************************************************************************/
481 #define vlc_thread_ready( P_THIS )                                          \
482     __vlc_thread_ready( VLC_OBJECT(P_THIS) )
483
484 /*****************************************************************************
485  * vlc_thread_join: wait until a thread exits
486  *****************************************************************************/
487 #define vlc_thread_join( P_THIS )                                           \
488     __vlc_thread_join( VLC_OBJECT(P_THIS), __FILE__, __LINE__ )
489
490 #endif