/* $Id: thread.c 13 2011-04-20 15:41:43Z mmamonski $ */ /* * PSNC DRMAA 2.0 utilities library * Copyright (C) 2012 Poznan Supercomputing and Networking Center * * 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 3 of the License, or * (at your option) any later version. * * 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, see . */ /** * @file thread.c * Implementation of recursive mutexes for systems without native support * for it. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #ifdef HAVE_GETTID #include #include pid_t gettid(void) { return (pid_t)syscall( __NR_gettid ); } #endif #ifndef lint static char rcsid[] # ifdef __GNUC__ __attribute__ ((unused)) # endif = "$Id: thread.c 13 2011-04-20 15:41:43Z mmamonski $"; #endif void fsd_thread_create( fsd_thread_t *thread, void* (*func)(void*), void *arg ) { int errno_ = 0; errno_ = pthread_create( thread, NULL, func, arg ); if( errno_ ) fsd_exc_raise_sys( errno_ ); } void fsd_thread_join( fsd_thread_t th, void **thread_return ) { int errno_ = 0; errno_ = pthread_join( th, thread_return ); if( errno_ ) fsd_exc_raise_sys( errno_ ); } void fsd_thread_detach( fsd_thread_t th ) { int errno_ = 0; errno_ = pthread_detach( th ); if( errno_ ) fsd_exc_raise_sys( errno_ ); } #if HAVE_RECURSIVE_MUTEXES void fsd_mutex_init( fsd_mutex_t *mutex ) { int errno_ = 0; pthread_mutexattr_t attr; do { errno_ = pthread_mutexattr_init( &attr ); if( errno_ ) break; errno_ = pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE_NP ); if( errno_ ) break; errno_ = pthread_mutex_init( mutex, &attr ); if( errno_ ) break; errno_ = pthread_mutexattr_destroy( &attr ); } while( false ); if( errno_ ) fsd_exc_raise_sys( errno_ ); } void fsd_mutex_destroy( fsd_mutex_t *mutex ) { int errno_ = 0; errno_ = pthread_mutex_destroy( mutex ); if( errno_ ) fsd_exc_raise_sys( errno_ ); } bool fsd_mutex_lock( fsd_mutex_t *mutex ) { int errno_ = 0; errno_ = pthread_mutex_lock( mutex ); if( errno_ ) fsd_exc_raise_sys( errno_ ); return true; } bool fsd_mutex_unlock( fsd_mutex_t *mutex ) { int errno_ = 0; errno_ = pthread_mutex_unlock( mutex ); if( errno_ ) fsd_exc_raise_sys( errno_ ); return false; } bool fsd_mutex_trylock( fsd_mutex_t *mutex ) { int errno_ = 0; errno_ = pthread_mutex_trylock( mutex ); switch( errno_ ) { case 0: return true; case EBUSY: return false; default: fsd_exc_raise_sys( errno_ ); } } int fsd_mutex_unlock_times( fsd_mutex_t *mutex ) { int count = 0; int errno_ = 0; while( errno_ == 0 ) { errno_ = pthread_mutex_unlock( mutex ); if( !errno_ ) count++; } if( errno_ != EPERM || count == 0 ) fsd_exc_raise_sys( errno_ ); return count; } void fsd_cond_init( fsd_cond_t *cond ) { int errno_ = 0; errno_ = pthread_cond_init( cond, NULL ); if( errno_ ) fsd_exc_raise_sys( errno_ ); } void fsd_cond_destroy( fsd_cond_t *cond ) { int errno_ = 0; errno_ = pthread_cond_destroy( cond ); if( errno_ ) fsd_exc_raise_sys( errno_ ); } void fsd_cond_signal( fsd_cond_t *cond ) { int errno_ = 0; errno_ = pthread_cond_signal( cond ); if( errno_ ) fsd_exc_raise_sys( errno_ ); } void fsd_cond_broadcast( fsd_cond_t *cond ) { int errno_ = 0; errno_ = pthread_cond_broadcast( cond ); if( errno_ ) fsd_exc_raise_sys( errno_ ); } void fsd_cond_wait( fsd_cond_t *cond, fsd_mutex_t *mutex ) { int errno_ = 0; errno_ = pthread_cond_wait( cond, mutex ); if( errno_ ) fsd_exc_raise_sys( errno_ ); } bool fsd_cond_timedwait( fsd_cond_t *cond, fsd_mutex_t *mutex, const struct timespec *abstime ) { int errno_ = 0; errno_ = pthread_cond_timedwait( cond, mutex, abstime ); switch( errno_ ) { case 0: return true; case ETIMEDOUT: return false; default: fsd_exc_raise_sys( errno_ ); } } #else /* ! HAVE_RECURSIVE_MUTEXES */ void fsd_mutex_init( fsd_mutex_t *mutex ) { int errno_ = 0; mutex->owner = (pthread_t)-1; mutex->acquired = 0; errno_ = pthread_mutex_init( &mutex->mutex, NULL ); if( errno_ ) fsd_exc_raise_sys( errno_ ); } void fsd_mutex_destroy( fsd_mutex_t *mutex ) { int errno_ = 0; errno_ = pthread_mutex_destroy( &mutex->mutex ); if( errno_ ) fsd_exc_raise_sys( errno_ ); } bool fsd_mutex_lock( fsd_mutex_t *mutex ) { /* Note: The order of checks is significant. */ if( mutex->acquired && pthread_equal( mutex->owner, pthread_self() ) ) mutex->acquired ++; else { int errno_ = 0; errno_ = pthread_mutex_lock( &mutex->mutex ); if( errno_ == 0 ) { mutex->owner = pthread_self(); mutex->acquired = 1; } else fsd_exc_raise_sys( errno_ ); } return true; } bool fsd_mutex_unlock( fsd_mutex_t *mutex ) { fsd_assert( mutex->acquired && pthread_equal( mutex->owner, pthread_self() ) ); if( -- (mutex->acquired) == 0 ) { int errno_ = 0; errno_ = pthread_mutex_unlock( &mutex->mutex ); if( errno_ ) fsd_exc_raise_sys( errno_ ); } return false; } bool fsd_mutex_trylock( fsd_mutex_t *mutex ) { if( mutex->acquired && pthread_equal( mutex->owner, pthread_self() ) ) { mutex->acquired ++; return true; } else { int errno_ = 0; errno_ = pthread_mutex_trylock( &mutex->mutex ); switch( errno_ ) { case 0: mutex->owner = pthread_self(); mutex->acquired = 1; return true; case ETIMEDOUT: return false; default: fsd_exc_raise_sys( errno_ ); } } } int fsd_mutex_unlock_times( fsd_mutex_t *mutex ) { int errno_ = 0; int count = 0; fsd_assert( mutex->acquired && pthread_equal( mutex->owner, pthread_self() ) ); count = mutex->acquired; mutex->acquired = 0; errno_ = pthread_mutex_unlock( &mutex->mutex ); if( errno_ ) fsd_exc_raise_sys( errno_ ); return count; } void fsd_cond_init( fsd_cond_t *cond ) { int errno_ = 0; errno_ = pthread_cond_init( cond, NULL ); if( errno_ ) fsd_exc_raise_sys( errno_ ); } void fsd_cond_destroy( fsd_cond_t *cond ) { int errno_ = 0; errno_ = pthread_cond_destroy( cond ); if( errno_ ) fsd_exc_raise_sys( errno_ ); } void fsd_cond_signal( fsd_cond_t *cond ) { int errno_ = 0; errno_ = pthread_cond_signal( cond ); if( errno_ ) fsd_exc_raise_sys( errno_ ); } void fsd_cond_broadcast( fsd_cond_t *cond ) { int errno_ = 0; errno_ = pthread_cond_broadcast( cond ); if( errno_ ) fsd_exc_raise_sys( errno_ ); } void fsd_cond_wait( fsd_cond_t *cond, fsd_mutex_t *mutex ) { int errno_ = 0; int acquired_save = mutex->acquired; fsd_assert( mutex->acquired && pthread_equal( mutex->owner, pthread_self() ) ); errno_ = pthread_cond_wait( cond, &mutex->mutex ); if( errno_ == 0 ) { mutex->owner = pthread_self(); mutex->acquired = acquired_save; } else fsd_exc_raise_sys( errno_ ); } bool fsd_cond_timedwait( fsd_cond_t *cond, fsd_mutex_t *mutex, const struct timespec *abstime ) { int errno_ = 0; int acquired_save = mutex->acquired; fsd_assert( mutex->acquired && pthread_equal( mutex->owner, pthread_self() ) ); errno_ = pthread_cond_timedwait( cond, &mutex->mutex, abstime ); switch( errno_ ) { case 0: mutex->owner = pthread_self(); mutex->acquired = acquired_save; return true; case ETIMEDOUT: mutex->owner = pthread_self(); mutex->acquired = acquired_save; return false; default: fsd_exc_raise_sys( errno_ ); } } #endif /* ! HAVE_RECURSIVE_MUTEXES */ int fsd_thread_id(void) { #if HAVE_GETTID /* * On Linux 2.6 (with NPTL) getpid() returns * same value for all threads in single process. */ return (int)gettid(); #else return (int)getpid(); #endif }