vlc_threads_funcs.h 26.8 KB
Newer Older
1
2
3
4
/*****************************************************************************
 * vlc_threads_funcs.h : threads implementation for the VideoLAN client
 * This header provides a portable threads implementation.
 *****************************************************************************
5
 * Copyright (C) 1999-2007 the VideoLAN team
6
 * $Id$
7
8
9
10
11
12
13
14
15
16
 *
 * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
 *          Samuel Hocevar <sam@via.ecp.fr>
 *          Gildas Bazin <gbazin@netcourrier.com>
 *          Christophe Massiot <massiot@via.ecp.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
17
 *
18
19
20
21
22
23
24
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
dionoea's avatar
dionoea committed
25
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26
27
 *****************************************************************************/

zorglub's avatar
zorglub committed
28
29
30
31
#if !defined( __LIBVLC__ )
  #error You are not libvlc or one of its plugins. You cannot include this file
#endif

32
33
34
#ifndef _VLC_THREADFUNCS_H_
#define _VLC_THREADFUNCS_H_

35
36
37
/*****************************************************************************
 * Function definitions
 *****************************************************************************/
38
VLC_EXPORT( void, vlc_threads_error, ( vlc_object_t *) );
39
VLC_EXPORT( int,  __vlc_mutex_init,    ( vlc_object_t *, vlc_mutex_t * ) );
40
VLC_EXPORT( int,  __vlc_mutex_init_recursive, ( vlc_object_t *, vlc_mutex_t * ) );
41
VLC_EXPORT( int,  __vlc_mutex_destroy, ( const char *, int, vlc_mutex_t * ) );
42
VLC_EXPORT( int,  __vlc_cond_init,     ( vlc_object_t *, vlc_cond_t * ) );
43
VLC_EXPORT( int,  __vlc_cond_destroy,  ( const char *, int, vlc_cond_t * ) );
44
VLC_EXPORT( int, __vlc_threadvar_create, (vlc_object_t *, vlc_threadvar_t * ) );
45
46
VLC_EXPORT( int,  __vlc_thread_create, ( vlc_object_t *, const char *, int, const char *, void * ( * ) ( void * ), int, vlc_bool_t ) );
VLC_EXPORT( int,  __vlc_thread_set_priority, ( vlc_object_t *, const char *, int, int ) );
47
VLC_EXPORT( void, __vlc_thread_ready,  ( vlc_object_t * ) );
48
VLC_EXPORT( void, __vlc_thread_join,   ( vlc_object_t *, const char *, int ) );
49

50
51
52
/*****************************************************************************
 * vlc_threads_error: Signalize an error in the threading system
 *****************************************************************************/
53
54
55
#ifdef NDEBUG
# define vlc_threads_error( P_THIS ) (void)0
#endif
56

57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/*****************************************************************************
 * vlc_threads_init: initialize threads system
 *****************************************************************************/
#define vlc_threads_init( P_THIS )                                          \
    __vlc_threads_init( VLC_OBJECT(P_THIS) )

/*****************************************************************************
 * vlc_threads_end: deinitialize threads system
 *****************************************************************************/
#define vlc_threads_end( P_THIS )                                           \
    __vlc_threads_end( VLC_OBJECT(P_THIS) )

/*****************************************************************************
 * vlc_mutex_init: initialize a mutex
 *****************************************************************************/
#define vlc_mutex_init( P_THIS, P_MUTEX )                                   \
    __vlc_mutex_init( VLC_OBJECT(P_THIS), P_MUTEX )

75
76
77
78
79
80
/*****************************************************************************
 * vlc_mutex_init: initialize a recursive mutex (Don't use it)
 *****************************************************************************/
#define vlc_mutex_init_recursive( P_THIS, P_MUTEX )                         \
    __vlc_mutex_init_recursive( VLC_OBJECT(P_THIS), P_MUTEX )

81
82
83
84
85
86
/*****************************************************************************
 * vlc_mutex_lock: lock a mutex
 *****************************************************************************/
#define vlc_mutex_lock( P_MUTEX )                                           \
    __vlc_mutex_lock( __FILE__, __LINE__, P_MUTEX )

