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