]> git.sesse.net Git - vlc/blob - src/misc/threads.c
Remove support for GNU Portable Threads
[vlc] / src / misc / threads.c
1 /*****************************************************************************
2  * threads.c : threads implementation for the VideoLAN client
3  *****************************************************************************
4  * Copyright (C) 1999-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
8  *          Samuel Hocevar <sam@zoy.org>
9  *          Gildas Bazin <gbazin@netcourrier.com>
10  *          Clément Sténac
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
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 General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 #include <vlc/vlc.h>
28
29 #include "libvlc.h"
30 #include <assert.h>
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
34
35 #define VLC_THREADS_UNINITIALIZED  0
36 #define VLC_THREADS_PENDING        1
37 #define VLC_THREADS_ERROR          2
38 #define VLC_THREADS_READY          3
39
40 /*****************************************************************************
41  * Global mutex for lazy initialization of the threads system
42  *****************************************************************************/
43 static volatile unsigned i_initializations = 0;
44 static volatile int i_status = VLC_THREADS_UNINITIALIZED;
45 static vlc_object_t *p_root;
46
47 #if defined( ST_INIT_IN_ST_H )
48 #elif defined( UNDER_CE )
49 #elif defined( WIN32 )
50
51 /* following is only available on NT/2000/XP and above */
52 static SIGNALOBJECTANDWAIT pf_SignalObjectAndWait = NULL;
53
54 /*
55 ** On Windows NT/2K/XP we use a slow mutex implementation but which
56 ** allows us to correctly implement condition variables.
57 ** You can also use the faster Win9x implementation but you might
58 ** experience problems with it.
59 */
60 static vlc_bool_t          b_fast_mutex = VLC_FALSE;
61 /*
62 ** On Windows 9x/Me you can use a fast but incorrect condition variables
63 ** implementation (more precisely there is a possibility for a race
64 ** condition to happen).
65 ** However it is possible to use slower alternatives which are more robust.
66 ** Currently you can choose between implementation 0 (which is the
67 ** fastest but slightly incorrect), 1 (default) and 2.
68 */
69 static int i_win9x_cv = 1;
70
71 #elif defined( HAVE_KERNEL_SCHEDULER_H )
72 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
73 static pthread_mutex_t once_mutex = PTHREAD_MUTEX_INITIALIZER;
74 #elif defined( HAVE_CTHREADS_H )
75 #endif
76
77 vlc_threadvar_t msg_context_global_key;
78
79 #ifndef NDEBUG
80 /*****************************************************************************
81  * vlc_threads_error: Report an error from the threading mecanism
82  *****************************************************************************
83  * This is especially useful to debug those errors, as this is a nice symbol
84  * on which you can break.
85  *****************************************************************************/
86 void vlc_threads_error( vlc_object_t *p_this )
87 {
88      msg_Err( p_this, "Error detected. Put a breakpoint in '%s' to debug.",
89             __func__ );
90 }
91 #endif
92
93 /*****************************************************************************
94  * vlc_threads_init: initialize threads system
95  *****************************************************************************
96  * This function requires lazy initialization of a global lock in order to
97  * keep the library really thread-safe. Some architectures don't support this
98  * and thus do not guarantee the complete reentrancy.
99  *****************************************************************************/
100 int __vlc_threads_init( vlc_object_t *p_this )
101 {
102     libvlc_global_data_t *p_libvlc_global = (libvlc_global_data_t *)p_this;
103     int i_ret = VLC_SUCCESS;
104
105     /* If we have lazy mutex initialization, use it. Otherwise, we just
106      * hope nothing wrong happens. */
107 #if defined( ST_INIT_IN_ST_H )
108 #elif defined( UNDER_CE )
109 #elif defined( WIN32 )
110     if( IsDebuggerPresent() )
111     {
112         /* SignalObjectAndWait() is problematic under a debugger */
113         b_fast_mutex = VLC_TRUE;
114         i_win9x_cv = 1;
115     }
116 #elif defined( HAVE_KERNEL_SCHEDULER_H )
117 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
118     pthread_mutex_lock( &once_mutex );
119 #elif defined( HAVE_CTHREADS_H )
120 #endif
121
122     if( i_status == VLC_THREADS_UNINITIALIZED )
123     {
124         i_status = VLC_THREADS_PENDING;
125
126         /* We should be safe now. Do all the initialization stuff we want. */
127         p_libvlc_global->b_ready = VLC_FALSE;
128
129 #if defined( ST_INIT_IN_ST_H )
130         i_ret = st_init();
131
132 #elif defined( UNDER_CE )
133         /* Nothing to initialize */
134
135 #elif defined( WIN32 )
136         /* Dynamically get the address of SignalObjectAndWait */
137         if( GetVersion() < 0x80000000 )
138         {
139             HINSTANCE hInstLib;
140
141             /* We are running on NT/2K/XP, we can use SignalObjectAndWait */
142             hInstLib = LoadLibrary( "kernel32" );
143             if( hInstLib )
144             {
145                 pf_SignalObjectAndWait =
146                     (SIGNALOBJECTANDWAIT)GetProcAddress( hInstLib,
147                                                      "SignalObjectAndWait" );
148             }
149         }
150
151 #elif defined( HAVE_KERNEL_SCHEDULER_H )
152 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
153 #elif defined( HAVE_CTHREADS_H )
154 #endif
155
156         p_root = vlc_object_create( p_libvlc_global, VLC_OBJECT_GLOBAL );
157         if( p_root == NULL )
158             i_ret = VLC_ENOMEM;
159
160         if( i_ret )
161         {
162             i_status = VLC_THREADS_ERROR;
163         }
164         else
165         {
166             i_initializations++;
167             i_status = VLC_THREADS_READY;
168         }
169
170         vlc_threadvar_create( p_root, &msg_context_global_key );
171     }
172     else
173     {
174         /* Just increment the initialization count */
175         i_initializations++;
176     }
177
178     /* If we have lazy mutex initialization support, unlock the mutex;
179      * otherwize, do a naive wait loop. */
180 #if defined( ST_INIT_IN_ST_H )
181     while( i_status == VLC_THREADS_PENDING ) msleep( THREAD_SLEEP );
182 #elif defined( UNDER_CE )
183     while( i_status == VLC_THREADS_PENDING ) msleep( THREAD_SLEEP );
184 #elif defined( WIN32 )
185     while( i_status == VLC_THREADS_PENDING ) msleep( THREAD_SLEEP );
186 #elif defined( HAVE_KERNEL_SCHEDULER_H )
187     while( i_status == VLC_THREADS_PENDING ) msleep( THREAD_SLEEP );
188 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
189     pthread_mutex_unlock( &once_mutex );
190 #elif defined( HAVE_CTHREADS_H )
191     while( i_status == VLC_THREADS_PENDING ) msleep( THREAD_SLEEP );
192 #endif
193
194     if( i_status != VLC_THREADS_READY )
195     {
196         return VLC_ETHREAD;
197     }
198
199     return i_ret;
200 }
201
202 /*****************************************************************************
203  * vlc_threads_end: stop threads system
204  *****************************************************************************
205  * FIXME: This function is far from being threadsafe.
206  *****************************************************************************/
207 int __vlc_threads_end( vlc_object_t *p_this )
208 {
209     (void)p_this;
210 #if defined( ST_INIT_IN_ST_H )
211 #elif defined( UNDER_CE )
212 #elif defined( WIN32 )
213 #elif defined( HAVE_KERNEL_SCHEDULER_H )
214 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
215     pthread_mutex_lock( &once_mutex );
216 #elif defined( HAVE_CTHREADS_H )
217 #endif
218
219     if( i_initializations == 0 )
220         return VLC_EGENERIC;
221
222     i_initializations--;
223     if( i_initializations == 0 )
224     {
225         i_status = VLC_THREADS_UNINITIALIZED;
226         vlc_object_destroy( p_root );
227     }
228
229 #if defined( ST_INIT_IN_ST_H )
230 #elif defined( UNDER_CE )
231 #elif defined( WIN32 )
232 #elif defined( HAVE_KERNEL_SCHEDULER_H )
233 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
234     pthread_mutex_unlock( &once_mutex );
235 #elif defined( HAVE_CTHREADS_H )
236 #endif
237     return VLC_SUCCESS;
238 }
239
240 /*****************************************************************************
241  * vlc_mutex_init: initialize a mutex
242  *****************************************************************************/
243 int __vlc_mutex_init( vlc_object_t *p_this, vlc_mutex_t *p_mutex )
244 {
245     assert( p_this );
246     p_mutex->p_this = p_this;
247
248 #if defined( ST_INIT_IN_ST_H )
249     p_mutex->mutex = st_mutex_new();
250     return ( p_mutex->mutex == NULL ) ? errno : 0;
251
252 #elif defined( UNDER_CE )
253     InitializeCriticalSection( &p_mutex->csection );
254     return 0;
255
256 #elif defined( WIN32 )
257     /* We use mutexes on WinNT/2K/XP because we can use the SignalObjectAndWait
258      * function and have a 100% correct vlc_cond_wait() implementation.
259      * As this function is not available on Win9x, we can use the faster
260      * CriticalSections */
261     if( pf_SignalObjectAndWait && !b_fast_mutex )
262     {
263         /* We are running on NT/2K/XP, we can use SignalObjectAndWait */
264         p_mutex->mutex = CreateMutex( 0, FALSE, 0 );
265         return ( p_mutex->mutex != NULL ? 0 : 1 );
266     }
267     else
268     {
269         p_mutex->mutex = NULL;
270         InitializeCriticalSection( &p_mutex->csection );
271         return 0;
272     }
273
274 #elif defined( HAVE_KERNEL_SCHEDULER_H )
275     /* check the arguments and whether it's already been initialized */
276     if( p_mutex == NULL )
277     {
278         return B_BAD_VALUE;
279     }
280
281     if( p_mutex->init == 9999 )
282     {
283         return EALREADY;
284     }
285
286     p_mutex->lock = create_sem( 1, "BeMutex" );
287     if( p_mutex->lock < B_NO_ERROR )
288     {
289         return( -1 );
290     }
291
292     p_mutex->init = 9999;
293     return B_OK;
294
295 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
296 # if defined(DEBUG)
297     {
298         /* Create error-checking mutex to detect problems more easily. */
299         pthread_mutexattr_t attr;
300         int                 i_result;
301
302         pthread_mutexattr_init( &attr );
303 #   if defined(SYS_LINUX)
304         pthread_mutexattr_setkind_np( &attr, PTHREAD_MUTEX_ERRORCHECK_NP );
305 #   else
306         pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_ERRORCHECK );
307 #   endif
308
309         i_result = pthread_mutex_init( &p_mutex->mutex, &attr );
310         pthread_mutexattr_destroy( &attr );
311         return( i_result );
312     }
313 # endif
314     return pthread_mutex_init( &p_mutex->mutex, NULL );
315
316 #elif defined( HAVE_CTHREADS_H )
317     mutex_init( p_mutex );
318     return 0;
319
320 #endif
321 }
322
323 /*****************************************************************************
324  * vlc_mutex_init: initialize a recursive mutex (Do not use)
325  *****************************************************************************/
326 int __vlc_mutex_init_recursive( vlc_object_t *p_this, vlc_mutex_t *p_mutex )
327 {
328 #if defined( WIN32 )
329     /* Create mutex returns a recursive mutex */
330     p_mutex->mutex = CreateMutex( 0, FALSE, 0 );
331     return ( p_mutex->mutex != NULL ? 0 : 1 );
332 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
333     pthread_mutexattr_t attr;
334     int                 i_result;
335
336     pthread_mutexattr_init( &attr );
337 # if defined(DEBUG)
338     /* Create error-checking mutex to detect problems more easily. */
339 #   if defined(SYS_LINUX)
340     pthread_mutexattr_setkind_np( &attr, PTHREAD_MUTEX_ERRORCHECK_NP );
341 #   else
342     pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_ERRORCHECK );
343 #   endif
344 # endif
345     pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
346     i_result = pthread_mutex_init( &p_mutex->mutex, &attr );
347     pthread_mutexattr_destroy( &attr );
348     return( i_result );
349 #else
350     msg_Err(p_this, "no recursive mutex found. Falling back to regular mutex.\n"
351                     "Expect hangs\n")
352     return __vlc_mutex_init( p_this, p_mutex );
353 #endif
354 }
355
356
357 /*****************************************************************************
358  * vlc_mutex_destroy: destroy a mutex, inner version
359  *****************************************************************************/
360 int __vlc_mutex_destroy( const char * psz_file, int i_line, vlc_mutex_t *p_mutex )
361 {
362     int i_result;
363     /* In case of error : */
364     int i_thread = -1;
365
366 #if defined( ST_INIT_IN_ST_H )
367     i_result = st_mutex_destroy( p_mutex->mutex );
368
369 #elif defined( UNDER_CE )
370     DeleteCriticalSection( &p_mutex->csection );
371     return 0;
372
373 #elif defined( WIN32 )
374     if( p_mutex->mutex )
375     {
376         CloseHandle( p_mutex->mutex );
377     }
378     else
379     {
380         DeleteCriticalSection( &p_mutex->csection );
381     }
382     return 0;
383
384 #elif defined( HAVE_KERNEL_SCHEDULER_H )
385     if( p_mutex->init == 9999 )
386     {
387         delete_sem( p_mutex->lock );
388     }
389
390     p_mutex->init = 0;
391     return B_OK;
392
393 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
394     i_result = pthread_mutex_destroy( &p_mutex->mutex );
395     if( i_result )
396     {
397         i_thread = CAST_PTHREAD_TO_INT(pthread_self());
398         errno = i_result;
399     }
400
401 #elif defined( HAVE_CTHREADS_H )
402     return 0;
403
404 #endif
405
406     if( i_result )
407     {
408         msg_Err( p_mutex->p_this,
409                  "thread %d: mutex_destroy failed at %s:%d (%d:%m)",
410                  i_thread, psz_file, i_line, i_result );
411         vlc_threads_error( p_mutex->p_this );
412     }
413     return i_result;
414 }
415
416 /*****************************************************************************
417  * vlc_cond_init: initialize a condition
418  *****************************************************************************/
419 int __vlc_cond_init( vlc_object_t *p_this, vlc_cond_t *p_condvar )
420 {
421     p_condvar->p_this = p_this;
422
423 #if defined( ST_INIT_IN_ST_H )
424     p_condvar->cond = st_cond_new();
425     return ( p_condvar->cond == NULL ) ? errno : 0;
426
427 #elif defined( UNDER_CE )
428     /* Initialize counter */
429     p_condvar->i_waiting_threads = 0;
430
431     /* Create an auto-reset event. */
432     p_condvar->event = CreateEvent( NULL,   /* no security */
433                                     FALSE,  /* auto-reset event */
434                                     FALSE,  /* start non-signaled */
435                                     NULL ); /* unnamed */
436     return !p_condvar->event;
437
438 #elif defined( WIN32 )
439     /* Initialize counter */
440     p_condvar->i_waiting_threads = 0;
441
442     /* Misc init */
443     p_condvar->i_win9x_cv = i_win9x_cv;
444     p_condvar->SignalObjectAndWait = pf_SignalObjectAndWait;
445
446     if( (p_condvar->SignalObjectAndWait && !b_fast_mutex)
447         || p_condvar->i_win9x_cv == 0 )
448     {
449         /* Create an auto-reset event. */
450         p_condvar->event = CreateEvent( NULL,   /* no security */
451                                         FALSE,  /* auto-reset event */
452                                         FALSE,  /* start non-signaled */
453                                         NULL ); /* unnamed */
454
455         p_condvar->semaphore = NULL;
456         return !p_condvar->event;
457     }
458     else
459     {
460         p_condvar->semaphore = CreateSemaphore( NULL,       /* no security */
461                                                 0,          /* initial count */
462                                                 0x7fffffff, /* max count */
463                                                 NULL );     /* unnamed */
464
465         if( p_condvar->i_win9x_cv == 1 )
466             /* Create a manual-reset event initially signaled. */
467             p_condvar->event = CreateEvent( NULL, TRUE, TRUE, NULL );
468         else
469             /* Create a auto-reset event. */
470             p_condvar->event = CreateEvent( NULL, FALSE, FALSE, NULL );
471
472         InitializeCriticalSection( &p_condvar->csection );
473
474         return !p_condvar->semaphore || !p_condvar->event;
475     }
476
477 #elif defined( HAVE_KERNEL_SCHEDULER_H )
478     if( !p_condvar )
479     {
480         return B_BAD_VALUE;
481     }
482
483     if( p_condvar->init == 9999 )
484     {
485         return EALREADY;
486     }
487
488     p_condvar->thread = -1;
489     p_condvar->init = 9999;
490     return 0;
491
492 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
493     pthread_condattr_t attr;
494     int ret;
495
496     ret = pthread_condattr_init (&attr);
497     if (ret)
498         return ret;
499
500 # if !defined (_POSIX_CLOCK_SELECTION)
501    /* Fairly outdated POSIX support (that was defined in 2001) */
502 #  define _POSIX_CLOCK_SELECTION (-1)
503 # endif
504 # if (_POSIX_CLOCK_SELECTION >= 0)
505     /* NOTE: This must be the same clock as the one in mtime.c */
506     pthread_condattr_setclock (&attr, CLOCK_MONOTONIC);
507 # endif
508
509     ret = pthread_cond_init (&p_condvar->cond, &attr);
510     pthread_condattr_destroy (&attr);
511     return ret;
512
513 #elif defined( HAVE_CTHREADS_H )
514     /* condition_init() */
515     spin_lock_init( &p_condvar->lock );
516     cthread_queue_init( &p_condvar->queue );
517     p_condvar->name = 0;
518     p_condvar->implications = 0;
519
520     return 0;
521
522 #endif
523 }
524
525 /*****************************************************************************
526  * vlc_cond_destroy: destroy a condition, inner version
527  *****************************************************************************/
528 int __vlc_cond_destroy( const char * psz_file, int i_line, vlc_cond_t *p_condvar )
529 {
530     int i_result;
531     /* In case of error : */
532     int i_thread = -1;
533
534 #if defined( ST_INIT_IN_ST_H )
535     i_result = st_cond_destroy( p_condvar->cond );
536
537 #elif defined( UNDER_CE )
538     i_result = !CloseHandle( p_condvar->event );
539
540 #elif defined( WIN32 )
541     if( !p_condvar->semaphore )
542         i_result = !CloseHandle( p_condvar->event );
543     else
544         i_result = !CloseHandle( p_condvar->event )
545           || !CloseHandle( p_condvar->semaphore );
546
547     if( p_condvar->semaphore != NULL )
548         DeleteCriticalSection( &p_condvar->csection );
549
550 #elif defined( HAVE_KERNEL_SCHEDULER_H )
551     p_condvar->init = 0;
552     return 0;
553
554 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
555     i_result = pthread_cond_destroy( &p_condvar->cond );
556     if( i_result )
557     {
558         i_thread = CAST_PTHREAD_TO_INT(pthread_self());
559         errno = i_result;
560     }
561
562 #elif defined( HAVE_CTHREADS_H )
563     return 0;
564
565 #endif
566
567     if( i_result )
568     {
569         msg_Err( p_condvar->p_this,
570                  "thread %d: cond_destroy failed at %s:%d (%d:%m)",
571                  i_thread, psz_file, i_line, i_result );
572         vlc_threads_error( p_condvar->p_this );
573     }
574     return i_result;
575 }
576
577 /*****************************************************************************
578  * vlc_tls_create: create a thread-local variable
579  *****************************************************************************/
580 int __vlc_threadvar_create( vlc_object_t *p_this, vlc_threadvar_t *p_tls )
581 {
582     int i_ret = -1;
583     (void)p_this;
584
585 #if defined( HAVE_KERNEL_SCHEDULER_H )
586     msg_Err( p_this, "TLS not implemented" );
587     i_ret VLC_EGENERIC;
588 #elif defined( ST_INIT_IN_ST_H )
589     i_ret = st_key_create( &p_tls->handle, NULL );
590 #elif defined( UNDER_CE ) || defined( WIN32 )
591 #elif defined( WIN32 )
592     p_tls->handle = TlsAlloc();
593     i_ret = !( p_tls->handle == 0xFFFFFFFF );
594
595 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
596     i_ret =  pthread_key_create( &p_tls->handle, NULL );
597 #elif defined( HAVE_CTHREADS_H )
598     i_ret = cthread_keycreate( &p_tls-handle );
599 #endif
600     return i_ret;
601 }
602
603 /*****************************************************************************
604  * vlc_thread_create: create a thread, inner version
605  *****************************************************************************
606  * Note that i_priority is only taken into account on platforms supporting
607  * userland real-time priority threads.
608  *****************************************************************************/
609 int __vlc_thread_create( vlc_object_t *p_this, const char * psz_file, int i_line,
610                          const char *psz_name, void * ( *func ) ( void * ),
611                          int i_priority, vlc_bool_t b_wait )
612 {
613     int i_ret;
614     void *p_data = (void *)p_this;
615     vlc_object_internals_t *p_priv = p_this->p_internals;
616
617     vlc_mutex_lock( &p_this->object_lock );
618
619 #if defined( ST_INIT_IN_ST_H )
620     p_priv->thread_id = st_thread_create( func, p_data, 1, 0 );
621     i_ret = 0;
622
623 #elif defined( WIN32 ) || defined( UNDER_CE )
624     {
625         /* When using the MSVCRT C library you have to use the _beginthreadex
626          * function instead of CreateThread, otherwise you'll end up with
627          * memory leaks and the signal functions not working (see Microsoft
628          * Knowledge Base, article 104641) */
629 #if defined( UNDER_CE )
630         DWORD  threadId;
631         HANDLE hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)func,
632                                       (LPVOID)p_data, CREATE_SUSPENDED,
633                       &threadId );
634 #else
635         unsigned threadId;
636         uintptr_t hThread = _beginthreadex( NULL, 0,
637                         (LPTHREAD_START_ROUTINE)func,
638                                             (void*)p_data, CREATE_SUSPENDED,
639                         &threadId );
640 #endif
641         p_priv->thread_id.id = (DWORD)threadId;
642         p_priv->thread_id.hThread = (HANDLE)hThread;
643     ResumeThread((HANDLE)hThread);
644     }
645
646     i_ret = ( p_priv->thread_id.hThread ? 0 : 1 );
647
648     if( i_ret && i_priority )
649     {
650         if( !SetThreadPriority(p_priv->thread_id.hThread, i_priority) )
651         {
652             msg_Warn( p_this, "couldn't set a faster priority" );
653             i_priority = 0;
654         }
655     }
656
657 #elif defined( HAVE_KERNEL_SCHEDULER_H )
658     p_priv->thread_id = spawn_thread( (thread_func)func, psz_name,
659                                       i_priority, p_data );
660     i_ret = resume_thread( p_priv->thread_id );
661
662 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
663     i_ret = pthread_create( &p_priv->thread_id, NULL, func, p_data );
664
665 #ifndef __APPLE__
666     if( config_GetInt( p_this, "rt-priority" ) )
667 #endif
668     {
669         int i_error, i_policy;
670         struct sched_param param;
671
672         memset( &param, 0, sizeof(struct sched_param) );
673         if( config_GetType( p_this, "rt-offset" ) )
674         {
675             i_priority += config_GetInt( p_this, "rt-offset" );
676         }
677         if( i_priority <= 0 )
678         {
679             param.sched_priority = (-1) * i_priority;
680             i_policy = SCHED_OTHER;
681         }
682         else
683         {
684             param.sched_priority = i_priority;
685             i_policy = SCHED_RR;
686         }
687         if( (i_error = pthread_setschedparam( p_priv->thread_id,
688                                                i_policy, &param )) )
689         {
690             errno = i_error;
691             msg_Warn( p_this, "couldn't set thread priority (%s:%d): %m",
692                       psz_file, i_line );
693             i_priority = 0;
694         }
695     }
696 #ifndef __APPLE__
697     else
698     {
699         i_priority = 0;
700     }
701 #endif
702
703 #elif defined( HAVE_CTHREADS_H )
704     p_priv->thread_id = cthread_fork( (cthread_fn_t)func, (any_t)p_data );
705     i_ret = 0;
706
707 #endif
708
709     if( i_ret == 0 )
710     {
711         if( b_wait )
712         {
713             msg_Dbg( p_this, "waiting for thread completion" );
714             vlc_object_wait( p_this );
715         }
716
717         p_priv->b_thread = VLC_TRUE;
718
719 #if defined( WIN32 ) || defined( UNDER_CE )
720         msg_Dbg( p_this, "thread %u (%s) created at priority %d (%s:%d)",
721                  (unsigned int)p_priv->thread_id.id, psz_name,
722          i_priority, psz_file, i_line );
723 #else
724         msg_Dbg( p_this, "thread %u (%s) created at priority %d (%s:%d)",
725                  (unsigned int)p_priv->thread_id, psz_name, i_priority,
726                  psz_file, i_line );
727 #endif
728
729
730         vlc_mutex_unlock( &p_this->object_lock );
731     }
732     else
733     {
734         errno = i_ret;
735         msg_Err( p_this, "%s thread could not be created at %s:%d (%m)",
736                          psz_name, psz_file, i_line );
737         vlc_threads_error( p_this );
738         vlc_mutex_unlock( &p_this->object_lock );
739     }
740
741     return i_ret;
742 }
743
744 /*****************************************************************************
745  * vlc_thread_set_priority: set the priority of the current thread when we
746  * couldn't set it in vlc_thread_create (for instance for the main thread)
747  *****************************************************************************/
748 int __vlc_thread_set_priority( vlc_object_t *p_this, const char * psz_file,
749                                int i_line, int i_priority )
750 {
751     vlc_object_internals_t *p_priv = p_this->p_internals;
752 #if defined( ST_INIT_IN_ST_H )
753 #elif defined( WIN32 ) || defined( UNDER_CE )
754     if( !p_priv->thread_id.hThread )
755         p_priv->thread_id.hThread = GetCurrentThread();
756     if( !SetThreadPriority(p_priv->thread_id.hThread, i_priority) )
757     {
758         msg_Warn( p_this, "couldn't set a faster priority" );
759         return 1;
760     }
761
762 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
763 # ifndef __APPLE__
764     if( config_GetInt( p_this, "rt-priority" ) > 0 )
765 # endif
766     {
767         int i_error, i_policy;
768         struct sched_param param;
769
770         memset( &param, 0, sizeof(struct sched_param) );
771         if( config_GetType( p_this, "rt-offset" ) )
772         {
773             i_priority += config_GetInt( p_this, "rt-offset" );
774         }
775         if( i_priority <= 0 )
776         {
777             param.sched_priority = (-1) * i_priority;
778             i_policy = SCHED_OTHER;
779         }
780         else
781         {
782             param.sched_priority = i_priority;
783             i_policy = SCHED_RR;
784         }
785         if( !p_priv->thread_id )
786             p_priv->thread_id = pthread_self();
787         if( (i_error = pthread_setschedparam( p_priv->thread_id,
788                                                i_policy, &param )) )
789         {
790             errno = i_error;
791             msg_Warn( p_this, "couldn't set thread priority (%s:%d): %m",
792                       psz_file, i_line );
793             i_priority = 0;
794         }
795     }
796 #endif
797
798     return 0;
799 }
800
801 /*****************************************************************************
802  * vlc_thread_ready: tell the parent thread we were successfully spawned
803  *****************************************************************************/
804 void __vlc_thread_ready( vlc_object_t *p_this )
805 {
806     vlc_object_signal( p_this );
807 }
808
809 /*****************************************************************************
810  * vlc_thread_join: wait until a thread exits, inner version
811  *****************************************************************************/
812 void __vlc_thread_join( vlc_object_t *p_this, const char * psz_file, int i_line )
813 {
814     vlc_object_internals_t *p_priv = p_this->p_internals;
815
816 #if defined( UNDER_CE ) || defined( WIN32 )
817     HMODULE hmodule;
818     BOOL (WINAPI *OurGetThreadTimes)( HANDLE, FILETIME*, FILETIME*,
819                                       FILETIME*, FILETIME* );
820     FILETIME create_ft, exit_ft, kernel_ft, user_ft;
821     int64_t real_time, kernel_time, user_time;
822     HANDLE hThread;
823  
824     /*
825     ** object will close its thread handle when destroyed, duplicate it here
826     ** to be on the safe side
827     */
828     if( ! DuplicateHandle(GetCurrentProcess(),
829             p_priv->thread_id.hThread,
830             GetCurrentProcess(),
831             &hThread,
832             0,
833             FALSE,
834             DUPLICATE_SAME_ACCESS) )
835     {
836         msg_Err( p_this, "thread_join(%u) failed at %s:%d (%s)",
837                          (unsigned int)p_priv->thread_id.id,
838              psz_file, i_line, GetLastError() );
839         vlc_threads_error( p_this );
840         p_priv->b_thread = VLC_FALSE;
841         return;
842     }
843
844     WaitForSingleObject( hThread, INFINITE );
845
846     msg_Dbg( p_this, "thread %u joined (%s:%d)",
847              (unsigned int)p_priv->thread_id.id,
848              psz_file, i_line );
849 #if defined( UNDER_CE )
850     hmodule = GetModuleHandle( _T("COREDLL") );
851 #else
852     hmodule = GetModuleHandle( _T("KERNEL32") );
853 #endif
854     OurGetThreadTimes = (BOOL (WINAPI*)( HANDLE, FILETIME*, FILETIME*,
855                                          FILETIME*, FILETIME* ))
856         GetProcAddress( hmodule, _T("GetThreadTimes") );
857
858     if( OurGetThreadTimes &&
859         OurGetThreadTimes( hThread,
860                            &create_ft, &exit_ft, &kernel_ft, &user_ft ) )
861     {
862         real_time =
863           ((((int64_t)exit_ft.dwHighDateTime)<<32)| exit_ft.dwLowDateTime) -
864           ((((int64_t)create_ft.dwHighDateTime)<<32)| create_ft.dwLowDateTime);
865         real_time /= 10;
866
867         kernel_time =
868           ((((int64_t)kernel_ft.dwHighDateTime)<<32)|
869            kernel_ft.dwLowDateTime) / 10;
870
871         user_time =
872           ((((int64_t)user_ft.dwHighDateTime)<<32)|
873            user_ft.dwLowDateTime) / 10;
874
875         msg_Dbg( p_this, "thread times: "
876                  "real "I64Fd"m%fs, kernel "I64Fd"m%fs, user "I64Fd"m%fs",
877                  real_time/60/1000000,
878                  (double)((real_time%(60*1000000))/1000000.0),
879                  kernel_time/60/1000000,
880                  (double)((kernel_time%(60*1000000))/1000000.0),
881                  user_time/60/1000000,
882                  (double)((user_time%(60*1000000))/1000000.0) );
883     }
884     CloseHandle( hThread );
885
886 #else /* !defined(WIN32) */
887
888     int i_ret = 0;
889
890 #if defined( ST_INIT_IN_ST_H )
891     i_ret = st_thread_join( p_priv->thread_id, NULL );
892
893 #elif defined( HAVE_KERNEL_SCHEDULER_H )
894     int32_t exit_value;
895     i_ret = (B_OK == wait_for_thread( p_priv->thread_id, &exit_value ));
896
897 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
898     i_ret = pthread_join( p_priv->thread_id, NULL );
899
900 #elif defined( HAVE_CTHREADS_H )
901     cthread_join( p_priv->thread_id );
902     i_ret = 1;
903
904 #endif
905
906     if( i_ret )
907     {
908         errno = i_ret;
909         msg_Err( p_this, "thread_join(%u) failed at %s:%d (%m)",
910                          (unsigned int)p_priv->thread_id, psz_file, i_line );
911         vlc_threads_error( p_this );
912     }
913     else
914     {
915         msg_Dbg( p_this, "thread %u joined (%s:%d)",
916                          (unsigned int)p_priv->thread_id, psz_file, i_line );
917     }
918
919 #endif
920
921     p_priv->b_thread = VLC_FALSE;
922 }
923