87
#if defined( PTHREAD_COND_T_IN_PTHREAD_H )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
88
static inline unsigned long int CAST_PTHREAD_TO_INT (pthread_t th)
89
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
90
     union { pthread_t th; unsigned long int i; } v = { };
91
92
93
     v.th = th;
     return v.i;
}
94
95
#endif

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
96
static inline int __vlc_mutex_lock( const char * psz_file, int i_line,
97
98
99
100
                                    vlc_mutex_t * p_mutex )
{
    int i_result;
    /* In case of error : */
101
    unsigned long int i_thread = 0;
102

103
#if defined( UNDER_CE )
104
    EnterCriticalSection( &p_mutex->csection );
105
    i_result = 0;
106

107
108
109
110
111
112
113
114
115
#elif defined( WIN32 )
    if( p_mutex->mutex )
    {
        WaitForSingleObject( p_mutex->mutex, INFINITE );
    }
    else
    {
        EnterCriticalSection( &p_mutex->csection );
    }
116
    i_result = 0;
117
118
119
120
121
122
123
124
125
126
127
128
129
130

#elif defined( HAVE_KERNEL_SCHEDULER_H )
    if( p_mutex == NULL )
    {
        i_result = B_BAD_VALUE;
    }
    else if( p_mutex->init < 2000 )
    {
        i_result = B_NO_INIT;
    }
    else
    {
        i_result = acquire_sem( p_mutex->lock );
    }
131
132

#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
133
134
135
#   define vlc_assert_locked( m ) \
           assert (pthread_mutex_lock (&((m)->mutex)) == EDEADLK)

136
137
138
    i_result = pthread_mutex_lock( &p_mutex->mutex );
    if ( i_result )
    {
139
        i_thread = CAST_PTHREAD_TO_INT(pthread_self());
140
        errno = i_result;
141
142
    }

143
144
#endif

145
    if( i_result )
146
147
    {
        msg_Err( p_mutex->p_this,
148
149
                 "thread %li: mutex_lock failed at %s:%d (%d:%m)",
                 i_thread, psz_file, i_line, i_result );
150
        vlc_threads_error( p_mutex->p_this );
151
152
153
154
    }
    return i_result;
}

155
156
157
158
#ifndef vlc_assert_locked
# define vlc_assert_locked( m ) (void)0
#endif

159
160
161
162
163
164
/*****************************************************************************
 * vlc_mutex_unlock: unlock a mutex
 *****************************************************************************/
#define vlc_mutex_unlock( P_MUTEX )                                         \
    __vlc_mutex_unlock( __FILE__, __LINE__, P_MUTEX )

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
165
static inline int __vlc_mutex_unlock( const char * psz_file, int i_line,
166
167
168
169
                                      vlc_mutex_t *p_mutex )
{
    int i_result;
    /* In case of error : */
170
    unsigned long int i_thread = 0;
171

172
#if defined( UNDER_CE )
173
    LeaveCriticalSection( &p_mutex->csection );
174
    i_result = 0;
175

176
177
178
179
180
181
182
183
184
#elif defined( WIN32 )
    if( p_mutex->mutex )
    {
        ReleaseMutex( p_mutex->mutex );
    }
    else
    {
        LeaveCriticalSection( &p_mutex->csection );
    }
185
    i_result = 0;
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200

#elif defined( HAVE_KERNEL_SCHEDULER_H )
    if( p_mutex == NULL )
    {
        i_result = B_BAD_VALUE;
    }
    else if( p_mutex->init < 2000 )
    {
        i_result = B_NO_INIT;
    }
    else
    {
        release_sem( p_mutex->lock );
        return B_OK;
    }
201
202
203
204
205

#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
    i_result = pthread_mutex_unlock( &p_mutex->mutex );
    if ( i_result )
    {
206
        i_thread = CAST_PTHREAD_TO_INT(pthread_self());
207
        errno = i_result;
208
209
    }

210
211
#endif

212
    if( i_result )
213
214
    {
        msg_Err( p_mutex->p_this,
215
216
                 "thread %li: mutex_unlock failed at %s:%d (%d:%m)",
                 i_thread, psz_file, i_line, i_result );
217
        vlc_threads_error( p_mutex->p_this );
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
    }

    return i_result;
}

