]> git.sesse.net Git - vlc/blob - include/vlc_threads_funcs.h
Restores [13132] back - break the new interface again
[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, 2002 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 /*****************************************************************************
29  * Function definitions
30  *****************************************************************************/
31 VLC_EXPORT( int,  __vlc_threads_init,  ( vlc_object_t * ) );
32 VLC_EXPORT( int,  __vlc_threads_end,   ( vlc_object_t * ) );
33 VLC_EXPORT( int,  __vlc_mutex_init,    ( vlc_object_t *, vlc_mutex_t * ) );
34 VLC_EXPORT( int,  __vlc_mutex_destroy, ( char *, int, vlc_mutex_t * ) );
35 VLC_EXPORT( int,  __vlc_cond_init,     ( vlc_object_t *, vlc_cond_t * ) );
36 VLC_EXPORT( int,  __vlc_cond_destroy,  ( char *, int, vlc_cond_t * ) );
37 VLC_EXPORT( int,  __vlc_thread_create, ( vlc_object_t *, char *, int, char *, void * ( * ) ( void * ), int, vlc_bool_t ) );
38 VLC_EXPORT( int,  __vlc_thread_set_priority, ( vlc_object_t *, char *, int, int ) );
39 VLC_EXPORT( void, __vlc_thread_ready,  ( vlc_object_t * ) );
40 VLC_EXPORT( void, __vlc_thread_join,   ( vlc_object_t *, char *, int ) );
41
42
43 /*****************************************************************************
44  * vlc_threads_init: initialize threads system
45  *****************************************************************************/
46 #define vlc_threads_init( P_THIS )                                          \
47     __vlc_threads_init( VLC_OBJECT(P_THIS) )
48
49 /*****************************************************************************
50  * vlc_threads_end: deinitialize threads system
51  *****************************************************************************/
52 #define vlc_threads_end( P_THIS )                                           \
53     __vlc_threads_end( VLC_OBJECT(P_THIS) )
54
55 /*****************************************************************************
56  * vlc_mutex_init: initialize a mutex
57  *****************************************************************************/
58 #define vlc_mutex_init( P_THIS, P_MUTEX )                                   \
59     __vlc_mutex_init( VLC_OBJECT(P_THIS), P_MUTEX )
60
61 /*****************************************************************************
62  * vlc_mutex_lock: lock a mutex
63  *****************************************************************************/
64 #define vlc_mutex_lock( P_MUTEX )                                           \
65     __vlc_mutex_lock( __FILE__, __LINE__, P_MUTEX )
66
67 static inline int __vlc_mutex_lock( const char * psz_file, int i_line,
68                                     vlc_mutex_t * p_mutex )
69 {
70     int i_result;
71     /* In case of error : */
72     int i_thread = -1;
73     const char * psz_error = "";
74
75 #if defined( PTH_INIT_IN_PTH_H )
76     i_result = ( pth_mutex_acquire( &p_mutex->mutex, FALSE, NULL ) == FALSE );
77
78 #elif defined( ST_INIT_IN_ST_H )
79     i_result = st_mutex_lock( p_mutex->mutex );
80
81 #elif defined( UNDER_CE )
82     EnterCriticalSection( &p_mutex->csection );
83     i_result = 0;
84
85 #elif defined( WIN32 )
86     if( p_mutex->mutex )
87     {
88         WaitForSingleObject( p_mutex->mutex, INFINITE );
89     }
90     else
91     {
92         EnterCriticalSection( &p_mutex->csection );
93     }
94     i_result = 0;
95
96 #elif defined( HAVE_KERNEL_SCHEDULER_H )
97     if( p_mutex == NULL )
98     {
99         i_result = B_BAD_VALUE;
100     }
101     else if( p_mutex->init < 2000 )
102     {
103         i_result = B_NO_INIT;
104     }
105     else
106     {
107         i_result = acquire_sem( p_mutex->lock );
108     }
109
110 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
111     i_result = pthread_mutex_lock( &p_mutex->mutex );
112     if ( i_result )
113     {
114         i_thread = (int)pthread_self();
115         psz_error = strerror(i_result);
116     }
117
118 #elif defined( HAVE_CTHREADS_H )
119     mutex_lock( p_mutex->mutex );
120     i_result = 0;
121
122 #endif
123
124     if( i_result )
125     {
126         msg_Err( p_mutex->p_this,
127                  "thread %u: mutex_lock failed at %s:%d (%d:%s)",
128                  i_thread, psz_file, i_line, i_result, psz_error );
129     }
130     return i_result;
131 }
132
133 /*****************************************************************************
134  * vlc_mutex_unlock: unlock a mutex
135  *****************************************************************************/
136 #define vlc_mutex_unlock( P_MUTEX )                                         \
137     __vlc_mutex_unlock( __FILE__, __LINE__, P_MUTEX )
138
139 static inline int __vlc_mutex_unlock( const char * psz_file, int i_line,
140                                       vlc_mutex_t *p_mutex )
141 {
142     int i_result;
143     /* In case of error : */
144     int i_thread = -1;
145     const char * psz_error = "";
146
147 #if defined( PTH_INIT_IN_PTH_H )
148     i_result = ( pth_mutex_release( &p_mutex->mutex ) == FALSE );
149
150 #elif defined( ST_INIT_IN_ST_H )
151     i_result = st_mutex_unlock( p_mutex->mutex );
152
153 #elif defined( UNDER_CE )
154     LeaveCriticalSection( &p_mutex->csection );
155     i_result = 0;
156
157 #elif defined( WIN32 )
158     if( p_mutex->mutex )
159     {
160         ReleaseMutex( p_mutex->mutex );
161     }
162     else
163     {
164         LeaveCriticalSection( &p_mutex->csection );
165     }
166     i_result = 0;
167
168 #elif defined( HAVE_KERNEL_SCHEDULER_H )
169     if( p_mutex == NULL )
170     {
171         i_result = B_BAD_VALUE;
172     }
173     else if( p_mutex->init < 2000 )
174     {
175         i_result = B_NO_INIT;
176     }
177     else
178     {
179         release_sem( p_mutex->lock );
180         return B_OK;
181     }
182
183 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
184     i_result = pthread_mutex_unlock( &p_mutex->mutex );
185     if ( i_result )
186     {
187         i_thread = (int)pthread_self();
188         psz_error = strerror(i_result);
189     }
190
191 #elif defined( HAVE_CTHREADS_H )
192     mutex_unlock( p_mutex );
193     i_result = 0;
194
195 #endif
196
197     if( i_result )
198     {
199         msg_Err( p_mutex->p_this,
200                  "thread %u: mutex_unlock failed at %s:%d (%d:%s)",
201                  i_thread, psz_file, i_line, i_result, psz_error );
202     }
203
204     return i_result;
205 }
206
207 /*****************************************************************************
208  * vlc_mutex_destroy: destroy a mutex
209  *****************************************************************************/
210 #define vlc_mutex_destroy( P_MUTEX )                                        \
211     __vlc_mutex_destroy( __FILE__, __LINE__, P_MUTEX )
212
213 /*****************************************************************************
214  * vlc_cond_init: initialize a condition
215  *****************************************************************************/
216 #define vlc_cond_init( P_THIS, P_COND )                                     \
217     __vlc_cond_init( VLC_OBJECT(P_THIS), P_COND )
218
219 /*****************************************************************************
220  * vlc_cond_signal: start a thread on condition completion
221  *****************************************************************************/
222 #define vlc_cond_signal( P_COND )                                           \
223     __vlc_cond_signal( __FILE__, __LINE__, P_COND )
224
225 static inline int __vlc_cond_signal( const char * psz_file, int i_line,
226                                      vlc_cond_t *p_condvar )
227 {
228     int i_result;
229     /* In case of error : */
230     int i_thread = -1;
231     const char * psz_error = "";
232
233 #if defined( PTH_INIT_IN_PTH_H )
234     i_result = ( pth_cond_notify( &p_condvar->cond, FALSE ) == FALSE );
235
236 #elif defined( ST_INIT_IN_ST_H )
237     i_result = st_cond_signal( p_condvar->cond );
238
239 #elif defined( UNDER_CE )
240     PulseEvent( p_condvar->event );
241     i_result = 0;
242
243 #elif defined( WIN32 )
244     /* Release one waiting thread if one is available. */
245     /* For this trick to work properly, the vlc_cond_signal must be surrounded
246      * by a mutex. This will prevent another thread from stealing the signal */
247     if( !p_condvar->semaphore )
248     {
249         PulseEvent( p_condvar->event );
250     }
251     else if( p_condvar->i_win9x_cv == 1 )
252     {
253         /* Wait for the gate to be open */
254         WaitForSingleObject( p_condvar->event, INFINITE );
255
256         if( p_condvar->i_waiting_threads )
257         {
258             /* Using a semaphore exposes us to a race condition. It is
259              * possible for another thread to start waiting on the semaphore
260              * just after we signaled it and thus steal the signal.
261              * We have to prevent new threads from entering the cond_wait(). */
262             ResetEvent( p_condvar->event );
263
264             /* A semaphore is used here because Win9x doesn't have
265              * SignalObjectAndWait() and thus a race condition exists
266              * during the time we release the mutex and the time we start
267              * waiting on the event (more precisely, the signal can sometimes
268              * be missed by the waiting thread if we use PulseEvent()). */
269             ReleaseSemaphore( p_condvar->semaphore, 1, 0 );
270         }
271     }
272     else
273     {
274         if( p_condvar->i_waiting_threads )
275         {
276             ReleaseSemaphore( p_condvar->semaphore, 1, 0 );
277
278             /* Wait for the last thread to be awakened */
279             WaitForSingleObject( p_condvar->event, INFINITE );
280         }
281     }
282     i_result = 0;
283
284 #elif defined( HAVE_KERNEL_SCHEDULER_H )
285     if( p_condvar == NULL )
286     {
287         i_result = B_BAD_VALUE;
288     }
289     else if( p_condvar->init < 2000 )
290     {
291         i_result = B_NO_INIT;
292     }
293     else
294     {
295         while( p_condvar->thread != -1 )
296         {
297             thread_info info;
298             if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
299             {
300                 return 0;
301             }
302
303             if( info.state != B_THREAD_SUSPENDED )
304             {
305                 /* The  waiting thread is not suspended so it could
306                  * have been interrupted beetwen the unlock and the
307                  * suspend_thread line. That is why we sleep a little
308                  * before retesting p_condver->thread. */
309                 snooze( 10000 );
310             }
311             else
312             {
313                 /* Ok, we have to wake up that thread */
314                 resume_thread( p_condvar->thread );
315                 return 0;
316             }
317         }
318         i_result = 0;
319     }
320
321 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
322     i_result = pthread_cond_signal( &p_condvar->cond );
323     if ( i_result )
324     {
325         i_thread = (int)pthread_self();
326         psz_error = strerror(i_result);
327     }
328
329 #elif defined( HAVE_CTHREADS_H )
330     /* condition_signal() */
331     if ( p_condvar->queue.head || p_condvar->implications )
332     {
333         cond_signal( (condition_t)p_condvar );
334     }
335     i_result = 0;
336
337 #endif
338
339     if( i_result )
340     {
341         msg_Err( p_condvar->p_this,
342                  "thread %u: cond_signal failed at %s:%d (%d:%s)",
343                  i_thread, psz_file, i_line, i_result, psz_error );
344     }
345
346     return i_result;
347 }
348
349 /*****************************************************************************
350  * vlc_cond_wait: wait until condition completion
351  *****************************************************************************/
352 #define vlc_cond_wait( P_COND, P_MUTEX )                                     \
353     __vlc_cond_wait( __FILE__, __LINE__, P_COND, P_MUTEX  )
354
355 static inline int __vlc_cond_wait( const char * psz_file, int i_line,
356                                    vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex )
357 {
358     int i_result;
359     /* In case of error : */
360     int i_thread = -1;
361     const char * psz_error = "";
362
363 #if defined( PTH_INIT_IN_PTH_H )
364     i_result = ( pth_cond_await( &p_condvar->cond, &p_mutex->mutex, NULL )
365                  == FALSE );
366
367 #elif defined( ST_INIT_IN_ST_H )
368     st_mutex_unlock( p_mutex->mutex );
369     i_result = st_cond_wait( p_condvar->cond );
370     st_mutex_lock( p_mutex->mutex );
371
372 #elif defined( UNDER_CE )
373     p_condvar->i_waiting_threads++;
374     LeaveCriticalSection( &p_mutex->csection );
375     WaitForSingleObject( p_condvar->event, INFINITE );
376     p_condvar->i_waiting_threads--;
377
378     /* Reacquire the mutex before returning. */
379     vlc_mutex_lock( p_mutex );
380
381     i_result = 0;
382
383 #elif defined( WIN32 )
384     if( !p_condvar->semaphore )
385     {
386         /* Increase our wait count */
387         p_condvar->i_waiting_threads++;
388
389         if( p_mutex->mutex )
390         {
391             /* It is only possible to atomically release the mutex and
392              * initiate the waiting on WinNT/2K/XP. Win9x doesn't have
393              * SignalObjectAndWait(). */
394             p_condvar->SignalObjectAndWait( p_mutex->mutex,
395                                             p_condvar->event,
396                                             INFINITE, FALSE );
397         }
398         else
399         {
400             LeaveCriticalSection( &p_mutex->csection );
401             WaitForSingleObject( p_condvar->event, INFINITE );
402         }
403
404         p_condvar->i_waiting_threads--;
405     }
406     else if( p_condvar->i_win9x_cv == 1 )
407     {
408         int i_waiting_threads;
409
410         /* Wait for the gate to be open */
411         WaitForSingleObject( p_condvar->event, INFINITE );
412
413         /* Increase our wait count */
414         p_condvar->i_waiting_threads++;
415
416         LeaveCriticalSection( &p_mutex->csection );
417         WaitForSingleObject( p_condvar->semaphore, INFINITE );
418
419         /* Decrement and test must be atomic */
420         EnterCriticalSection( &p_condvar->csection );
421
422         /* Decrease our wait count */
423         i_waiting_threads = --p_condvar->i_waiting_threads;
424
425         LeaveCriticalSection( &p_condvar->csection );
426
427         /* Reopen the gate if we were the last waiting thread */
428         if( !i_waiting_threads )
429             SetEvent( p_condvar->event );
430     }
431     else
432     {
433         int i_waiting_threads;
434
435         /* Increase our wait count */
436         p_condvar->i_waiting_threads++;
437
438         LeaveCriticalSection( &p_mutex->csection );
439         WaitForSingleObject( p_condvar->semaphore, INFINITE );
440
441         /* Decrement and test must be atomic */
442         EnterCriticalSection( &p_condvar->csection );
443
444         /* Decrease our wait count */
445         i_waiting_threads = --p_condvar->i_waiting_threads;
446
447         LeaveCriticalSection( &p_condvar->csection );
448
449         /* Signal that the last waiting thread just went through */
450         if( !i_waiting_threads )
451             SetEvent( p_condvar->event );
452     }
453
454     /* Reacquire the mutex before returning. */
455     vlc_mutex_lock( p_mutex );
456
457     i_result = 0;
458
459 #elif defined( HAVE_KERNEL_SCHEDULER_H )
460     if( p_condvar == NULL )
461     {
462         i_result = B_BAD_VALUE;
463     }
464     else if( p_mutex == NULL )
465     {
466         i_result = B_BAD_VALUE;
467     }
468     else if( p_condvar->init < 2000 )
469     {
470         i_result = B_NO_INIT;
471     }
472
473     /* The p_condvar->thread var is initialized before the unlock because
474      * it enables to identify when the thread is interrupted beetwen the
475      * unlock line and the suspend_thread line */
476     p_condvar->thread = find_thread( NULL );
477     vlc_mutex_unlock( p_mutex );
478     suspend_thread( p_condvar->thread );
479     p_condvar->thread = -1;
480
481     vlc_mutex_lock( p_mutex );
482     i_result = 0;
483
484 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
485
486 #   ifdef DEBUG
487     /* In debug mode, timeout */
488     struct timeval now;
489     struct timespec timeout;
490
491     gettimeofday( &now, NULL );
492     timeout.tv_sec = now.tv_sec + THREAD_COND_TIMEOUT;
493     timeout.tv_nsec = now.tv_usec * 1000;
494
495     i_result = pthread_cond_timedwait( &p_condvar->cond, &p_mutex->mutex,
496                                        &timeout );
497
498     if( i_result == ETIMEDOUT )
499     {
500         /* People keep pissing me off with this. --Meuuh */
501         msg_Dbg( p_condvar->p_this,
502                   "thread %u: secret message triggered "
503                   "at %s:%d (%s)", (int)pthread_self(),
504                   psz_file, i_line, strerror(i_result) );
505
506         i_result = pthread_cond_wait( &p_condvar->cond, &p_mutex->mutex );
507     }
508
509 #   else
510     i_result = pthread_cond_wait( &p_condvar->cond, &p_mutex->mutex );
511 #   endif
512
513     if ( i_result )
514     {
515         i_thread = (int)pthread_self();
516         psz_error = strerror(i_result);
517     }
518
519 #elif defined( HAVE_CTHREADS_H )
520     condition_wait( (condition_t)p_condvar, (mutex_t)p_mutex );
521     i_result = 0;
522
523 #endif
524
525     if( i_result )
526     {
527         msg_Err( p_condvar->p_this,
528                  "thread %u: cond_wait failed at %s:%d (%d:%s)",
529                  i_thread, psz_file, i_line, i_result, psz_error );
530     }
531
532     return i_result;
533 }
534
535 /*****************************************************************************
536  * vlc_cond_destroy: destroy a condition
537  *****************************************************************************/
538 #define vlc_cond_destroy( P_COND )                                          \
539     __vlc_cond_destroy( __FILE__, __LINE__, P_COND )
540
541 /*****************************************************************************
542  * vlc_thread_create: create a thread
543  *****************************************************************************/
544 #define vlc_thread_create( P_THIS, PSZ_NAME, FUNC, PRIORITY, WAIT )         \
545     __vlc_thread_create( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PSZ_NAME, (void * ( * ) ( void * ))FUNC, PRIORITY, WAIT )
546
547 /*****************************************************************************
548  * vlc_thread_set_priority: set the priority of the calling thread
549  *****************************************************************************/
550 #define vlc_thread_set_priority( P_THIS, PRIORITY )                         \
551     __vlc_thread_set_priority( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PRIORITY )
552
553 /*****************************************************************************
554  * vlc_thread_ready: tell the parent thread we were successfully spawned
555  *****************************************************************************/
556 #define vlc_thread_ready( P_THIS )                                          \
557     __vlc_thread_ready( VLC_OBJECT(P_THIS) )
558
559 /*****************************************************************************
560  * vlc_thread_join: wait until a thread exits
561  *****************************************************************************/
562 #define vlc_thread_join( P_THIS )                                           \
563     __vlc_thread_join( VLC_OBJECT(P_THIS), __FILE__, __LINE__ )