2 This source code file is part of thread_mpi.
3 Written by Sander Pronk, Erik Lindahl, and possibly others.
5 Copyright (c) 2009, Sander Pronk, Erik Lindahl.
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are met:
10 1) Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2) Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 3) Neither the name of the copyright holders nor the
16 names of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY US ''AS IS'' AND ANY
20 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 DISCLAIMED. IN NO EVENT SHALL WE BE LIABLE FOR ANY
23 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 If you want to redistribute modifications, please consider that
31 scientific software is very special. Version control is crucial -
32 bugs must be traceable. We will be happy to consider code for
33 inclusion in the official distribution, but derived work should not
34 be called official thread_mpi. Details are found in the README & COPYING
40 /* Include the defines that determine which thread library to use.
41 * We do not use HAVE_PTHREAD_H directly, since we might want to
42 * turn off thread support explicity (e.g. for debugging).
44 #ifdef HAVE_TMPI_CONFIG_H
45 #include "tmpi_config.h"
53 #ifdef THREAD_PTHREADS
55 #ifdef HAVE_PTHREAD_SETAFFINITY
59 /* pthread.h must be the first header, apart from the defines in config.h */
73 #include "thread_mpi/atomic.h"
74 #include "thread_mpi/threads.h"
81 /* mutex for initializing mutexes */
82 static pthread_mutex_t mutex_init = PTHREAD_MUTEX_INITIALIZER;
83 /* mutex for initializing barriers */
84 static pthread_mutex_t once_init = PTHREAD_MUTEX_INITIALIZER;
85 /* mutex for initializing thread_conds */
86 static pthread_mutex_t cond_init = PTHREAD_MUTEX_INITIALIZER;
87 /* mutex for initializing barriers */
88 static pthread_mutex_t barrier_init = PTHREAD_MUTEX_INITIALIZER;
90 /* mutex for managing thread IDs */
91 static pthread_mutex_t thread_id_mutex = PTHREAD_MUTEX_INITIALIZER;
92 static pthread_key_t thread_id_key;
93 static int thread_id_key_initialized = 0;
98 enum tMPI_Thread_support tMPI_Thread_support(void)
100 return TMPI_THREAD_SUPPORT_YES;
104 int tMPI_Thread_get_hw_number(void)
108 #if defined(_SC_NPROCESSORS_ONLN)
109 ret = sysconf(_SC_NPROCESSORS_ONLN);
110 #elif defined(_SC_NPROC_ONLN)
111 ret = sysconf(_SC_NPROC_ONLN);
112 #elif defined(_SC_NPROCESSORS_CONF)
113 ret = sysconf(_SC_NPROCESSORS_CONF);
114 #elif defined(_SC_NPROC_CONF)
115 ret = sysconf(_SC_NPROC_CONF);
122 /* destructor for thread ids */
123 static void tMPI_Destroy_thread_id(void* thread_id)
125 struct tMPI_Thread *thread = (struct tMPI_Thread*)thread_id;
126 if (!thread->started_by_tmpi)
128 /* if the thread is started by tMPI, it must be freed in the join()
135 /* Set the thread id var for this thread
136 Returns a pointer to the thread object if succesful, NULL if ENOMEM */
137 static struct tMPI_Thread* tMPI_Set_thread_id_key(int started_by_tmpi)
139 struct tMPI_Thread *th;
141 th = (struct tMPI_Thread*)malloc(sizeof(struct tMPI_Thread)*1);
146 th->th = pthread_self();
147 th->started_by_tmpi = started_by_tmpi;
148 /* we ignore errors because any thread that needs this value will
149 re-generate it in the next iteration. */
150 pthread_setspecific(thread_id_key, th);
154 /* initialize the thread id vars if not already initialized */
155 static int tMPI_Init_thread_ids(void)
158 ret = pthread_mutex_lock( &thread_id_mutex );
164 if (!thread_id_key_initialized)
166 /* initialize and set the thread id thread-specific variable */
167 struct tMPI_Thread *th;
169 thread_id_key_initialized = 1;
170 ret = pthread_key_create(&thread_id_key, tMPI_Destroy_thread_id);
175 th = tMPI_Set_thread_id_key(0);
183 ret = pthread_mutex_unlock( &thread_id_mutex );
186 pthread_mutex_unlock( &thread_id_mutex );
190 /* structure to hold the arguments for the thread_starter function */
191 struct tMPI_Thread_starter
193 struct tMPI_Thread *thread;
194 void *(*start_routine)(void*);
196 pthread_mutex_t cond_lock; /* lock for initialization of thread
200 /* the thread_starter function that sets the thread id */
201 static void *tMPI_Thread_starter(void *arg)
203 struct tMPI_Thread_starter *starter = (struct tMPI_Thread_starter *)arg;
204 void *(*start_routine)(void*);
208 /* first wait for the parent thread to signal that the starter->thread
209 structure is ready. That's done by unlocking the starter->cond_lock */
210 ret = pthread_mutex_lock(&(starter->cond_lock));
215 ret = pthread_mutex_unlock(&(starter->cond_lock));
221 /* now remember the tMPI_thread_t structure for this thread */
222 ret = pthread_setspecific(thread_id_key, starter->thread);
227 start_routine = starter->start_routine;
230 /* deallocate the starter structure. Errors here are non-fatal. */
231 pthread_mutex_destroy(&(starter->cond_lock));
233 return (*start_routine)(parg);
236 int tMPI_Thread_create(tMPI_Thread_t *thread, void *(*start_routine)(void *),
240 struct tMPI_Thread_starter *starter;
246 tMPI_Init_thread_ids();
248 *thread = (struct tMPI_Thread*)malloc(sizeof(struct tMPI_Thread)*1);
253 (*thread)->started_by_tmpi = 1;
254 starter = (struct tMPI_Thread_starter*)
255 malloc(sizeof(struct tMPI_Thread_starter)*1);
260 /* fill the starter structure */
261 starter->thread = *thread;
262 starter->start_routine = start_routine;
265 ret = pthread_mutex_init(&(starter->cond_lock), NULL);
270 /* now lock the mutex so we can unlock it once we know the data in
271 thread->th is safe. */
272 ret = pthread_mutex_lock(&(starter->cond_lock));
278 ret = pthread_create(&((*thread)->th), NULL, tMPI_Thread_starter,
285 /* Here we know thread->th is safe. */
286 ret = pthread_mutex_unlock(&(starter->cond_lock));
293 int tMPI_Thread_join(tMPI_Thread_t thread, void **value_ptr)
296 pthread_t th = thread->th;
298 ret = pthread_join( th, value_ptr );
308 tMPI_Thread_t tMPI_Thread_self(void)
313 /* make sure the key var is set */
314 ret = tMPI_Init_thread_ids();
320 th = pthread_getspecific(thread_id_key);
322 /* check if it is already in our list */
325 th = tMPI_Set_thread_id_key(0);
330 int tMPI_Thread_equal(tMPI_Thread_t t1, tMPI_Thread_t t2)
332 return pthread_equal(t1->th, t2->th);
336 enum tMPI_Thread_setaffinity_support tMPI_Thread_setaffinity_support(void)
338 #ifdef HAVE_PTHREAD_SETAFFINITY
342 /* run getaffinity to check whether we get back ENOSYS */
343 ret = pthread_getaffinity_np(pthread_self(), sizeof(set), &set);
346 return TMPI_SETAFFINITY_SUPPORT_YES;
350 return TMPI_SETAFFINITY_SUPPORT_NO;
353 return TMPI_SETAFFINITY_SUPPORT_NO;
358 /* set thread's own affinity to a processor number n */
359 int tMPI_Thread_setaffinity_single(tMPI_Thread_t thread, unsigned int nr)
361 #ifdef HAVE_PTHREAD_SETAFFINITY
362 int nt = tMPI_Thread_get_hw_number();
367 return TMPI_ERR_PROCNR;
372 return pthread_setaffinity_np(thread->th, sizeof(set), &set);
380 int tMPI_Thread_mutex_init(tMPI_Thread_mutex_t *mtx)
389 mtx->mutex = (struct tMPI_Mutex*)malloc(sizeof(struct tMPI_Mutex)*1);
390 if (mtx->mutex == NULL)
394 ret = pthread_mutex_init(&(mtx->mutex->mtx), NULL);
400 #ifndef TMPI_NO_ATOMICS
401 tMPI_Atomic_set(&(mtx->initialized), 1);
403 mtx->initialized.value = 1;
408 static inline int tMPI_Thread_mutex_init_once(tMPI_Thread_mutex_t *mtx)
412 #ifndef TMPI_NO_ATOMICS
413 /* check whether the mutex is initialized */
414 if (tMPI_Atomic_get( &(mtx->initialized) ) == 0)
417 /* we're relying on the memory barrier semantics of mutex_lock/unlock
418 for the check preceding this function call to have worked */
419 ret = pthread_mutex_lock( &(mutex_init) );
425 if (mtx->mutex == NULL)
427 mtx->mutex = (struct tMPI_Mutex*)malloc(sizeof(struct tMPI_Mutex));
428 if (mtx->mutex == NULL)
433 ret = pthread_mutex_init( &(mtx->mutex->mtx), NULL);
440 ret = pthread_mutex_unlock( &(mutex_init) );
443 pthread_mutex_unlock( &(mutex_init) );
448 int tMPI_Thread_mutex_destroy(tMPI_Thread_mutex_t *mtx)
457 ret = pthread_mutex_destroy( &(mtx->mutex->mtx) );
468 int tMPI_Thread_mutex_lock(tMPI_Thread_mutex_t *mtx)
472 /* check whether the mutex is initialized */
473 ret = tMPI_Thread_mutex_init_once(mtx);
479 ret = pthread_mutex_lock(&(mtx->mutex->mtx));
486 int tMPI_Thread_mutex_trylock(tMPI_Thread_mutex_t *mtx)
490 /* check whether the mutex is initialized */
491 ret = tMPI_Thread_mutex_init_once(mtx);
497 ret = pthread_mutex_trylock(&(mtx->mutex->mtx));
503 int tMPI_Thread_mutex_unlock(tMPI_Thread_mutex_t *mtx)
507 /* check whether the mutex is initialized */
508 ret = tMPI_Thread_mutex_init_once(mtx);
514 ret = pthread_mutex_unlock(&(mtx->mutex->mtx));
520 int tMPI_Thread_key_create(tMPI_Thread_key_t *key, void (*destructor)(void *))
530 key->key = (struct tMPI_Thread_key*)malloc(sizeof(struct
532 if (key->key == NULL)
536 ret = pthread_key_create(&((key)->key->pkey), destructor);
542 tMPI_Atomic_set(&(key->initialized), 1);
547 int tMPI_Thread_key_delete(tMPI_Thread_key_t key)
551 ret = pthread_key_delete((key.key->pkey));
563 void * tMPI_Thread_getspecific(tMPI_Thread_key_t key)
567 p = pthread_getspecific((key.key->pkey));
573 int tMPI_Thread_setspecific(tMPI_Thread_key_t key, void *value)
577 ret = pthread_setspecific((key.key->pkey), value);
583 int tMPI_Thread_once(tMPI_Thread_once_t *once_control,
584 void (*init_routine)(void))
587 if (!once_control || !init_routine)
592 /* really ugly hack - and it's slow... */
593 ret = pthread_mutex_lock( &once_init );
598 if (tMPI_Atomic_get(&(once_control->once)) == 0)
601 tMPI_Atomic_set(&(once_control->once), 1);
603 ret = pthread_mutex_unlock( &once_init );
611 int tMPI_Thread_cond_init(tMPI_Thread_cond_t *cond)
620 cond->condp = (struct tMPI_Thread_cond*)malloc(
621 sizeof(struct tMPI_Thread_cond));
622 if (cond->condp == NULL)
627 ret = pthread_cond_init(&(cond->condp->cond), NULL);
632 tMPI_Atomic_set(&(cond->initialized), 1);
633 tMPI_Atomic_memory_barrier();
639 static int tMPI_Thread_cond_init_once(tMPI_Thread_cond_t *cond)
643 /* we're relying on the memory barrier semantics of mutex_lock/unlock
644 for the check preceding this function call to have worked */
645 ret = pthread_mutex_lock( &(cond_init) );
650 if (cond->condp == NULL)
652 cond->condp = (struct tMPI_Thread_cond*)
653 malloc(sizeof(struct tMPI_Thread_cond)*1);
654 if (cond->condp == NULL)
659 ret = pthread_cond_init( &(cond->condp->cond), NULL);
665 ret = pthread_mutex_unlock( &(cond_init) );
668 /* try to unlock anyway */
669 pthread_mutex_unlock( &(cond_init) );
675 int tMPI_Thread_cond_destroy(tMPI_Thread_cond_t *cond)
684 ret = pthread_cond_destroy(&(cond->condp->cond));
695 int tMPI_Thread_cond_wait(tMPI_Thread_cond_t *cond, tMPI_Thread_mutex_t *mtx)
699 /* check whether the condition is initialized */
700 if (tMPI_Atomic_get( &(cond->initialized) ) == 0)
702 ret = tMPI_Thread_cond_init_once(cond);
708 /* the mutex must have been initialized because it should be locked here */
710 ret = pthread_cond_wait( &(cond->condp->cond), &(mtx->mutex->mtx) );
718 int tMPI_Thread_cond_signal(tMPI_Thread_cond_t *cond)
722 /* check whether the condition is initialized */
723 if (tMPI_Atomic_get( &(cond->initialized) ) == 0)
725 ret = tMPI_Thread_cond_init_once(cond);
732 ret = pthread_cond_signal( &(cond->condp->cond) );
739 int tMPI_Thread_cond_broadcast(tMPI_Thread_cond_t *cond)
743 /* check whether the condition is initialized */
744 if (tMPI_Atomic_get( &(cond->initialized) ) == 0)
746 ret = tMPI_Thread_cond_init_once(cond);
753 ret = pthread_cond_broadcast( &(cond->condp->cond) );
761 void tMPI_Thread_exit(void *value_ptr)
763 pthread_exit(value_ptr);
767 int tMPI_Thread_cancel(tMPI_Thread_t thread)
769 return pthread_cancel(thread->th);
775 int tMPI_Thread_barrier_init(tMPI_Thread_barrier_t *barrier, int n)
778 /*tMPI_Thread_pthread_barrier_t *p;*/
785 barrier->barrierp = (struct tMPI_Thread_barrier*)
786 malloc(sizeof(struct tMPI_Thread_barrier)*1);
787 if (barrier->barrierp == NULL)
792 ret = pthread_mutex_init(&(barrier->barrierp->mutex), NULL);
798 ret = pthread_cond_init(&(barrier->barrierp->cv), NULL);
804 barrier->threshold = n;
808 tMPI_Atomic_set(&(barrier->initialized), 1);
812 static int tMPI_Thread_barrier_init_once(tMPI_Thread_barrier_t *barrier)
816 /* we're relying on the memory barrier semantics of mutex_lock/unlock
817 for the check preceding this function call to have worked */
818 ret = pthread_mutex_lock( &(barrier_init) );
824 if (barrier->barrierp == NULL)
826 barrier->barrierp = (struct tMPI_Thread_barrier*)
827 malloc(sizeof(struct tMPI_Thread_barrier)*1);
828 if (barrier->barrierp == NULL)
834 ret = pthread_mutex_init(&(barrier->barrierp->mutex), NULL);
841 ret = pthread_cond_init(&(barrier->barrierp->cv), NULL);
848 ret = pthread_mutex_unlock( &(barrier_init) );
851 pthread_mutex_unlock( &(barrier_init) );
858 int tMPI_Thread_barrier_destroy(tMPI_Thread_barrier_t *barrier)
867 ret = pthread_mutex_destroy(&(barrier->barrierp->mutex));
872 ret = pthread_cond_destroy(&(barrier->barrierp->cv));
878 free(barrier->barrierp);
884 int tMPI_Thread_barrier_wait(tMPI_Thread_barrier_t * barrier)
889 /* check whether the barrier is initialized */
890 if (tMPI_Atomic_get( &(barrier->initialized) ) == 0)
892 tMPI_Thread_barrier_init_once(barrier);
896 ret = pthread_mutex_lock(&barrier->barrierp->mutex);
902 cycle = barrier->cycle;
904 /* Decrement the count atomically and check if it is zero.
905 * This will only be true for the last thread calling us.
907 if (--barrier->count <= 0)
909 barrier->cycle = !barrier->cycle;
910 barrier->count = barrier->threshold;
911 ret = pthread_cond_broadcast(&barrier->barrierp->cv);
920 while (cycle == barrier->cycle)
922 ret = pthread_cond_wait(&barrier->barrierp->cv,
923 &barrier->barrierp->mutex);
931 ret = pthread_mutex_unlock(&barrier->barrierp->mutex);
934 pthread_mutex_unlock(&barrier->barrierp->mutex);
941 /* just to have some symbols */
942 int tMPI_Thread_pthreads = 0;
944 #endif /* THREAD_PTHREADS */