/*****************************************************************************
 * vlc_mutex_destroy: destroy a mutex
 *****************************************************************************/
#define vlc_mutex_destroy( P_MUTEX )                                        \
    __vlc_mutex_destroy( __FILE__, __LINE__, P_MUTEX )

/*****************************************************************************
 * vlc_cond_init: initialize a condition
 *****************************************************************************/
#define vlc_cond_init( P_THIS, P_COND )                                     \
    __vlc_cond_init( VLC_OBJECT(P_THIS), P_COND )

/*****************************************************************************
 * vlc_cond_signal: start a thread on condition completion
 *****************************************************************************/
#define vlc_cond_signal( P_COND )                                           \
    __vlc_cond_signal( __FILE__, __LINE__, P_COND )

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
241
static inline int __vlc_cond_signal( const char * psz_file, int i_line,
242
243
244
245
                                     vlc_cond_t *p_condvar )
{
    int i_result;
    /* In case of error : */
246
    unsigned long int i_thread = 0;
247

248
#if defined( UNDER_CE )
249
    PulseEvent( p_condvar->event );
250
    i_result = 0;
251

252
253
254
255
256
257
#elif defined( WIN32 )
    /* Release one waiting thread if one is available. */
    /* For this trick to work properly, the vlc_cond_signal must be surrounded
     * by a mutex. This will prevent another thread from stealing the signal */
    if( !p_condvar->semaphore )
    {
258
259
260
261
262
        /*
        ** PulseEvent() only works if none of the waiting threads is suspended.
        ** this is particularily problematic under a debug session. 
        ** as documented in http://support.microsoft.com/kb/q173260/
        */
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
        PulseEvent( p_condvar->event );
    }
    else if( p_condvar->i_win9x_cv == 1 )
    {
        /* Wait for the gate to be open */
        WaitForSingleObject( p_condvar->event, INFINITE );

        if( p_condvar->i_waiting_threads )
        {
            /* Using a semaphore exposes us to a race condition. It is
             * possible for another thread to start waiting on the semaphore
             * just after we signaled it and thus steal the signal.
             * We have to prevent new threads from entering the cond_wait(). */
            ResetEvent( p_condvar->event );

            /* A semaphore is used here because Win9x doesn't have
             * SignalObjectAndWait() and thus a race condition exists
             * during the time we release the mutex and the time we start
             * waiting on the event (more precisely, the signal can sometimes
             * be missed by the waiting thread if we use PulseEvent()). */
            ReleaseSemaphore( p_condvar->semaphore, 1, 0 );
        }
    }
    else
    {
        if( p_condvar->i_waiting_threads )
        {
            ReleaseSemaphore( p_condvar->semaphore, 1, 0 );

            /* Wait for the last thread to be awakened */
            WaitForSingleObject( p_condvar->event, INFINITE );
        }
    }
296
    i_result = 0;
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331

#elif defined( HAVE_KERNEL_SCHEDULER_H )
    if( p_condvar == NULL )
    {
        i_result = B_BAD_VALUE;
    }
    else if( p_condvar->init < 2000 )
    {
        i_result = B_NO_INIT;
    }
    else
    {
        while( p_condvar->thread != -1 )
        {
            thread_info info;
            if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
            {
                return 0;
            }

            if( info.state != B_THREAD_SUSPENDED )
            {
                /* The  waiting thread is not suspended so it could
                 * have been interrupted beetwen the unlock and the
                 * suspend_thread line. That is why we sleep a little
                 * before retesting p_condver->thread. */
                snooze( 10000 );
            }
            else
            {
                /* Ok, we have to wake up that thread */
                resume_thread( p_condvar->thread );
                return 0;
            }
        }
332
        i_result = 0;
333
    }
334
335
336
337
338

#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
    i_result = pthread_cond_signal( &p_condvar->cond );
    if ( i_result )
    {
339
        i_thread = CAST_PTHREAD_TO_INT(pthread_self());
340
        errno = i_result;
341
342
    }

343
344
345
346
347
#endif

    if( i_result )
    {
        msg_Err( p_condvar->p_this,
348
349
                 "thread %li: cond_signal failed at %s:%d (%d:%m)",
                 i_thread, psz_file, i_line, i_result );
350
        vlc_threads_error( p_condvar->p_this );
351
352
353
354
355
356
357
358
359
360
361
    }

    return i_result;
}

