| 164 | | typedef pthread_t vlc_thread_t; |
|---|
| 165 | | typedef pthread_mutex_t vlc_mutex_t; |
|---|
| 166 | | typedef pthread_cond_t vlc_cond_t; |
|---|
| 167 | | typedef pthread_key_t vlc_threadvar_t; |
|---|
| 168 | | |
|---|
| 169 | | #endif |
|---|
| | 201 | # define VLC_THREAD_ASSERT (void)0 |
|---|
| | 202 | #endif |
|---|
| | 203 | |
|---|
| | 204 | static inline void __vlc_mutex_lock( const char * psz_file, int i_line, |
|---|
| | 205 | vlc_mutex_t * p_mutex ) |
|---|
| | 206 | { |
|---|
| | 207 | #if defined(LIBVLC_USE_PTHREAD) |
|---|
| | 208 | # define vlc_assert_locked( m ) \ |
|---|
| | 209 | assert (pthread_mutex_lock (m) == EDEADLK) |
|---|
| | 210 | int val = pthread_mutex_lock( p_mutex ); |
|---|
| | 211 | VLC_THREAD_ASSERT ("locking mutex"); |
|---|
| | 212 | |
|---|
| | 213 | #elif defined( UNDER_CE ) |
|---|
| | 214 | VLC_UNUSED( psz_file); VLC_UNUSED( i_line ); |
|---|
| | 215 | |
|---|
| | 216 | EnterCriticalSection( &p_mutex->csection ); |
|---|
| | 217 | |
|---|
| | 218 | #elif defined( WIN32 ) |
|---|
| | 219 | VLC_UNUSED( psz_file); VLC_UNUSED( i_line ); |
|---|
| | 220 | |
|---|
| | 221 | WaitForSingleObject( *p_mutex, INFINITE ); |
|---|
| | 222 | |
|---|
| | 223 | #elif defined( HAVE_KERNEL_SCHEDULER_H ) |
|---|
| | 224 | acquire_sem( p_mutex->lock ); |
|---|
| | 225 | |
|---|
| | 226 | #endif |
|---|
| | 227 | } |
|---|
| | 228 | |
|---|
| | 229 | #ifndef vlc_assert_locked |
|---|
| | 230 | # define vlc_assert_locked( m ) (void)0 |
|---|
| | 231 | #endif |
|---|
| | 232 | |
|---|
| | 233 | /***************************************************************************** |
|---|
| | 234 | * vlc_mutex_unlock: unlock a mutex |
|---|
| | 235 | *****************************************************************************/ |
|---|
| | 236 | #define vlc_mutex_unlock( P_MUTEX ) \ |
|---|
| | 237 | __vlc_mutex_unlock( __FILE__, __LINE__, P_MUTEX ) |
|---|
| | 238 | |
|---|
| | 239 | static inline void __vlc_mutex_unlock( const char * psz_file, int i_line, |
|---|
| | 240 | vlc_mutex_t *p_mutex ) |
|---|
| | 241 | { |
|---|
| | 242 | #if defined(LIBVLC_USE_PTHREAD) |
|---|
| | 243 | int val = pthread_mutex_unlock( p_mutex ); |
|---|
| | 244 | VLC_THREAD_ASSERT ("unlocking mutex"); |
|---|
| | 245 | |
|---|
| | 246 | #elif defined( UNDER_CE ) |
|---|
| | 247 | VLC_UNUSED( psz_file); VLC_UNUSED( i_line ); |
|---|
| | 248 | |
|---|
| | 249 | LeaveCriticalSection( &p_mutex->csection ); |
|---|
| | 250 | |
|---|
| | 251 | #elif defined( WIN32 ) |
|---|
| | 252 | VLC_UNUSED( psz_file); VLC_UNUSED( i_line ); |
|---|
| | 253 | |
|---|
| | 254 | ReleaseMutex( *p_mutex ); |
|---|
| | 255 | |
|---|
| | 256 | #elif defined( HAVE_KERNEL_SCHEDULER_H ) |
|---|
| | 257 | release_sem( p_mutex->lock ); |
|---|
| | 258 | |
|---|
| | 259 | #endif |
|---|
| | 260 | } |
|---|
| | 261 | |
|---|
| | 262 | /***************************************************************************** |
|---|
| | 263 | * vlc_mutex_destroy: destroy a mutex |
|---|
| | 264 | *****************************************************************************/ |
|---|
| | 265 | #define vlc_mutex_destroy( P_MUTEX ) \ |
|---|
| | 266 | __vlc_mutex_destroy( __FILE__, __LINE__, P_MUTEX ) |
|---|
| | 267 | |
|---|
| | 268 | /***************************************************************************** |
|---|
| | 269 | * vlc_cond_init: initialize a condition |
|---|
| | 270 | *****************************************************************************/ |
|---|
| | 271 | #define vlc_cond_init( P_THIS, P_COND ) \ |
|---|
| | 272 | __vlc_cond_init( P_COND ) |
|---|
| | 273 | |
|---|
| | 274 | /***************************************************************************** |
|---|
| | 275 | * vlc_cond_signal: start a thread on condition completion |
|---|
| | 276 | *****************************************************************************/ |
|---|
| | 277 | #define vlc_cond_signal( P_COND ) \ |
|---|
| | 278 | __vlc_cond_signal( __FILE__, __LINE__, P_COND ) |
|---|
| | 279 | |
|---|
| | 280 | static inline void __vlc_cond_signal( const char * psz_file, int i_line, |
|---|
| | 281 | vlc_cond_t *p_condvar ) |
|---|
| | 282 | { |
|---|
| | 283 | #if defined(LIBVLC_USE_PTHREAD) |
|---|
| | 284 | int val = pthread_cond_signal( p_condvar ); |
|---|
| | 285 | VLC_THREAD_ASSERT ("signaling condition variable"); |
|---|
| | 286 | |
|---|
| | 287 | #elif defined( UNDER_CE ) || defined( WIN32 ) |
|---|
| | 288 | VLC_UNUSED( psz_file); VLC_UNUSED( i_line ); |
|---|
| | 289 | |
|---|
| | 290 | /* Release one waiting thread if one is available. */ |
|---|
| | 291 | /* For this trick to work properly, the vlc_cond_signal must be surrounded |
|---|
| | 292 | * by a mutex. This will prevent another thread from stealing the signal */ |
|---|
| | 293 | /* PulseEvent() only works if none of the waiting threads is suspended. |
|---|
| | 294 | * This is particularily problematic under a debug session. |
|---|
| | 295 | * as documented in http://support.microsoft.com/kb/q173260/ */ |
|---|
| | 296 | PulseEvent( p_condvar->event ); |
|---|
| | 297 | |
|---|
| | 298 | #elif defined( HAVE_KERNEL_SCHEDULER_H ) |
|---|
| | 299 | while( p_condvar->thread != -1 ) |
|---|
| | 300 | { |
|---|
| | 301 | thread_info info; |
|---|
| | 302 | if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE ) |
|---|
| | 303 | return; |
|---|
| | 304 | |
|---|
| | 305 | if( info.state != B_THREAD_SUSPENDED ) |
|---|
| | 306 | { |
|---|
| | 307 | /* The waiting thread is not suspended so it could |
|---|
| | 308 | * have been interrupted beetwen the unlock and the |
|---|
| | 309 | * suspend_thread line. That is why we sleep a little |
|---|
| | 310 | * before retesting p_condver->thread. */ |
|---|
| | 311 | snooze( 10000 ); |
|---|
| | 312 | } |
|---|
| | 313 | else |
|---|
| | 314 | { |
|---|
| | 315 | /* Ok, we have to wake up that thread */ |
|---|
| | 316 | resume_thread( p_condvar->thread ); |
|---|
| | 317 | } |
|---|
| | 318 | } |
|---|
| | 319 | |
|---|
| | 320 | #endif |
|---|
| | 321 | } |
|---|
| | 322 | |
|---|
| | 323 | /***************************************************************************** |
|---|
| | 324 | * vlc_cond_wait: wait until condition completion |
|---|
| | 325 | *****************************************************************************/ |
|---|
| | 326 | #define vlc_cond_wait( P_COND, P_MUTEX ) \ |
|---|
| | 327 | __vlc_cond_wait( __FILE__, __LINE__, P_COND, P_MUTEX ) |
|---|
| | 328 | |
|---|
| | 329 | static inline void __vlc_cond_wait( const char * psz_file, int i_line, |
|---|
| | 330 | vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex ) |
|---|
| | 331 | { |
|---|
| | 332 | #if defined(LIBVLC_USE_PTHREAD) |
|---|
| | 333 | int val = pthread_cond_wait( p_condvar, p_mutex ); |
|---|
| | 334 | VLC_THREAD_ASSERT ("waiting on condition"); |
|---|
| | 335 | |
|---|
| | 336 | #elif defined( UNDER_CE ) |
|---|
| | 337 | p_condvar->i_waiting_threads++; |
|---|
| | 338 | LeaveCriticalSection( &p_mutex->csection ); |
|---|
| | 339 | WaitForSingleObject( p_condvar->event, INFINITE ); |
|---|
| | 340 | p_condvar->i_waiting_threads--; |
|---|
| | 341 | |
|---|
| | 342 | /* Reacquire the mutex before returning. */ |
|---|
| | 343 | vlc_mutex_lock( p_mutex ); |
|---|
| | 344 | |
|---|
| | 345 | #elif defined( WIN32 ) |
|---|
| | 346 | VLC_UNUSED( psz_file); VLC_UNUSED( i_line ); |
|---|
| | 347 | |
|---|
| | 348 | /* Increase our wait count */ |
|---|
| | 349 | p_condvar->i_waiting_threads++; |
|---|
| | 350 | SignalObjectAndWait( *p_mutex, p_condvar->event, INFINITE, FALSE ); |
|---|
| | 351 | p_condvar->i_waiting_threads--; |
|---|
| | 352 | |
|---|
| | 353 | /* Reacquire the mutex before returning. */ |
|---|
| | 354 | vlc_mutex_lock( p_mutex ); |
|---|
| | 355 | |
|---|
| | 356 | #elif defined( HAVE_KERNEL_SCHEDULER_H ) |
|---|
| | 357 | /* The p_condvar->thread var is initialized before the unlock because |
|---|
| | 358 | * it enables to identify when the thread is interrupted beetwen the |
|---|
| | 359 | * unlock line and the suspend_thread line */ |
|---|
| | 360 | p_condvar->thread = find_thread( NULL ); |
|---|
| | 361 | vlc_mutex_unlock( p_mutex ); |
|---|
| | 362 | suspend_thread( p_condvar->thread ); |
|---|
| | 363 | p_condvar->thread = -1; |
|---|
| | 364 | |
|---|
| | 365 | vlc_mutex_lock( p_mutex ); |
|---|
| | 366 | |
|---|
| | 367 | #endif |
|---|
| | 368 | } |
|---|
| | 369 | |
|---|
| | 370 | |
|---|
| | 371 | /***************************************************************************** |
|---|
| | 372 | * vlc_cond_timedwait: wait until condition completion or expiration |
|---|
| | 373 | ***************************************************************************** |
|---|
| | 374 | * Returns 0 if object signaled, an error code in case of timeout or error. |
|---|
| | 375 | *****************************************************************************/ |
|---|
| | 376 | #define vlc_cond_timedwait( P_COND, P_MUTEX, DEADLINE ) \ |
|---|
| | 377 | __vlc_cond_timedwait( __FILE__, __LINE__, P_COND, P_MUTEX, DEADLINE ) |
|---|
| | 378 | |
|---|
| | 379 | static inline int __vlc_cond_timedwait( const char * psz_file, int i_line, |
|---|
| | 380 | vlc_cond_t *p_condvar, |
|---|
| | 381 | vlc_mutex_t *p_mutex, |
|---|
| | 382 | mtime_t deadline ) |
|---|
| | 383 | { |
|---|
| | 384 | #if defined(LIBVLC_USE_PTHREAD) |
|---|
| | 385 | lldiv_t d = lldiv( deadline, 1000000 ); |
|---|
| | 386 | struct timespec ts = { d.quot, d.rem * 1000 }; |
|---|
| | 387 | |
|---|
| | 388 | int val = pthread_cond_timedwait (p_condvar, p_mutex, &ts); |
|---|
| | 389 | if (val == ETIMEDOUT) |
|---|
| | 390 | return ETIMEDOUT; /* this error is perfectly normal */ |
|---|
| | 391 | VLC_THREAD_ASSERT ("timed-waiting on condition"); |
|---|
| | 392 | |
|---|
| | 393 | #elif defined( UNDER_CE ) |
|---|
| | 394 | mtime_t delay_ms = (deadline - mdate())/1000; |
|---|
| | 395 | |
|---|
| | 396 | DWORD result; |
|---|
| | 397 | if( delay_ms < 0 ) |
|---|
| | 398 | delay_ms = 0; |
|---|
| | 399 | |
|---|
| | 400 | p_condvar->i_waiting_threads++; |
|---|
| | 401 | LeaveCriticalSection( &p_mutex->csection ); |
|---|
| | 402 | result = WaitForSingleObject( p_condvar->event, delay_ms ); |
|---|
| | 403 | p_condvar->i_waiting_threads--; |
|---|
| | 404 | |
|---|
| | 405 | /* Reacquire the mutex before returning. */ |
|---|
| | 406 | vlc_mutex_lock( p_mutex ); |
|---|
| | 407 | |
|---|
| | 408 | if(result == WAIT_TIMEOUT) |
|---|
| | 409 | return ETIMEDOUT; /* this error is perfectly normal */ |
|---|
| | 410 | |
|---|
| | 411 | #elif defined( WIN32 ) |
|---|
| | 412 | VLC_UNUSED( psz_file); VLC_UNUSED( i_line ); |
|---|
| | 413 | |
|---|
| | 414 | DWORD result; |
|---|
| | 415 | |
|---|
| | 416 | mtime_t delay_ms = (deadline - mdate())/1000; |
|---|
| | 417 | if( delay_ms < 0 ) |
|---|
| | 418 | delay_ms = 0; |
|---|
| | 419 | |
|---|
| | 420 | /* Increase our wait count */ |
|---|
| | 421 | p_condvar->i_waiting_threads++; |
|---|
| | 422 | result = SignalObjectAndWait( *p_mutex, p_condvar->event, |
|---|
| | 423 | delay_ms, FALSE ); |
|---|
| | 424 | p_condvar->i_waiting_threads--; |
|---|
| | 425 | |
|---|
| | 426 | /* Reacquire the mutex before returning. */ |
|---|
| | 427 | vlc_mutex_lock( p_mutex ); |
|---|
| | 428 | if(result == WAIT_TIMEOUT) |
|---|
| | 429 | return ETIMEDOUT; /* this error is perfectly normal */ |
|---|
| | 430 | |
|---|
| | 431 | #elif defined( HAVE_KERNEL_SCHEDULER_H ) |
|---|
| | 432 | # error Unimplemented |
|---|
| | 433 | |
|---|
| | 434 | #endif |
|---|
| | 435 | |
|---|
| | 436 | return 0; |
|---|
| | 437 | } |
|---|
| | 438 | |
|---|
| | 439 | /***************************************************************************** |
|---|
| | 440 | * vlc_cond_destroy: destroy a condition |
|---|
| | 441 | *****************************************************************************/ |
|---|
| | 442 | #define vlc_cond_destroy( P_COND ) \ |
|---|
| | 443 | __vlc_cond_destroy( __FILE__, __LINE__, P_COND ) |
|---|
| | 444 | |
|---|
| | 445 | /***************************************************************************** |
|---|
| | 446 | * vlc_threadvar_create: create a thread-local variable |
|---|
| | 447 | *****************************************************************************/ |
|---|
| | 448 | #define vlc_threadvar_create( PTHIS, P_TLS ) \ |
|---|
| | 449 | __vlc_threadvar_create( P_TLS ) |
|---|
| | 450 | |
|---|
| | 451 | /***************************************************************************** |
|---|
| | 452 | * vlc_threadvar_set: create: set the value of a thread-local variable |
|---|
| | 453 | *****************************************************************************/ |
|---|
| | 454 | static inline int vlc_threadvar_set( vlc_threadvar_t * p_tls, void *p_value ) |
|---|
| | 455 | { |
|---|
| | 456 | int i_ret; |
|---|
| | 457 | |
|---|
| | 458 | #if defined(LIBVLC_USE_PTHREAD) |
|---|
| | 459 | i_ret = pthread_setspecific( *p_tls, p_value ); |
|---|
| | 460 | |
|---|
| | 461 | #elif defined( HAVE_KERNEL_SCHEDULER_H ) |
|---|
| | 462 | i_ret = EINVAL; |
|---|
| | 463 | |
|---|
| | 464 | #elif defined( UNDER_CE ) || defined( WIN32 ) |
|---|
| | 465 | i_ret = TlsSetValue( *p_tls, p_value ) ? EINVAL : 0; |
|---|
| | 466 | |
|---|
| | 467 | #endif |
|---|
| | 468 | |
|---|
| | 469 | return i_ret; |
|---|
| | 470 | } |
|---|
| | 471 | |
|---|
| | 472 | /***************************************************************************** |
|---|
| | 473 | * vlc_threadvar_get: create: get the value of a thread-local variable |
|---|
| | 474 | *****************************************************************************/ |
|---|
| | 475 | static inline void* vlc_threadvar_get( vlc_threadvar_t * p_tls ) |
|---|
| | 476 | { |
|---|
| | 477 | void *p_ret; |
|---|
| | 478 | |
|---|
| | 479 | #if defined(LIBVLC_USE_PTHREAD) |
|---|
| | 480 | p_ret = pthread_getspecific( *p_tls ); |
|---|
| | 481 | |
|---|
| | 482 | #elif defined( HAVE_KERNEL_SCHEDULER_H ) |
|---|
| | 483 | p_ret = NULL; |
|---|
| | 484 | |
|---|
| | 485 | #elif defined( UNDER_CE ) || defined( WIN32 ) |
|---|
| | 486 | p_ret = TlsGetValue( *p_tls ); |
|---|
| | 487 | |
|---|
| | 488 | #endif |
|---|
| | 489 | |
|---|
| | 490 | return p_ret; |
|---|
| | 491 | } |
|---|
| | 492 | |
|---|
| | 493 | # if defined (_POSIX_SPIN_LOCKS) && ((_POSIX_SPIN_LOCKS - 0) > 0) |
|---|
| | 494 | typedef pthread_spinlock_t vlc_spinlock_t; |
|---|
| | 495 | |
|---|
| | 496 | /** |
|---|
| | 497 | * Initializes a spinlock. |
|---|
| | 498 | */ |
|---|
| | 499 | static inline int vlc_spin_init (vlc_spinlock_t *spin) |
|---|
| | 500 | { |
|---|
| | 501 | return pthread_spin_init (spin, PTHREAD_PROCESS_PRIVATE); |
|---|
| | 502 | } |
|---|
| | 503 | |
|---|
| | 504 | /** |
|---|
| | 505 | * Acquires a spinlock. |
|---|
| | 506 | */ |
|---|
| | 507 | static inline void vlc_spin_lock (vlc_spinlock_t *spin) |
|---|
| | 508 | { |
|---|
| | 509 | pthread_spin_lock (spin); |
|---|
| | 510 | } |
|---|
| | 511 | |
|---|
| | 512 | /** |
|---|
| | 513 | * Releases a spinlock. |
|---|
| | 514 | */ |
|---|
| | 515 | static inline void vlc_spin_unlock (vlc_spinlock_t *spin) |
|---|
| | 516 | { |
|---|
| | 517 | pthread_spin_unlock (spin); |
|---|
| | 518 | } |
|---|
| | 519 | |
|---|
| | 520 | /** |
|---|
| | 521 | * Deinitializes a spinlock. |
|---|
| | 522 | */ |
|---|
| | 523 | static inline void vlc_spin_destroy (vlc_spinlock_t *spin) |
|---|
| | 524 | { |
|---|
| | 525 | pthread_spin_destroy (spin); |
|---|
| | 526 | } |
|---|
| | 527 | |
|---|
| | 528 | #elif defined( WIN32 ) |
|---|
| | 529 | |
|---|
| | 530 | typedef CRITICAL_SECTION vlc_spinlock_t; |
|---|
| | 531 | |
|---|
| | 532 | /** |
|---|
| | 533 | * Initializes a spinlock. |
|---|
| | 534 | */ |
|---|
| | 535 | static inline int vlc_spin_init (vlc_spinlock_t *spin) |
|---|
| | 536 | { |
|---|
| | 537 | return !InitializeCriticalSectionAndSpinCount(spin, 4000); |
|---|
| | 538 | } |
|---|
| | 539 | |
|---|
| | 540 | /** |
|---|
| | 541 | * Acquires a spinlock. |
|---|
| | 542 | */ |
|---|
| | 543 | static inline void vlc_spin_lock (vlc_spinlock_t *spin) |
|---|
| | 544 | { |
|---|
| | 545 | EnterCriticalSection(spin); |
|---|
| | 546 | } |
|---|
| | 547 | |
|---|
| | 548 | /** |
|---|
| | 549 | * Releases a spinlock. |
|---|
| | 550 | */ |
|---|
| | 551 | static inline void vlc_spin_unlock (vlc_spinlock_t *spin) |
|---|
| | 552 | { |
|---|
| | 553 | LeaveCriticalSection(spin); |
|---|
| | 554 | } |
|---|
| | 555 | |
|---|
| | 556 | /** |
|---|
| | 557 | * Deinitializes a spinlock. |
|---|
| | 558 | */ |
|---|
| | 559 | static inline void vlc_spin_destroy (vlc_spinlock_t *spin) |
|---|
| | 560 | { |
|---|
| | 561 | DeleteCriticalSection(spin); |
|---|
| | 562 | } |
|---|
| | 563 | |
|---|
| | 564 | #else |
|---|
| | 565 | |
|---|
| | 566 | /* Fallback to plain mutexes if spinlocks are not available */ |
|---|
| | 567 | typedef vlc_mutex_t vlc_spinlock_t; |
|---|
| | 568 | |
|---|
| | 569 | static inline int vlc_spin_init (vlc_spinlock_t *spin) |
|---|
| | 570 | { |
|---|
| | 571 | return vlc_mutex_init (spin); |
|---|
| | 572 | } |
|---|
| | 573 | |
|---|
| | 574 | # define vlc_spin_lock vlc_mutex_lock |
|---|
| | 575 | # define vlc_spin_unlock vlc_mutex_unlock |
|---|
| | 576 | # define vlc_spin_destroy vlc_mutex_destroy |
|---|
| | 577 | #endif |
|---|
| | 578 | |
|---|
| | 579 | /***************************************************************************** |
|---|
| | 580 | * vlc_thread_create: create a thread |
|---|
| | 581 | *****************************************************************************/ |
|---|
| | 582 | #define vlc_thread_create( P_THIS, PSZ_NAME, FUNC, PRIORITY, WAIT ) \ |
|---|
| | 583 | __vlc_thread_create( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PSZ_NAME, (void * ( * ) ( void * ))FUNC, PRIORITY, WAIT ) |
|---|
| | 584 | |
|---|
| | 585 | /***************************************************************************** |
|---|
| | 586 | * vlc_thread_set_priority: set the priority of the calling thread |
|---|
| | 587 | *****************************************************************************/ |
|---|
| | 588 | #define vlc_thread_set_priority( P_THIS, PRIORITY ) \ |
|---|
| | 589 | __vlc_thread_set_priority( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PRIORITY ) |
|---|
| | 590 | |
|---|
| | 591 | /***************************************************************************** |
|---|
| | 592 | * vlc_thread_ready: tell the parent thread we were successfully spawned |
|---|
| | 593 | *****************************************************************************/ |
|---|
| | 594 | #define vlc_thread_ready( P_THIS ) \ |
|---|
| | 595 | __vlc_thread_ready( VLC_OBJECT(P_THIS) ) |
|---|
| | 596 | |
|---|
| | 597 | /***************************************************************************** |
|---|
| | 598 | * vlc_thread_join: wait until a thread exits |
|---|
| | 599 | *****************************************************************************/ |
|---|
| | 600 | #define vlc_thread_join( P_THIS ) \ |
|---|
| | 601 | __vlc_thread_join( VLC_OBJECT(P_THIS), __FILE__, __LINE__ ) |
|---|