]> git.sesse.net Git - vlc/blob - include/threads.h
D�but du portage BeOS. Beaucoup de fuchiers ont �t� modifi� car il a fallu
[vlc] / include / threads.h
1 /*****************************************************************************
2  * threads.h : thread implementation for VideoLAN client
3  * This header is supposed to provide a portable threads implementation.
4  * Currently, it is a wrapper to either the POSIX pthreads library, or
5  * the Mach cthreads (for the GNU/Hurd).
6  *****************************************************************************
7  * Copyright (C) 1999, 2000 VideoLAN
8  *
9  * Authors:
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public
22  * License along with this program; if not, write to the
23  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24  * Boston, MA 02111-1307, USA.
25  *****************************************************************************/
26
27
28 #ifdef SYS_GNU
29 #include <cthreads.h>
30 #endif
31
32 #ifdef SYS_BEOS
33 #include <kernel/OS.h>
34 #include <kernel/scheduler.h>
35 #endif
36
37 #if defined(SYS_LINUX) || defined(SYS_BSD)
38 #include <pthread.h>
39 #endif
40
41 /*****************************************************************************
42  * Constants
43  *****************************************************************************
44  * These constants are used by all threads in *_CreateThread() and
45  * *_DestroyThreads() functions. Since those calls are non-blocking, an integer
46  * value is used as a shared flag to represent the status of the thread.
47  *****************************************************************************/
48
49 /* Void status - this value can be used to be sure, in an array of recorded
50  * threads, that no operation is currently in progress on the concerned thread */
51 #define THREAD_NOP          0                            /* nothing happened */
52
53 /* Creation status */
54 #define THREAD_CREATE       10                     /* thread is initializing */
55 #define THREAD_START        11                          /* thread has forked */
56 #define THREAD_READY        19                            /* thread is ready */
57
58 /* Destructions status */
59 #define THREAD_DESTROY      20            /* destruction order has been sent */
60 #define THREAD_END          21        /* destruction order has been received */
61 #define THREAD_OVER         29             /* thread does not exist any more */
62
63 /* Error status */
64 #define THREAD_ERROR        30                           /* an error occured */
65 #define THREAD_FATAL        31  /* an fatal error occured - program must end */
66
67 /*****************************************************************************
68  * Types definition
69  *****************************************************************************/
70
71 #ifdef SYS_GNU
72
73 typedef cthread_t        vlc_thread_t;
74
75 /* those structs are the ones defined in /include/cthreads.h but we need
76  *  * to handle *foo where foo is a mutex_t */
77 typedef struct s_mutex {
78     spin_lock_t held;
79     spin_lock_t lock;
80     char *name;
81     struct cthread_queue queue;
82 } vlc_mutex_t;
83
84 typedef struct s_condition {
85     spin_lock_t lock;
86     struct cthread_queue queue;
87     char *name;
88     struct cond_imp *implications;
89 } vlc_cond_t;
90
91 #endif /* SYS_GNU */
92
93 #ifdef SYS_BEOS
94
95 typedef thread_id vlc_thread_t;
96
97 typedef struct
98 {
99     int32           init;
100     sem_id          lock;
101     thread_id       owner;
102 } vlc_mutex_t;
103
104 typedef struct
105 {
106     int32           init;
107     sem_id          sem;
108     sem_id          handshakeSem;
109     sem_id          signalSem;
110     volatile int32  nw;
111     volatile int32  ns;
112 } vlc_cond_t;
113
114 #endif /* SYS_BEOS */
115
116 #if defined(SYS_LINUX) || defined(SYS_BSD)
117
118 typedef pthread_t        vlc_thread_t;
119 typedef pthread_mutex_t  vlc_mutex_t;
120 typedef pthread_cond_t   vlc_cond_t;
121
122 #endif /* SYS_LINUX || SYS_BSD */
123
124 typedef void *(*vlc_thread_func_t)(void *p_data);
125
126 /*****************************************************************************
127  * Prototypes
128  *****************************************************************************/
129
130 static __inline__ int  vlc_thread_create( vlc_thread_t *p_thread, char *psz_name,
131                                           vlc_thread_func_t func, void *p_data );
132 static __inline__ void vlc_thread_exit  ( void );
133 static __inline__ void vlc_thread_join  ( vlc_thread_t thread );
134
135 static __inline__ int  vlc_mutex_init   ( vlc_mutex_t *p_mutex );
136 static __inline__ int  vlc_mutex_lock   ( vlc_mutex_t *p_mutex );
137 static __inline__ int  vlc_mutex_unlock ( vlc_mutex_t *p_mutex );
138
139 static __inline__ int  vlc_cond_init    ( vlc_cond_t *p_condvar );
140 static __inline__ int  vlc_cond_signal  ( vlc_cond_t *p_condvar );
141 static __inline__ int  vlc_cond_wait    ( vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex );
142
143 #if 0
144 static _inline__ int    vlc_cond_timedwait   ( vlc_cond_t * condvar, vlc_mutex_t * mutex,
145                               mtime_t absoute_timeout_time );
146 #endif
147
148 /*****************************************************************************
149  * vlc_thread_create: create a thread
150  *****************************************************************************/
151 static __inline__ int vlc_thread_create( vlc_thread_t *p_thread,
152                                          char *psz_name, vlc_thread_func_t func,
153                                          void *p_data)
154 {
155 #ifdef SYS_GNU
156     *p_thread = cthread_fork( (cthread_fn_t)func, (any_t)p_data );
157     return( 0 );
158 #endif
159
160 #ifdef SYS_BEOS
161     *p_thread = spawn_thread( (thread_func)func, psz_name, B_NORMAL_PRIORITY, p_data );
162     return resume_thread( *p_thread );
163 #endif
164
165 #if defined(SYS_LINUX) || defined(SYS_BSD)
166     return pthread_create( p_thread, NULL, func, p_data );
167 #endif
168 }
169
170 /*****************************************************************************
171  * vlc_thread_exit: terminate a thread
172  *****************************************************************************/
173 static __inline__ void vlc_thread_exit( void )
174 {
175 #ifdef SYS_GNU
176     int result;
177     cthread_exit( &result );
178 #endif
179
180 #ifdef SYS_BEOS
181     exit_thread( 0 );
182 #endif
183
184 #if defined(SYS_LINUX) || defined(SYS_BSD)      
185     pthread_exit( 0 );
186 #endif
187 }
188
189 /*****************************************************************************
190  * vlc_thread_join: wait until a thread exits
191  *****************************************************************************/
192 static __inline__ void vlc_thread_join( vlc_thread_t thread )
193 {
194 #ifdef SYS_GNU
195     cthread_join( thread );
196 #endif
197
198 #ifdef SYS_BEOS
199     int32 exit_value;   
200     wait_for_thread( thread, &exit_value );
201 #endif
202
203 #if defined(SYS_LINUX) || defined(SYS_BSD)      
204     pthread_join( thread, NULL );
205 #endif
206 }
207
208 #ifdef SYS_BEOS
209 /* lazy_init_mutex */
210 static __inline__ void lazy_init_mutex(vlc_mutex_t* p_mutex)
211 {
212     int32 v = atomic_or( &p_mutex->init, 1 );
213     if( 2000 == v ) // we're the first, so do the init
214     {
215         vlc_mutex_init( p_mutex );
216     }
217     else // we're not the first, so wait until the init is finished
218     {
219         while( p_mutex->init != 9999 ) snooze( 10000 );
220     }
221 }
222 #endif
223
224 /*****************************************************************************
225  * vlc_mutex_init: initialize a mutex
226  *****************************************************************************/
227 static __inline__ int vlc_mutex_init( vlc_mutex_t *p_mutex )
228 {
229 #ifdef SYS_GNU
230     mutex_init( p_mutex );
231     return( 0 );
232 #endif
233
234 #ifdef SYS_BEOS
235     // check the arguments and whether it's already been initialized
236     if( !p_mutex ) return B_BAD_VALUE;
237     if( p_mutex->init == 9999 ) return EALREADY;
238
239     p_mutex->lock = create_sem( 1, "BeMutex" );
240     p_mutex->owner = -1;
241     p_mutex->init = 9999;
242     return B_OK;
243 #endif
244
245 #if defined(SYS_LINUX) || defined(SYS_BSD)      
246     return pthread_mutex_init( p_mutex, NULL );
247 #endif
248 }
249
250 /*****************************************************************************
251  * vlc_mutex_lock: lock a mutex
252  *****************************************************************************/
253 static __inline__ int vlc_mutex_lock( vlc_mutex_t *p_mutex )
254 {
255 #ifdef SYS_GNU
256     mutex_lock( p_mutex );
257     return( 0 );
258 #endif
259
260 #ifdef SYS_BEOS
261     status_t err;
262
263     if( !p_mutex ) return B_BAD_VALUE;
264     if( p_mutex->init < 2000 ) return B_NO_INIT;
265     lazy_init_mutex( p_mutex );
266
267     err = acquire_sem( p_mutex->lock );
268     if( !err ) p_mutex->owner = find_thread( NULL );
269     return err;
270 #endif
271
272 #if defined(SYS_LINUX) || defined(SYS_BSD)      
273     return pthread_mutex_lock( p_mutex );
274 #endif
275 }
276
277 /*****************************************************************************
278  * vlc_mutex_unlock: unlock a mutex
279  *****************************************************************************/
280 static __inline__ int vlc_mutex_unlock( vlc_mutex_t *p_mutex )
281 {
282 #ifdef SYS_GNU
283     mutex_unlock( p_mutex );
284     return( 0 );
285 #endif
286
287 #ifdef SYS_BEOS
288     if(! p_mutex) return B_BAD_VALUE;
289     if( p_mutex->init < 2000 ) return B_NO_INIT;
290     lazy_init_mutex( p_mutex );
291
292     if( p_mutex->owner != find_thread(NULL) ) return ENOLCK;
293     p_mutex->owner = -1;
294     release_sem( p_mutex->lock );
295     return B_OK;
296 #endif
297
298 #if defined(SYS_LINUX) || defined(SYS_BSD)      
299     return pthread_mutex_unlock( p_mutex );
300 #endif
301 }
302
303 #ifdef SYS_BEOS
304 /* lazy_init_cond */
305 static __inline__ void lazy_init_cond( vlc_cond_t* p_condvar )
306 {
307     int32 v = atomic_or( &p_condvar->init, 1 );
308     if( 2000 == v ) // we're the first, so do the init
309     {
310         vlc_cond_init( p_condvar );
311     }
312     else // we're not the first, so wait until the init is finished
313     {
314         while( p_condvar->init != 9999 ) snooze( 10000 );
315     }
316 }
317 #endif
318
319 /*****************************************************************************
320  * vlc_cond_init: initialize a condition
321  *****************************************************************************/
322 static __inline__ int vlc_cond_init( vlc_cond_t *p_condvar )
323 {
324 #ifdef SYS_GNU
325     /* condition_init() */
326     spin_lock_init( &p_condvar->lock );
327     cthread_queue_init( &p_condvar->queue );
328     p_condvar->name = 0;
329     p_condvar->implications = 0;
330
331     return( 0 );
332 #endif
333
334 #ifdef SYS_BEOS
335     if( !p_condvar ) return B_BAD_VALUE;
336     if( p_condvar->init == 9999 ) return EALREADY;
337
338     p_condvar->sem = create_sem( 0, "CVSem" );
339     p_condvar->handshakeSem = create_sem( 0, "CVHandshake" );
340     p_condvar->signalSem = create_sem( 1, "CVSignal" );
341     p_condvar->ns = p_condvar->nw = 0;
342     p_condvar->init = 9999;
343     return B_OK;
344 #endif
345
346 #if defined(SYS_LINUX) || defined(SYS_BSD)      
347     return pthread_cond_init( p_condvar, NULL );
348 #endif
349 }
350
351 /*****************************************************************************
352  * vlc_cond_signal: start a thread on condition completion
353  *****************************************************************************/
354 static __inline__ int vlc_cond_signal( vlc_cond_t *p_condvar )
355 {
356 #ifdef SYS_GNU
357     /* condition_signal() */
358     if ( p_condvar->queue.head || p_condvar->implications )
359     {
360         cond_signal( (condition_t)p_condvar );
361     }
362     return( 0 );
363 #endif
364
365 #ifdef SYS_BEOS
366     status_t err = B_OK;
367
368     if( !p_condvar ) return B_BAD_VALUE;
369     if( p_condvar->init < 2000 ) return B_NO_INIT;
370     lazy_init_cond( p_condvar );
371
372     if( acquire_sem(p_condvar->signalSem) == B_INTERRUPTED) return B_INTERRUPTED;
373
374     if( p_condvar->nw > p_condvar->ns )
375     {
376         p_condvar->ns += 1;
377         release_sem( p_condvar->sem );
378         release_sem( p_condvar->signalSem );
379         while( acquire_sem(p_condvar->handshakeSem) == B_INTERRUPTED )
380             { err = B_INTERRUPTED; }
381     }
382     else
383     {
384         release_sem( p_condvar->signalSem );
385     }
386     return err;
387 #endif
388
389 #if defined(SYS_LINUX) || defined(SYS_BSD)      
390     return pthread_cond_signal( p_condvar );
391 #endif
392 }
393
394 /*****************************************************************************
395  * vlc_cond_wait: wait until condition completion
396  *****************************************************************************/
397 static __inline__ int vlc_cond_wait( vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex )
398 {
399 #ifdef SYS_GNU
400     condition_wait( (condition_t)p_condvar, (mutex_t)p_mutex );
401     return( 0 );
402 #endif
403
404 #ifdef SYS_BEOS
405     status_t err;
406
407     if( !p_condvar ) return B_BAD_VALUE;
408     if( !p_mutex ) return B_BAD_VALUE;
409     if( p_condvar->init < 2000 ) return B_NO_INIT;
410     lazy_init_cond( p_condvar );
411
412     if( acquire_sem(p_condvar->signalSem) == B_INTERRUPTED ) return B_INTERRUPTED;
413     p_condvar->nw += 1;
414     release_sem( p_condvar->signalSem );
415
416     vlc_mutex_unlock( p_mutex );
417     err = acquire_sem( p_condvar->sem );
418
419     while( acquire_sem(p_condvar->signalSem) == B_INTERRUPTED)
420         { err = B_INTERRUPTED; }
421     if( p_condvar->ns > 0 )
422     {
423         release_sem( p_condvar->handshakeSem );
424         p_condvar->ns -= 1;
425     }
426     p_condvar->nw -= 1;
427     release_sem( p_condvar->signalSem );
428
429     while( vlc_mutex_lock(p_mutex) == B_INTERRUPTED)
430         { err = B_INTERRUPTED; }
431     return err;
432 #endif
433
434 #if defined(SYS_LINUX) || defined(SYS_BSD)      
435     return pthread_cond_wait( p_condvar, p_mutex );
436 #endif
437 }