/*****************************************************************************
 * vlc_cond_wait: wait until condition completion
 *****************************************************************************/
#define vlc_cond_wait( P_COND, P_MUTEX )                                     \
    __vlc_cond_wait( __FILE__, __LINE__, P_COND, P_MUTEX  )

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
362
static inline int __vlc_cond_wait( const char * psz_file, int i_line,
363
364
365
366
                                   vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex )
{
    int i_result;
    /* In case of error : */
367
    unsigned long int i_thread = 0;
368

369
#if defined( UNDER_CE )
370
371
372
373
374
375
376
377
    p_condvar->i_waiting_threads++;
    LeaveCriticalSection( &p_mutex->csection );
    WaitForSingleObject( p_condvar->event, INFINITE );
    p_condvar->i_waiting_threads--;

    /* Reacquire the mutex before returning. */
    vlc_mutex_lock( p_mutex );

378
    i_result = 0;
379

380
381
382
383
384
385
#elif defined( WIN32 )
    if( !p_condvar->semaphore )
    {
        /* Increase our wait count */
        p_condvar->i_waiting_threads++;

gbazin's avatar
   
gbazin committed
386
        if( p_mutex->mutex )
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
        {
            /* It is only possible to atomically release the mutex and
             * initiate the waiting on WinNT/2K/XP. Win9x doesn't have
             * SignalObjectAndWait(). */
            p_condvar->SignalObjectAndWait( p_mutex->mutex,
                                            p_condvar->event,
                                            INFINITE, FALSE );
        }
        else
        {
            LeaveCriticalSection( &p_mutex->csection );
            WaitForSingleObject( p_condvar->event, INFINITE );
        }

        p_condvar->i_waiting_threads--;
    }
    else if( p_condvar->i_win9x_cv == 1 )
    {
        int i_waiting_threads;

        /* Wait for the gate to be open */
        WaitForSingleObject( p_condvar->event, INFINITE );

        /* Increase our wait count */
        p_condvar->i_waiting_threads++;

        LeaveCriticalSection( &p_mutex->csection );
        WaitForSingleObject( p_condvar->semaphore, INFINITE );

        /* Decrement and test must be atomic */
        EnterCriticalSection( &p_condvar->csection );

        /* Decrease our wait count */
        i_waiting_threads = --p_condvar->i_waiting_threads;

        LeaveCriticalSection( &p_condvar->csection );

        /* Reopen the gate if we were the last waiting thread */
        if( !i_waiting_threads )
            SetEvent( p_condvar->event );
    }
    else
    {
        int i_waiting_threads;

        /* Increase our wait count */
        p_condvar->i_waiting_threads++;

        LeaveCriticalSection( &p_mutex->csection );
        WaitForSingleObject( p_condvar->semaphore, INFINITE );

        /* Decrement and test must be atomic */
        EnterCriticalSection( &p_condvar->csection );

        /* Decrease our wait count */
        i_waiting_threads = --p_condvar->i_waiting_threads;

        LeaveCriticalSection( &p_condvar->csection );

        /* Signal that the last waiting thread just went through */
        if( !i_waiting_threads )
            SetEvent( p_condvar->event );
    }

    /* Reacquire the mutex before returning. */
    vlc_mutex_lock( p_mutex );

454
    i_result = 0;
455

456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
#elif defined( HAVE_KERNEL_SCHEDULER_H )
    if( p_condvar == NULL )
    {
        i_result = B_BAD_VALUE;
    }
    else if( p_mutex == NULL )
    {
        i_result = B_BAD_VALUE;
    }
    else if( p_condvar->init < 2000 )
    {
        i_result = B_NO_INIT;
    }

    /* The p_condvar->thread var is initialized before the unlock because
     * it enables to identify when the thread is interrupted beetwen the
     * unlock line and the suspend_thread line */
    p_condvar->thread = find_thread( NULL );
    vlc_mutex_unlock( p_mutex );
    suspend_thread( p_condvar->thread );
    p_condvar->thread = -1;

    vlc_mutex_lock( p_mutex );
    i_result = 0;

481
482
483
484
#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )

#   ifdef DEBUG
    /* In debug mode, timeout */
485
486
487
488
    struct timespec timeout = {
        (mdate() / 1000000) + THREAD_COND_TIMEOUT,
        0 /* 1Hz precision is sufficient here :-) */
    };
489

490
491
    i_result = pthread_cond_timedwait( &p_condvar->cond, &p_mutex->mutex,
                                       &timeout );
492

493
494
    if( i_result == ETIMEDOUT )
    {
495
        errno = ETIMEDOUT;
496
        msg_Dbg( p_condvar->p_this,
497
                  "thread %li: possible condition deadlock "
498
499
                  "at %s:%d (%m)", CAST_PTHREAD_TO_INT(pthread_self()),
                  psz_file, i_line );
500
501

        i_result = pthread_cond_wait( &p_condvar->cond, &p_mutex->mutex );
502
    }
503

504
505
506
507
508
509
#   else
    i_result = pthread_cond_wait( &p_condvar->cond, &p_mutex->mutex );
#   endif

    if ( i_result )
    {
510
        i_thread = CAST_PTHREAD_TO_INT(pthread_self());
511
        errno = i_result;
512
513
514
515
516
517
518
    }

#endif

    if( i_result )
    {
        msg_Err( p_condvar->p_this,
519
520
                 "thread %li: cond_wait failed at %s:%d (%d:%m)",
                 i_thread, psz_file, i_line, i_result );
521
        vlc_threads_error( p_condvar->p_this );
522
523
524
525
526
    }

    return i_result;
}

