vlc_threads_funcs.h 26.1 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
Antoine Cellerier's avatar
Antoine Cellerier committed
25
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26 27
 *****************************************************************************/

Clément Stenac's avatar
Clément Stenac 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(LIBVLC_USE_PTHREAD)
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(LIBVLC_USE_PTHREAD)
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
#elif defined(LIBVLC_USE_PTHREAD)
203 204 205
    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
#elif defined(LIBVLC_USE_PTHREAD)
336 337 338
    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++;

Gildas Bazin's avatar
 
Gildas Bazin 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
#elif defined(LIBVLC_USE_PTHREAD)
482 483 484
    i_result = pthread_cond_wait( &p_condvar->cond, &p_mutex->mutex );
    if ( i_result )
    {
485
        i_thread = CAST_PTHREAD_TO_INT(pthread_self());
486
        errno = i_result;
487 488 489 490 491 492 493
    }

#endif

    if( i_result )
    {
        msg_Err( p_condvar->p_this,
494 495
                 "thread %li: cond_wait failed at %s:%d (%d:%m)",
                 i_thread, psz_file, i_line, i_result );
496
        vlc_threads_error( p_condvar->p_this );
497 498 499 500 501
    }

    return i_result;
}

502 503 504

/*****************************************************************************
 * vlc_cond_timedwait: wait until condition completion or expiration
505 506
 *****************************************************************************
 * Returns 0 if object signaled, an error code in case of timeout or error.
507 508 509 510 511 512 513 514 515 516 517 518
 *****************************************************************************/
#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;

519
#if defined( UNDER_CE )
520 521 522 523
    mtime_t delay_ms = (deadline - mdate())/1000;

    DWORD result;
    if( delay_ms < 0 )
524
        delay_ms = 0;
525 526 527 528 529 530 531 532 533 534

    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;
535 536
    if(result == WAIT_TIMEOUT)
       return WAIT_TIMEOUT; /* this error is perfectly normal */
537

538
#elif defined( WIN32 )
539 540 541 542
    DWORD result;

    mtime_t delay_ms = (deadline - mdate())/1000;
    if( delay_ms < 0 )
543
        delay_ms = 0;
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577

    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 );
578 579 580 581 582 583 584 585 586
        if( !result )
        {
            /* recaculate remaining delay */
            delay_ms = (deadline - mdate())/1000;
            if( delay_ms < 0 )
                delay_ms = 0;

            result = WaitForSingleObject( p_condvar->semaphore, delay_ms );
        }
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624

        /* 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 );
625 626
    if(result == WAIT_TIMEOUT)
       return WAIT_TIMEOUT; /* this error is perfectly normal */
627 628

    i_res = (int)result;
629 630 631

#elif defined( HAVE_KERNEL_SCHEDULER_H )
#   error Unimplemented
632
#elif defined(LIBVLC_USE_PTHREAD)
633 634 635 636
    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
637
    if( i_res == ETIMEDOUT )
638
        return ETIMEDOUT; /* this error is perfectly normal */
639 640
    else
    if ( i_res ) /* other errors = bug */
641 642
    {
        i_thread = CAST_PTHREAD_TO_INT(pthread_self());
643
        errno = i_res;
644 645 646 647 648 649 650
    }

#endif

    if( i_res )
    {
        msg_Err( p_condvar->p_this,
651 652
                 "thread %li: cond_wait failed at %s:%d (%d:%m)",
                 i_thread, psz_file, i_line, i_res );
653
        vlc_threads_error( p_condvar->p_this );
654 655 656 657 658
    }

    return i_res;
}

659 660 661 662 663 664
/*****************************************************************************
 * vlc_cond_destroy: destroy a condition
 *****************************************************************************/
#define vlc_cond_destroy( P_COND )                                          \
    __vlc_cond_destroy( __FILE__, __LINE__, P_COND )

665 666 667 668 669 670 671 672 673
/*****************************************************************************
 * 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
 *****************************************************************************/
674
static inline int vlc_threadvar_set( vlc_threadvar_t * p_tls, void *p_value )
675 676 677
{
    int i_ret;

678
#if defined( HAVE_KERNEL_SCHEDULER_H )
679 680 681
    return -1;

#elif defined( UNDER_CE ) || defined( WIN32 )
682
    i_ret = ( TlsSetValue( p_tls->handle, p_value ) != 0 );
683

684
#elif defined(LIBVLC_USE_PTHREAD)
685 686 687 688 689 690 691 692 693 694
    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
 *****************************************************************************/
695
static inline void* vlc_threadvar_get( vlc_threadvar_t * p_tls )
696 697 698
{
    void* p_ret;

699
#if defined( HAVE_KERNEL_SCHEDULER_H )
700
    p_ret = NULL;
701
#elif defined( UNDER_CE ) || defined( WIN32 )
Christophe Mutricy's avatar
Christophe Mutricy committed
702
    p_ret = TlsGetValue( p_tls->handle );
703

704
#elif defined(LIBVLC_USE_PTHREAD)
705 706 707 708 709 710 711
    p_ret = pthread_getspecific( p_tls->handle );

#endif

    return p_ret;
}

712 713 714 715 716 717 718 719 720 721 722
# 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
723
    return pthread_spin_init (&spin->spin, PTHREAD_PROCESS_PRIVATE);
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
}

/**
 * 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);
}
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 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789

#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;
}


790
#else
791 792


793 794
/* 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
795 796 797

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

801 802 803 804 805
# define vlc_spin_lock    vlc_mutex_lock
# define vlc_spin_unlock  vlc_mutex_unlock
# define vlc_spin_destroy vlc_mutex_destroy
#endif

806 807 808 809 810 811
/*****************************************************************************
 * 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 )

812 813 814 815 816 817
/*****************************************************************************
 * 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 )

818 819 820 821 822 823 824 825 826 827
/*****************************************************************************
 * 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 )                                           \
828
    __vlc_thread_join( VLC_OBJECT(P_THIS), __FILE__, __LINE__ )
829 830

#endif