File: gmx_thread.h

package info (click to toggle)
gromacs 4.0.7-3
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 56,760 kB
  • ctags: 28,606
  • sloc: asm: 844,232; ansic: 264,574; sh: 11,691; makefile: 1,755; csh: 702; perl: 685; python: 264
file content (369 lines) | stat: -rw-r--r-- 11,483 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
/* -*- mode: c; tab-width: 4; indent-tabs-mode: n; c-basic-offset: 4 -*- 
*
* $Id$
* 
* This file is part of Gromacs        Copyright (c) 1991-2004
* David van der Spoel, Erik Lindahl, University of Groningen.
*
* 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 2
* of the License, or (at your option) any later version.
*
* To help us fund GROMACS development, we humbly ask that you cite
* the research papers on the package. Check out http://www.gromacs.org
* 
* And Hey:
* Gnomes, ROck Monsters And Chili Sauce
*/
#ifndef _GMX_THREAD_H_
#define _GMX_THREAD_H_

/*! \file gmx_thread.h
 *
 *  @brief Platform-independent multithreading support.
 *
 *  This file provides an portable thread interface very similar to POSIX 
 *  threads, but the actual implementation is sometimes done with inline atomic
 *  operations in assembly for performance. 
 *
 *  In other words, while the naming conventions are very similar to 
 *  pthreads, you should NOT assume that a Gromacs thread type
 *  (thread,mutex,key, etc) is the same as the Pthreads equivalent,
 *  even on platforms where we are using pthreads. For instance, on 
 *  all platforms where it is possible we try to use lower-latency spinlocks
 *  instead of real posix style mutexes.
 *
 *  A key difference compared to pthreads is that you must use dynamic
 *  (instead of static) initialization of all variables by calling a routine.
 *  The reason for this is that static initialization doesn't work for many
 *  other thread libraries, not that we are lazy...
 *  The only type which can be initialized statically is gmx_thread_once_t.
 *  Note that you can only declare variable as a pointer to a mutex 
 *  and not a mutex variable directly. Declare a pointer, and call 
 *  gmx_thread_mutex_create() to get a pointer to a new mutex. Don't forget to
 *  embed it in a function called by gmx_thread_once() if your routine can be
 *  executed by multiple threads...
 */


#include <stdio.h>


#ifdef __cplusplus
extern "C" 
{  
#endif
#if 0
} /* Avoids screwing up auto-indentation */
#endif




/*! \brief Opaque datatype for gromacs thread
 *
 *  Note that in contrast to pthreads you must always work with pointers
 *  to Gromacs threads. This is unfortunately necessary in order to hide the
 *  underlying implementation - we can't let this header file to depend
 *  on config.h since it might be used with a different compiler, or on 
 *  a different system from where Gromacs was compiled.
 */
typedef struct gmx_thread              gmx_thread_t;





/*! \brief Opaque mutex datatype for Gromacs threads
 *
 *  Note that in contrast to pthreads you must always work with pointers
 *  to Gromacs mutexes. This is unfortunately necessary in order to hide the
 *  underlying implementation - we can't let this header file to depend
 *  on config.h since it might be used with a different compiler, or on 
 *  a different system from where Gromacs was compiled.
 */
typedef struct gmx_thread_mutex        gmx_thread_mutex_t;



/*! \brief Opaque mutex datatype for Gromacs threads
 *
 *  Note that in contrast to pthreads you must always work with pointers
 *  to Gromacs threads. This is unfortunately necessary in order to hide the
 *  underlying implementation - we can't let this header file to depend
 *  on config.h since it might be used with a different compiler, or on 
 *  a different system from where Gromacs was compiled.
 */