527
528
529

/*****************************************************************************
 * vlc_cond_timedwait: wait until condition completion or expiration
530
531
 *****************************************************************************
 * Returns 0 if object signaled, an error code in case of timeout or error.
532
533
534
535
536
537
538
539
540
541
542
543
 *****************************************************************************/
#define vlc_cond_timedwait( P_COND, P_MUTEX, DEADLINE )                      \
    __vlc_cond_timedwait( __FILE__, __LINE__, P_COND, P_MUTEX, DEADLINE  )

static inline int __vlc_cond_timedwait( const char * psz_file, int i_line,
                                        vlc_cond_t *p_condvar,
                                        vlc_mutex_t *p_mutex,
                                        mtime_t deadline )
{
    int i_res;
    unsigned long int i_thread = 0;

544
#if defined( UNDER_CE )
545
546
547
548
    mtime_t delay_ms = (deadline - mdate())/1000;

    DWORD result;
    if( delay_ms < 0 )
549
        delay_ms = 0;
550
551
552
553
554
555
556
557
558
559

    p_condvar->i_waiting_threads++;
    LeaveCriticalSection( &p_mutex->csection );
    result = WaitForSingleObject( p_condvar->event, delay_ms );
    p_condvar->i_waiting_threads--;

    /* Reacquire the mutex before returning. */
    vlc_mutex_lock( p_mutex );

    i_res = (int)result;
560
561
    if(result == WAIT_TIMEOUT)
       return WAIT_TIMEOUT; /* this error is perfectly normal */
562

563
#elif defined( WIN32 )
564
565
566
567
    DWORD result;

    mtime_t delay_ms = (deadline - mdate())/1000;
    if( delay_ms < 0 )
568
        delay_ms = 0;
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602

    if( !p_condvar->semaphore )
    {
        /* Increase our wait count */
        p_condvar->i_waiting_threads++;

        if( p_mutex->mutex )
        {
            /* It is only possible to atomically release the mutex and
             * initiate the waiting on WinNT/2K/XP. Win9x doesn't have
             * SignalObjectAndWait(). */
            result = p_condvar->SignalObjectAndWait( p_mutex->mutex,
                                            p_condvar->event,
                                            delay_ms, FALSE );
        }
        else
        {
            LeaveCriticalSection( &p_mutex->csection );
            result = WaitForSingleObject( p_condvar->event, delay_ms );
        }

        p_condvar->i_waiting_threads--;
    }
    else if( p_condvar->i_win9x_cv == 1 )
    {
        int i_waiting_threads;

        /* Wait for the gate to be open */
        result = WaitForSingleObject( p_condvar->event, delay_ms );

        /* Increase our wait count */
        p_condvar->i_waiting_threads++;

        LeaveCriticalSection( &p_mutex->csection );
603
604
605
606
607
608
609
610
611
        if( !result )
        {
            /* recaculate remaining delay */
            delay_ms = (deadline - mdate())/1000;
            if( delay_ms < 0 )
                delay_ms = 0;

            result = WaitForSingleObject( p_condvar->semaphore, delay_ms );
        }
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649

        /* Decrement and test must be atomic */
        EnterCriticalSection( &p_condvar->csection );

        /* Decrease our wait count */
        i_waiting_threads = --p_condvar->i_waiting_threads;

        LeaveCriticalSection( &p_condvar->csection );

        /* Reopen the gate if we were the last waiting thread */
        if( !i_waiting_threads )
            SetEvent( p_condvar->event );
    }
    else
    {
        int i_waiting_threads;

        /* Increase our wait count */
        p_condvar->i_waiting_threads++;

        LeaveCriticalSection( &p_mutex->csection );
        result = WaitForSingleObject( p_condvar->semaphore, delay_ms );

        /* Decrement and test must be atomic */
        EnterCriticalSection( &p_condvar->csection );

        /* Decrease our wait count */
        i_waiting_threads = --p_condvar->i_waiting_threads;

        LeaveCriticalSection( &p_condvar->csection );

        /* Signal that the last waiting thread just went through */
        if( !i_waiting_threads )
            SetEvent( p_condvar->event );
    }

    /* Reacquire the mutex before returning. */
    vlc_mutex_lock( p_mutex );
650
651
    if(result == WAIT_TIMEOUT)
       return WAIT_TIMEOUT; /* this error is perfectly normal */
652
653

    i_res = (int)result;
654
655
656
657
658
659
660
661

#elif defined( HAVE_KERNEL_SCHEDULER_H )
#   error Unimplemented
#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
    lldiv_t d = lldiv( deadline, 1000000 );
    struct timespec ts = { d.quot, d.rem * 1000 };

    i_res = pthread_cond_timedwait( &p_condvar->cond, &p_mutex->mutex, &ts );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
662
    if( i_res == ETIMEDOUT )
663
        return ETIMEDOUT; /* this error is perfectly normal */
664
665
    else
    if ( i_res ) /* other errors = bug */
666
667
    {
        i_thread = CAST_PTHREAD_TO_INT(pthread_self());
668
        errno = i_res;
669
670
671
672
673
674
675
    }

#endif

    if( i_res )
    {
        msg_Err( p_condvar->p_this,
676
677
                 "thread %li: cond_wait failed at %s:%d (%d:%m)",
                 i_thread, psz_file, i_line, i_res );
678
        vlc_threads_error( p_condvar->p_this );
679
680
681
682
683
    }

    return i_res;
}

