/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
/*
* (C) 2001 by Argonne National Laboratory.
* See COPYRIGHT in top-level directory.
*/
#if !defined(MPIU_THREAD_PRIV_H_INCLUDED)
#define MPIU_THREAD_PRIV_H_INCLUDED
/* The following three macros define a way to portably access thread-private
storage in MPICH, and avoid extra overhead when MPICH is single
threaded
INITKEY - Create the key. Must happen *before* the other threads
are created
INIT - Create the thread-private storage. Must happen once per thread
DECL - Declare local variables
GET - Access the thread-private storage
FIELD - Access the thread-private field (by name)
FINALIZE - to be invoked when all threads no longer need access to the thread
local storage, such as at MPI_Finalize time
The "DECL" is the extern so that there is always a statement for
the declaration.
*/
#if !defined(MPICH_TLS_SPECIFIER)
/* We need to provide a function that will cleanup the storage attached
* to the key. */
void MPIUI_Cleanup_tls(void *a);
/* In the case where the thread level is set in MPI_Init_thread, we
need a blended version of the non-threaded and the thread-multiple
definitions.
The approach is to have TWO MPIUI_Per_thread_t pointers. One is local
(The MPIU_THREADPRIV_DECL is used in the routines local definitions),
as in the threaded version of these macros. This is set by using a routine
to get thread-private storage. The second is a preallocated, extern
MPIUI_Per_thread_t struct, as in the single threaded case. Based on
MPIR_Process.isThreaded, one or the other is used.
*/
/* For the single threaded case, we use a preallocated structure
This structure is allocated in src/mpi/init/initthread.c */
extern MPIUI_Per_thread_t MPIUI_ThreadSingle;
#define MPIU_THREADPRIV_INITKEY \
do { \
if (MPIR_ThreadInfo.isThreaded) { \
int initkey_err_; \
MPIU_Thread_tls_create(MPIUI_Cleanup_tls,&MPIR_ThreadInfo.thread_storage,&initkey_err_); \
MPIU_Assert(initkey_err_ == 0); \
} \
} while (0)
#define MPIU_THREADPRIV_INIT \
do { \
if (MPIR_ThreadInfo.isThreaded) { \
int init_err_; \
MPIUI_Thread_ptr = (MPIUI_Per_thread_t *) MPIU_Calloc(1, sizeof(MPIUI_Per_thread_t)); \
MPIU_Assert(MPIUI_Thread_ptr); \
MPIU_Thread_tls_set(&MPIR_ThreadInfo.thread_storage, (void *)MPIUI_Thread_ptr, &init_err_); \
MPIU_Assert(init_err_ == 0); \
} \
} while (0)
#define MPIU_THREADPRIV_GET \
do { \
if (!MPIUI_Thread_ptr) { \
if (MPIR_ThreadInfo.isThreaded) { \
int get_err_; \
MPIU_Thread_tls_get(&MPIR_ThreadInfo.thread_storage, (void **) &MPIUI_Thread_ptr, &get_err_); \
MPIU_Assert(get_err_ == 0); \
if (!MPIUI_Thread_ptr) { \
MPIU_THREADPRIV_INIT; /* subtle, sets MPIUI_Thread_ptr */ \
} \
} \
else { \
MPIUI_Thread_ptr = &MPIUI_ThreadSingle; \
} \
MPIU_Assert(MPIUI_Thread_ptr); \
} \
} while (0)
/* common definitions when using MPIU_Thread-based TLS */
#define MPIU_THREADPRIV_DECL MPIUI_Per_thread_t *MPIUI_Thread_ptr = NULL
#define MPIU_THREADPRIV_FIELD(a_) (MPIUI_Thread_ptr->a_)
#define MPIU_THREADPRIV_FINALIZE \
do { \
MPIU_THREADPRIV_DECL; \
if (MPIR_ThreadInfo.isThreaded) { \
int tpf_err_; /* unique name to not conflict with vars in called macros */ \
MPIU_THREADPRIV_GET; \
MPIU_Free(MPIUI_Thread_ptr); \
MPIU_Thread_tls_set(&MPIR_ThreadInfo.thread_storage,NULL, &tpf_err_); \
MPIU_Assert(tpf_err_ == 0); \
MPIU_Thread_tls_destroy(&MPIR_ThreadInfo.thread_storage,&tpf_err_); \
MPIU_Assert(tpf_err_ == 0); \
} \
} while (0)
#else /* defined(MPICH_TLS_SPECIFIER) */
/* We have proper thread-local storage (TLS) support from the compiler, which
* should yield the best performance and simplest code, so we'll use that. */
extern MPICH_TLS_SPECIFIER MPIUI_Per_thread_t MPIUI_Thread;
#define MPIU_THREADPRIV_INITKEY
#define MPIU_THREADPRIV_INIT
#define MPIU_THREADPRIV_DECL
#define MPIU_THREADPRIV_GET
#define MPIU_THREADPRIV_FIELD(a_) (MPIUI_Thread.a_)
#define MPIU_THREADPRIV_FINALIZE do {} while (0)
#endif /* defined(MPICH_TLS_SPECIFIER) */
#endif /* !defined(MPIU_THREAD_PRIV_H_INCLUDED) */