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.
46 /* Hide this implementation from Doxygen, since it conflicts with pthreads */
49 #if ! (defined(THREAD_PTHREADS) || defined(THREAD_WINDOWS))
51 #include "thread_mpi/thread.h"
62 #include "tMPI_Fatal_error.h"
64 /* Number of thread-specific storage elements.
66 * It might seem stupid to make the length constant instead of dynamic,
67 * but e.g. the Pthreads standard only guarantees 128 key entries, so for
68 * portability we shouldn't use more.
70 #define TMPI_THREAD_NOTHREADS_NSPECIFICDATA 128
74 * Static variables used to keep track of thread-private data
75 * when we are compiling without thread support. This is actually quite
76 * simple - we just keep a list of structures with the value (pointer)
82 int used
; /*!< 1 if this element is used, 0 if it is free */
83 void * value
; /*!< Pointer to the specific data for key n */
84 void (*destructor
)(void *); /*!< Pointer to destructor function for key n */
86 tMPI_Thread_nothreads_specificdata
[TMPI_THREAD_NOTHREADS_NSPECIFICDATA
];
89 /*! \brief flag to determine if static key storage has been initialized.
92 tMPI_Thread_nothreads_specific_init_done
= 0;
96 /* Dummy implementation of abstract thread datatype */
99 int locked
; /* Just useful for debugging */
105 /* Dummy implementation of abstract thread-specific data key type */
106 struct tMPI_Thread_key
108 int index
; /*!< Index into our static list of private data */
114 enum tMPI_Thread_support
115 tMPI_Thread_support(void)
117 return TMPI_THREAD_SUPPORT_NO
;
123 tMPI_Thread_create (tMPI_Thread_t
* thread
,
124 void * (*start_routine
)(void *),
127 tMPI_Fatal_error(FARGS
,"Cannot start threads without thread support.\n");
135 tMPI_Thread_join (tMPI_Thread_t thread
,
138 tMPI_Fatal_error(FARGS
,"Cannot join threads without thread support.\n");
147 tMPI_Thread_mutex_init(tMPI_Thread_mutex_t
*mtx
)
154 /* We use an integer as a mutex for debugging. */
155 mtx
->actual_mutex
= malloc(sizeof(int));
157 if(mtx
->actual_mutex
==NULL
)
160 "error [%s, line %d]: Failed to allocate mutex memory.\n",
166 * ( (int *) (mtx
->actual_mutex
) ) = 0; /* Unlocked */
168 mtx
->status
= TMPI_THREAD_ONCE_STATUS_READY
;
176 tMPI_Thread_mutex_destroy(tMPI_Thread_mutex_t
*mtx
)
183 /* Must use system free() since memory allocation depends on
184 * messages and threads working.
186 free(mtx
->actual_mutex
);
195 tMPI_Thread_mutex_init_once(tMPI_Thread_mutex_t
*mtx
)
198 /* No threads = nothing to worry about */
199 if(mtx
->status
!= TMPI_THREAD_ONCE_STATUS_READY
)
200 rc
= tMPI_Thread_mutex_init(mtx
);
210 tMPI_Thread_mutex_lock(tMPI_Thread_mutex_t
*mtx
)
212 /* Ccheck whether this mutex is initialized */
213 if(mtx
->status
!= TMPI_THREAD_ONCE_STATUS_READY
)
215 tMPI_Thread_mutex_init_once(mtx
);
218 /* The mutex is now guaranteed to be valid. */
219 * ( (int *) (mtx
->actual_mutex
) ) = 1;
228 tMPI_Thread_mutex_trylock(tMPI_Thread_mutex_t
*mtx
)
233 /* Ccheck whether this mutex is initialized */
234 if(mtx
->status
!= TMPI_THREAD_ONCE_STATUS_READY
)
236 tMPI_Thread_mutex_init_once(mtx
);
239 p
= (int *) (mtx
->actual_mutex
);
257 tMPI_Thread_mutex_unlock(tMPI_Thread_mutex_t
*mtx
)
259 * ( (int *) (mtx
->actual_mutex
) ) = 0; /* Unlocked */
267 tMPI_Thread_key_create(tMPI_Thread_key_t
* key
,
268 void (*destructor
)(void *))
275 "error [%s, line %d]: Invalid key pointer.\n",
282 * Allocate memory for the pthread key. We must use the system malloc
283 * here since the other memory allocation depends on tMPI_Thread.h.
285 *key
= malloc(sizeof(struct tMPI_Thread_key
));
290 "error [%s, line %d]: Failed to allocate thread key memory.\n",
296 if( tMPI_Thread_nothreads_specific_init_done
== 0)
299 for(i
=0;i
<TMPI_THREAD_NOTHREADS_NSPECIFICDATA
;i
++)
301 tMPI_Thread_nothreads_specificdata
[i
].used
= 0;
302 tMPI_Thread_nothreads_specificdata
[i
].value
= NULL
;
303 tMPI_Thread_nothreads_specificdata
[i
].destructor
= NULL
;
306 tMPI_Thread_nothreads_specific_init_done
= 1;
309 /* Try to find an empty spot */
310 for(i
=0;i
<TMPI_THREAD_NOTHREADS_NSPECIFICDATA
;i
++)
312 if(tMPI_Thread_nothreads_specificdata
[i
].used
== 0)
316 if(i
==TMPI_THREAD_NOTHREADS_NSPECIFICDATA
)
318 tMPI_Fatal_error(FARGS
,"Already used all %d private data keys.\n");
322 tMPI_Thread_nothreads_specificdata
[i
].used
= 1;
330 tMPI_Thread_key_delete(tMPI_Thread_key_t key
)
334 void (*destructor
)(void *);
336 if ( tMPI_Thread_nothreads_specific_init_done
== 0 || key
== NULL
)
343 if(tMPI_Thread_nothreads_specificdata
[i
].value
!= NULL
)
345 destructor
= tMPI_Thread_nothreads_specificdata
[i
].destructor
;
346 value
= tMPI_Thread_nothreads_specificdata
[i
].value
;
347 (*destructor
)(value
);
358 tMPI_Thread_getspecific(tMPI_Thread_key_t key
)
360 if ( tMPI_Thread_nothreads_specific_init_done
== 0 || key
== NULL
)
365 return tMPI_Thread_nothreads_specificdata
[key
->index
].value
;
370 tMPI_Thread_setspecific(tMPI_Thread_key_t key
,
374 if ( tMPI_Thread_nothreads_specific_init_done
== 0 || key
== NULL
)
379 tMPI_Thread_nothreads_specificdata
[key
->index
].value
= value
;
387 tMPI_Thread_once(tMPI_Thread_once_t
* once_control
,
388 void (*init_routine
)(void))
390 if(once_control
->status
!= TMPI_THREAD_ONCE_STATUS_READY
)
393 once_control
->status
= TMPI_THREAD_ONCE_STATUS_READY
;
404 tMPI_Thread_cond_init(tMPI_Thread_cond_t
* cond
)
408 /* Condition variables are completely useless without threads, since
409 * we cannot wait for some signal to happen if we are the only thread
412 * Still, as long as we don't try to call the wait routine it won't hurt,
413 * and we want the contents to be clean for debugging.
415 cond
->actual_cond
= NULL
;
416 cond
->status
= TMPI_THREAD_ONCE_STATUS_READY
;
423 tMPI_Thread_cond_destroy(tMPI_Thread_cond_t
* cond
)
437 tMPI_Thread_cond_init_once(tMPI_Thread_cond_t
* cond
)
439 /* No threads = nothing to worry about */
440 if(cond
->status
!= TMPI_THREAD_ONCE_STATUS_READY
)
441 return tMPI_Thread_cond_init(cond
);
447 tMPI_Thread_cond_wait(tMPI_Thread_cond_t
* cond
,
448 tMPI_Thread_mutex_t
* mtx
)
450 tMPI_Fatal_error(FARGS
,"Called tMPI_Thread_cond_wait() without thread support. This is a major\n"
451 "error, since nobody else can signal the condition variable - exiting.\n");
460 tMPI_Thread_cond_broadcast(tMPI_Thread_cond_t
* cond
)
462 tMPI_Fatal_error(FARGS
,"Called tMPI_Thread_broadcast() without thread support.\n");
471 tMPI_Thread_exit(void * value_ptr
)
473 tMPI_Fatal_error(FARGS
,"Called tMPI_Thread_exit() without thread support.\n");
480 tMPI_Thread_cancel(tMPI_Thread_t thread
)
482 tMPI_Fatal_error(FARGS
,"Called tMPI_Thread_cancel() without thread support.\n");
490 tMPI_Thread_barrier_init(tMPI_Thread_barrier_t
* barrier
,
493 /* Barriers don't do anything without multiple threads */
499 tMPI_Thread_barrier_destroy(tMPI_Thread_barrier_t
* barrier
)
501 /* Barriers don't do anything without multiple threads */
507 tMPI_Thread_barrier_wait(tMPI_Thread_barrier_t
* barrier
)
509 /* Barriers don't do anything without multiple threads.
510 * Since we are the only thread we're the master!
519 tMPI_lockfile(FILE * stream
)
521 /* Nothing to worry about without threads */
527 tMPI_unlockfile(FILE * stream
)
529 /* Nothing to worry about without threads */
536 #endif /* ifndef DOXYGEN */
538 #endif /* no threads */