684
685
686
687
688
689
/*****************************************************************************
 * vlc_cond_destroy: destroy a condition
 *****************************************************************************/
#define vlc_cond_destroy( P_COND )                                          \
    __vlc_cond_destroy( __FILE__, __LINE__, P_COND )

690
691
692
693
694
695
696
697
698
/*****************************************************************************
 * vlc_threadvar_create: create a thread-local variable
 *****************************************************************************/
#define vlc_threadvar_create( PTHIS, P_TLS )                                 \
   __vlc_threadvar_create( PTHIS, P_TLS )

/*****************************************************************************
 * vlc_threadvar_set: create: set the value of a thread-local variable
 *****************************************************************************/
699
static inline int vlc_threadvar_set( vlc_threadvar_t * p_tls, void *p_value )
700
701
702
{
    int i_ret;

703
#if defined( HAVE_KERNEL_SCHEDULER_H )
704
705
706
    return -1;

#elif defined( UNDER_CE ) || defined( WIN32 )
707
    i_ret = ( TlsSetValue( p_tls->handle, p_value ) != 0 );
708
709
710
711
712
713
714
715
716
717
718
719

#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
    i_ret = pthread_setspecific( p_tls->handle, p_value );

#endif

    return i_ret;
}

/*****************************************************************************
 * vlc_threadvar_get: create: get the value of a thread-local variable
 *****************************************************************************/