/*! \brief One-time initialization data for Gromacs thread
 *
 *  This is an opaque datatype which is necessary for gmx_thread_once(),
 *  but since it needs to be initialized statically it must be defined
 *  in the header. You will be sorry if you touch the contents.
 *  Variables of this type should always be initialized statically to
 *  GMX_THREAD_ONCE_INITIALIZER.
 *
 *  This type is used as control data for single-time initialization.
 *  The most common example is a mutex at file scope used when calling 
 *  a non-threadsafe function, e.g. the FFTW initialization routines.
 *  In contrast to pthreads, many thread libraries (think windows) do not
 *  support static initialization of the mutex. This means it needs to be
 *  initialized by the first thread trying to use it, but we must also 
 *  make sure it is only initialized by exactly one thread.
 *
 *  The situation is solved by declaring the mutex statically in the file,
 *  but not initialized. However, you should also declare a static variable
 *  of the gmx_thread_once_t, and initialize it to GMX_THREAD_ONCE_INITIALIZER.
 *
 *  Write a small static routine (no arguments) that initializes your mutex,
 *  and in the routine where you need to use the mutex you first make a call to
 *  gmx_thread_once() with the once control data type and your initialization
 *  routines as arguments.
 */
typedef struct
 {
    int  started; /*!< -1 if nobody has touched it, >=0 when init. started */
    int  done;    /*!<  1 once the initialization is complete, 0 otherwise */
} gmx_thread_once_t;



/*! \brief Statical initializer for gmx_thread_once_t
 *
 *  See the description of the gmx_thread_once_t datatype for instructions
 *  on how to use this. Normally, all variables of that type should be 
 *  initialized statically to this value.
 */
#define GMX_THREAD_ONCE_INITIALIZER     { -1, 0 }




/*! \brief Thread-specific-data handle for Gromacs threads
 *
 *  This handle is used to keep track of thread-local storage.
 *  After it has been initialized with gmx_thread_key_create()
 *  you can use gmx_thread_setspecific() and gmx_thread_getspecific()
 *  to access a pointer which will be private to each thread.
 */
typedef struct gmx_thread_key          gmx_thread_key_t;





/*! \brief Create a new thread
 *
 *  The new thread will call start_routine() with the argument arg.
 *  Please be careful not to change arg after calling this function.
 * 
 *  \param start_routine   The function to call in the new thread
 *  \param arg             Argument to call with
 *  
 *  \return Pointer to a thread identifier, or NULL if an error occured.
 */
gmx_thread_t *
gmx_thread_create   (void *            (*start_routine)(void *),
                     void *              arg);




/*! \brief Wait for a specific thread to finish executing
 *
 *  If the thread has already finished the routine returns immediately.
 *
 *  \param thread      Thread to wait for.
 *  \param value_ptr   Pointer to location where to store pointer to exit value
 *                     from threads that called gmx_thread_exit().
 *  
 *  \return GMX_SUCCESS if the join went ok, or a non-zero error code.
 */
int
gmx_thread_join     (gmx_thread_t *    thread,
                     void **           value_ptr);



/*! \brief Create a new mutex
 *
 *  \return Pointer to the new mutex, NULL if creation failed.
 */
gmx_thread_mutex_t *
gmx_thread_mutex_create(void);




/*! \brief Kill a mutex you no longer need
*
*  Note that this call only frees resources allocated inside the mutex. It
*  does not free the gmx_thread_mutex_t memory area itself if you created it
*  with dynamic memory allocation.
* 
*  \param mtx  Pointer to a mutex variable to get rid of.
*  \return GMX_SUCCESS or a non-zero error code.
*/
int
gmx_thread_mutex_destroy(gmx_thread_mutex_t *mtx);




/*! \brief Wait for exclusive access to a mutex
*
*  This routine does not return until the mutex has been acquired.
*
*  \param mtx  Pointer to the mutex to lock
*  \return GMX_SUCCESS or a non-zero error code.
*/
int
gmx_thread_mutex_lock(gmx_thread_mutex_t *mtx);




