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
37 To help us fund development, we humbly ask that you cite
38 any papers on the package - you can find them in the top README file.
44 /* Include the defines that determine which thread library to use.
45 * We do not use HAVE_PTHREAD_H directly, since we might want to
46 * turn off thread support explicity (e.g. for debugging).
54 /* the win32 header */
64 #include "thread_mpi/threads.h"
66 /*! \brief System mutex for all one-time initialization
68 * This static variable is necessary in order to make the header file
69 * independent of the thread library implementation. Anyway, it
70 * will only be locked a handful of times at the start of program execution.
72 enum tMPI_Thread_once_status tMPI_Thread_system_lock_state=
73 TMPI_THREAD_ONCE_STATUS_NOTCALLED;
74 static CRITICAL_SECTION tMPI_Thread_system_lock;
78 void tMPI_Fatal_error(const char *file, int line, const char *message, ...)
82 fprintf(stderr, "tMPI Fatal error in %s, line %d: ", file, line);
83 va_start(ap, message);
84 vfprintf(stderr, message, ap);
92 enum tMPI_Thread_support tMPI_Thread_support(void)
94 return TMPI_THREAD_SUPPORT_YES;
97 struct tMPI_Thread_starter_param
99 void *(*start_routine)(void*); /* the function */
100 void *param; /* its parameter */
103 static DWORD WINAPI tMPI_Win32_thread_starter( LPVOID lpParam )
105 struct tMPI_Thread_starter_param *prm=
106 (struct tMPI_Thread_starter_param*)lpParam;
108 (prm->start_routine)(prm->param);
113 int tMPI_Thread_create(tMPI_Thread_t *thread,
114 void *(*start_routine)(void *), void *arg)
117 struct tMPI_Thread_starter_param *prm;
119 /* a small memory leak to be sure that it doesn't get deallocated
120 once this function ends */
121 prm=malloc(sizeof(struct tMPI_Thread_starter_param));
122 prm->start_routine= start_routine;
127 tMPI_Fatal_error(TMPI_FARGS,"Invalid thread pointer.");
131 *thread = CreateThread( NULL, 0, tMPI_Win32_thread_starter, prm, 0, &thread_id);
135 tMPI_Fatal_error(TMPI_FARGS,"Failed to create thread, error code=%d",
145 int tMPI_Thread_join(tMPI_Thread_t thread, void **value_ptr)
149 ret = WaitForSingleObject(thread, INFINITE);
153 tMPI_Fatal_error(TMPI_FARGS,"Failed to join thread. error code=%d",
160 if (!GetExitCodeThread(thread, &retval))
162 /* TODO: somehow assign value_ptr */
163 tMPI_Fatal_error(TMPI_FARGS,"Failed to get thread exit code: error=%d",
174 void tMPI_Thread_exit(void *value_ptr)
176 /* TODO: fix exit code */
177 /* TODO: call destructors for thread-local storage */
184 int tMPI_Thread_cancel(tMPI_Thread_t thread)
186 if (!TerminateThread( thread, -1) )
188 tMPI_Fatal_error(TMPI_FARGS,"Failed thread_cancel, error code=%d",
198 int tMPI_Thread_mutex_init(tMPI_Thread_mutex_t *mtx)
205 InitializeCriticalSection(&(mtx->cs));
206 mtx->init_state = TMPI_THREAD_ONCE_STATUS_READY;
212 int tMPI_Thread_mutex_destroy(tMPI_Thread_mutex_t *mtx)
219 DeleteCriticalSection(&(mtx->cs));
227 static int tMPI_Thread_mutex_init_once(tMPI_Thread_mutex_t *mtx)
231 /* This is essentially a copy of the code from the one-time
232 * initialization, but with a call to the mutex init routine instead.
233 * It might seem like overkill, but it will only be executed the first
234 * time you call a static mutex, and it is important to get all the
235 * memory barriers right. Trust me, you don't want a deadlock here...
238 /* Lock the common one-time init mutex so we can check carefully */
239 EnterCriticalSection( &tMPI_Thread_system_lock );
243 /* If somebody is already initializing, wait until he is finished.
244 * In that case, the mutex will also be unlocked.
246 while (mtx->status == TMPI_THREAD_ONCE_STATUS_PROGRESS)
247 pthread_cond_wait (&tMPI_Thread_pthreads_system_cond,
248 &tMPI_Thread_pthreads_system_mtx);
251 /* Do the actual (locked) check - system mutex is locked if we get here */
252 if (mtx->init_state != TMPI_THREAD_ONCE_STATUS_READY)
254 /*mtx->status = TMPI_THREAD_ONCE_STATUS_PROGRESS;*/
256 /* No need to keep the lock during execution -
257 * Only one thread can do it anyway.
259 /*pthread_mutex_unlock (&tMPI_Thread_pthreads_system_mtx);*/
260 ret=tMPI_Thread_mutex_init(mtx);
261 /*pthread_mutex_lock (&tMPI_Thread_pthreads_system_mtx);*/
263 /* Status will be marked as ready by tMPI_Thread_mutex_init(). */
264 /*pthread_cond_broadcast (&tMPI_Thread_pthreads_system_cond);*/
271 LeaveCriticalSection( &tMPI_Thread_system_lock );
278 int tMPI_Thread_mutex_lock(tMPI_Thread_mutex_t *mtx)
280 /* Ccheck whether this mutex is initialized */
281 if(mtx->init_state != TMPI_THREAD_ONCE_STATUS_READY)
283 tMPI_Thread_mutex_init_once(mtx);
286 /* The mutex is now guaranteed to be valid. */
287 EnterCriticalSection( &(mtx->cs) );
295 int tMPI_Thread_mutex_trylock(tMPI_Thread_mutex_t *mtx)
299 /* Ccheck whether this mutex is initialized */
300 if(mtx->init_state != TMPI_THREAD_ONCE_STATUS_READY)
302 tMPI_Thread_mutex_init_once(mtx);
305 /* The mutex is now guaranteed to be valid. */
306 ret=TryEnterCriticalSection( &(mtx->cs) );
313 int tMPI_Thread_mutex_unlock(tMPI_Thread_mutex_t *mtx)
315 LeaveCriticalSection( &(mtx->cs) );
322 int tMPI_Thread_key_create(tMPI_Thread_key_t *key, void (*destructor)(void *))
326 tMPI_Fatal_error(TMPI_FARGS,"Invalid key pointer.");
331 /* TODO: make list of destructors for thread-local storage */
334 if ( *key == TLS_OUT_OF_INDEXES )
336 tMPI_Fatal_error(TMPI_FARGS,"Failed to create thread key, error code=%d.",
345 int tMPI_Thread_key_delete(tMPI_Thread_key_t key)
354 void * tMPI_Thread_getspecific(tMPI_Thread_key_t key)
364 int tMPI_Thread_setspecific(tMPI_Thread_key_t key, void *value)
368 ret = TlsSetValue(key, value);
374 static BOOL CALLBACK InitHandleWrapperFunction(PINIT_ONCE InitOnce,
378 void (*fn)(void)=Parameter;
386 int tMPI_Thread_once(tMPI_Thread_once_t *once_control,
387 void (*init_routine)(void))
390 bStatus = InitOnceExecuteOnce(once_control, InitHandleWrapperFunction,
395 tMPI_Fatal_error(TMPI_FARGS,"Failed to run thread_once routine");
406 int tMPI_Thread_cond_init(tMPI_Thread_cond_t *cond)
413 InitializeConditionVariable( &(cond->cv) );
414 cond->init_state=TMPI_THREAD_ONCE_STATUS_READY;
419 int tMPI_Thread_cond_destroy(tMPI_Thread_cond_t *cond)
421 /* windows doesnt have this function */
428 /*! \brief Static init routine for pthread barrier
432 * This is only used as a wrapper to enable static initialization
433 * of posix thread types together with out abstraction layer for tMPI_Thread.h
435 * \param cond Condition variable, must be statically initialized
437 * \return status - 0 on success, or a standard error code.
439 static int tMPI_Thread_cond_init_once(tMPI_Thread_cond_t *cond)
443 /* This is essentially a copy of the code from the one-time
444 * initialization, but with a call to the cond init routine instead.
445 * It might seem like overkill, but it will only be executed the first
446 * time you call a static condition variable, and it is important to get
447 * the memory barriers right. Trust me, you don't want a deadlock here...
449 /* Lock the common one-time init mutex so we can check carefully */
450 EnterCriticalSection( &tMPI_Thread_system_lock );
451 /* Do the actual (locked) check - system mutex is locked if we get here */
452 if (cond->init_state != TMPI_THREAD_ONCE_STATUS_READY)
454 ret=tMPI_Thread_cond_init(cond);
460 LeaveCriticalSection( &tMPI_Thread_system_lock );
467 int tMPI_Thread_cond_wait(tMPI_Thread_cond_t *cond, tMPI_Thread_mutex_t *mtx)
471 /* Ccheck whether this condition variable is initialized */
472 if(cond->init_state != TMPI_THREAD_ONCE_STATUS_READY)
474 tMPI_Thread_cond_init_once(cond);
476 if(mtx->init_state != TMPI_THREAD_ONCE_STATUS_READY)
478 tMPI_Thread_mutex_init_once(mtx);
481 ret=SleepConditionVariableCS (&(cond->cv), &(mtx->cs), INFINITE);
485 tMPI_Fatal_error(TMPI_FARGS,"Failed wait for condition, error code=%d",
496 int tMPI_Thread_cond_signal(tMPI_Thread_cond_t *cond)
498 /* Ccheck whether this condition variable is initialized */
499 if(cond->init_state != TMPI_THREAD_ONCE_STATUS_READY)
501 tMPI_Thread_cond_init_once(cond);
503 /* The condition variable is now guaranteed to be valid. */
504 WakeConditionVariable( &(cond->cv) );
511 int tMPI_Thread_cond_broadcast(tMPI_Thread_cond_t *cond)
513 /* Ccheck whether this condition variable is initialized */
514 if(cond->init_state != TMPI_THREAD_ONCE_STATUS_READY)
516 tMPI_Thread_cond_init_once(cond);
518 /* The condition variable is now guaranteed to be valid. */
519 WakeAllConditionVariable( &(cond->cv) );
527 int tMPI_Thread_barrier_init(tMPI_Thread_barrier_t *barrier, int n)
534 InitializeCriticalSection(&(barrier->cs));
535 InitializeConditionVariable(&(barrier->cv));
537 barrier->threshold = n;
541 barrier->init_state = TMPI_THREAD_ONCE_STATUS_READY;
548 int tMPI_Thread_barrier_destroy(tMPI_Thread_barrier_t *barrier)
556 DeleteCriticalSection(&(barrier->cs));
563 /*! \brief Static init routine for pthread barrier
567 * This is only used as a wrapper to enable static initialization
568 * of posix thread types together with out abstraction layer for tMPI_Thread.h
570 * \param barrier Statically initialized barrier type
571 * \param n Number of members in barrier
573 * \return status - 0 on success, or a standard error code.
575 static int tMPI_Thread_barrier_init_once(tMPI_Thread_barrier_t *barrier, int n)
579 /* This is essentially a copy of the code from the one-time
580 * initialization, but with a call to the cond init routine instead.
581 * It might seem like overkill, but it will only be executed the first
582 * time you call a static condition variable, and it is important to get
583 * the memory barriers right. Trust me, you don't want a deadlock here...
585 /* Lock the common one-time init mutex so we can check carefully */
586 EnterCriticalSection( &tMPI_Thread_system_lock );
587 /* Do the actual (locked) check - system mutex is locked if we get here */
588 if (barrier->init_state != TMPI_THREAD_ONCE_STATUS_READY)
590 ret=tMPI_Thread_barrier_init(barrier, n);
596 LeaveCriticalSection( &tMPI_Thread_system_lock );
603 int tMPI_Thread_barrier_wait(tMPI_Thread_barrier_t *barrier)
608 /*tMPI_Thread_pthread_barrier_t *p;*/
610 if(barrier->init_state != TMPI_THREAD_ONCE_STATUS_READY)
612 tMPI_Thread_barrier_init_once(barrier,barrier->threshold);
615 /*p = (tMPI_Thread_pthread_barrier_t*)barrier->actual_barrier;*/
617 EnterCriticalSection( &(barrier->cs) );
621 cycle = barrier->cycle;
623 /* Decrement the count atomically and check if it is zero.
624 * This will only be true for the last thread calling us.
626 if( --(barrier->count) <= 0 )
628 barrier->cycle = !barrier->cycle;
629 barrier->count = barrier->threshold;
631 WakeAllConditionVariable( &(barrier->cv) );
635 while(cycle == barrier->cycle)
637 rc=SleepConditionVariableCS (&(barrier->cv), &(barrier->cs),
647 LeaveCriticalSection( &(barrier->cs) );
653 void tMPI_lockfile(FILE *stream)
655 /* flockfile(stream);*/
656 /* TODO: implement this */
660 void tMPI_unlockfile(FILE *stream)
662 /* funlockfile(stream);*/
663 /* TODO: implement this */
666 #endif /* THREAD_WIN32 */