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
|