/*! \brief Try to lock a mutex, return if busy
 *
 *  This routine always return directly. If the mutex was available and
 *  we successfully locked it we return GMX_SUCCESS, otherwise a non-zero
 *  error code (usually meaning the mutex was already locked).
 *
 *  \param mtx  Pointer to the mutex to try and lock
 *  \return GMX_SUCCESS or a non-zero error code.
 */
int
gmx_thread_mutex_trylock(gmx_thread_mutex_t *mtx);




/*! \brief Release the exclusive access to a mutex
 *
 *  \param mtx  Pointer to the mutex to release
 *  \return GMX_SUCCESS or a non-zero error code.
 */
int
gmx_thread_mutex_unlock(gmx_thread_mutex_t *mtx);




/*! \brief Initialize thread-specific-storage handle
 *
 *  The gmx_thread_key_t handle must always be initialized dynamically with
 *  this routine. If you need to initialize it statically in a file, use the
 *  gmx_thread_once() routine and corresponding data to initialize the 
 *  thread-specific-storage key the first time you access it.
 *
 *  \param  destructor   Routine to call (to free memory of key) when we quit
 *  \return Pointer to the new key, or NULL if an error occured.
 */
gmx_thread_key_t *     
gmx_thread_key_create(void                   (*destructor)(void *));




/*! \brief Delete thread-specific-storage handle
 *
 *  Calling this routine will kill the handle, and invoke the automatic 
 *  destructor routine for each non-NULL value pointed to by key.
 *
 *  \param  key  Handle to the key to get rid off.
 *  \return GMX_SUCCESS or a non-zero error message.
 */
int
gmx_thread_key_delete(gmx_thread_key_t *      key);




/*! \brief Get value for thread-specific-storage in this thread
 *
 *  If it has not yet been set, NULL is returned.
 *  
 *  \param key   Thread-specific-storage handle.
 *  \return Pointer-to-void, the value of the data in this thread.
*/
void *
gmx_thread_getspecific(gmx_thread_key_t *key);



/*! \brief Set value for thread-specific-storage in this thread
 *
 *  \param key     Thread-specific-storage handle.
 *  \param value   What to set the data to (pointer-to-void).
 *  \return GMX_SUCCESS or a non-zero error message.
 */
int
gmx_thread_setspecific(gmx_thread_key_t *key, void *value);



/*! \brief Run the provided routine exactly once
 *
 *  The control data must have been initialized before calling this routine,
 *  but you can do it with the static initialzer GMX_THREAD_ONCE_INIT.
 *
 *  gmx_thread_once() will not return to any of the calling routines until
 *  the initialization function has been completed.
 *
 *  \param once_data     Initialized one-time execution data
 *  \param init_routine  Function to call exactly once
 *  \return GMX_SUCCESS or a non-zero error message.
 */
int
gmx_thread_once(gmx_thread_once_t *     once_data,
                void                    (*init_routine)(void));    




/*! \brief Terminate calling thread
 *
 *  Die voluntarily.
 *
 *  \param value_ptr   Pointer to a return value. Threads waiting for us to
 *                     join them can read this value if they try.
 */
int
gmx_thread_exit(void *      value_ptr);



/*! \brief Ask a thread to exit
 *
 *  This routine tries to end the execution of another thread, but there are
 *  no guarantees it will succeed.
 *
 *  \param thread     Handle to thread we want to see dead.
*  \return GMX_SUCCESS or a non-zero error message.
 */
int
gmx_thread_cancel(gmx_thread_t *    thread);


/*! \brief Lock a file so only one thread can use it
 *
 *  Call this routine before writing to logfiles or standard out, in order
 *  to avoid mixing output from multiple threads.
 */
int
gmx_lockfile(FILE *stream);


/*! \brief Unlock a file (allow other threads to use it)
 *
 *  Call this routine when you finish a write statement to a file, so other
 *  threads can use it again.
 */
int
gmx_unlockfile(FILE *stream);



#endif