720
static inline void* vlc_threadvar_get( vlc_threadvar_t * p_tls )
721
722
723
{
    void* p_ret;

724
#if defined( HAVE_KERNEL_SCHEDULER_H )
725
    p_ret = NULL;
726
#elif defined( UNDER_CE ) || defined( WIN32 )
Christophe Mutricy's avatar
Christophe Mutricy committed
727
    p_ret = TlsGetValue( p_tls->handle );
728
729
730
731
732
733
734
735
736

#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
    p_ret = pthread_getspecific( p_tls->handle );

#endif

    return p_ret;
}

737
738
739
740
741
742
743
744
745
746
747
# if defined (_POSIX_SPIN_LOCKS) && ((_POSIX_SPIN_LOCKS - 0) > 0)
typedef struct
{
    pthread_spinlock_t  spin;
} vlc_spinlock_t;

/**
 * Initializes a spinlock.
 */
static inline int vlc_spin_init (vlc_spinlock_t *spin)
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
748
    return pthread_spin_init (&spin->spin, PTHREAD_PROCESS_PRIVATE);
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
}

/**
 * Acquires a spinlock.
 */
static inline int vlc_spin_lock (vlc_spinlock_t *spin)
{
    return pthread_spin_lock (&spin->spin);
}

/**
 * Releases a spinlock.
 */
static inline int vlc_spin_unlock (vlc_spinlock_t *spin)
{
    return pthread_spin_unlock (&spin->spin);
}

/**
 * Deinitializes a spinlock.
 */
static inline int vlc_spin_destroy (vlc_spinlock_t *spin)
{
    return pthread_spin_destroy (&spin->spin);
}
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814

#elif defined( WIN32 )

typedef CRITICAL_SECTION vlc_spinlock_t;

/**
 * Initializes a spinlock.
 */
static inline int vlc_spin_init (vlc_spinlock_t *spin)
{
    return !InitializeCriticalSectionAndSpinCount(spin, 4000);
}

/**
 * Acquires a spinlock.
 */
static inline int vlc_spin_lock (vlc_spinlock_t *spin)
{
    EnterCriticalSection(spin);
    return 0;
}

/**
 * Releases a spinlock.
 */
static inline int vlc_spin_unlock (vlc_spinlock_t *spin)
{
    LeaveCriticalSection(spin);
    return 0;
}

/**
 * Deinitializes a spinlock.
 */
static inline int vlc_spin_destroy (vlc_spinlock_t *spin)
{
    DeleteCriticalSection(spin);
    return 0;
}


815
#else
816
817


818
819
/* Fallback to plain mutexes if spinlocks are not available */
typedef vlc_mutex_t vlc_spinlock_t;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
820
821
822

static inline int vlc_spin_init (vlc_spinlock_t *spin)
{
823
    return __vlc_mutex_init (NULL, spin);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
824
825
}

826
827
828
829
830
# define vlc_spin_lock    vlc_mutex_lock
# define vlc_spin_unlock  vlc_mutex_unlock
# define vlc_spin_destroy vlc_mutex_destroy
#endif

831
832
833
834
835
836
/*****************************************************************************
 * vlc_thread_create: create a thread
 *****************************************************************************/
#define vlc_thread_create( P_THIS, PSZ_NAME, FUNC, PRIORITY, WAIT )         \
    __vlc_thread_create( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PSZ_NAME, (void * ( * ) ( void * ))FUNC, PRIORITY, WAIT )

837
838
839
840
841
842
/*****************************************************************************
 * vlc_thread_set_priority: set the priority of the calling thread
 *****************************************************************************/
#define vlc_thread_set_priority( P_THIS, PRIORITY )                         \
    __vlc_thread_set_priority( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PRIORITY )

843
844
845
846
847
848
849
850
851
852
/*****************************************************************************
 * vlc_thread_ready: tell the parent thread we were successfully spawned
 *****************************************************************************/
#define vlc_thread_ready( P_THIS )                                          \
    __vlc_thread_ready( VLC_OBJECT(P_THIS) )

/*****************************************************************************
 * vlc_thread_join: wait until a thread exits
 *****************************************************************************/
#define vlc_thread_join( P_THIS )                                           \
853
    __vlc_thread_join( VLC_OBJECT(P_THIS), __FILE__, __LINE__ )
854
855

#endif