/* MPFR internal header related to thread-local variables. Copyright 2005-2021 Free Software Foundation, Inc. Contributed by the AriC and Caramba projects, INRIA. This file is part of the GNU MPFR Library. The GNU MPFR Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. The GNU MPFR Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __MPFR_THREAD_H__ #define __MPFR_THREAD_H__ /* Note: MPFR_NEED_THREAD_LOCK shall be defined before including this header */ /* Note: Let's define MPFR_THREAD_ATTR even after a #error to make the error message more visible (e.g. gcc doesn't immediately stop after the #error line and outputs many error messages if MPFR_THREAD_ATTR is not defined). But some compilers will just output a message and may build MPFR "successfully" (without thread support). */ #ifndef MPFR_THREAD_ATTR # ifdef MPFR_USE_THREAD_SAFE # if defined(_MSC_VER) # define MPFR_THREAD_ATTR __declspec( thread ) # elif defined(MPFR_USE_C11_THREAD_SAFE) # define MPFR_THREAD_ATTR _Thread_local # else # define MPFR_THREAD_ATTR __thread # endif # else # define MPFR_THREAD_ATTR # endif #endif /* If MPFR needs a lock mechanism for thread synchro */ #ifdef MPFR_NEED_THREAD_LOCK /**************************************************************************/ /**************************************************************************/ /* ISO C11 version */ /**************************************************************************/ /**************************************************************************/ #if defined (MPFR_HAVE_C11_LOCK) /* NOTE: This version has not been completely tested */ #define MPFR_THREAD_LOCK_METHOD "C11" #include #define MPFR_LOCK_DECL(_lock) \ mtx_t _lock; #define MPFR_LOCK_C(E) \ do { \ if ((E) != thrd_success) \ abort (); \ } while (0) #define MPFR_LOCK_INIT(_lock) MPFR_LOCK_C(mtx_init(&(_lock), mtx_plain)) #define MPFR_LOCK_CLEAR(_lock) do { mtx_destroy(&(_lock)); } while (0) #define MPFR_LOCK_READ(_lock) MPFR_LOCK_C(mtx_lock(&(_lock))) #define MPFR_UNLOCK_READ(_lock) MPFR_LOCK_C(mtx_unlock(&(_lock))) #define MPFR_LOCK_WRITE(_lock) MPFR_LOCK_C(mtx_lock(&(_lock))) #define MPFR_UNLOCK_WRITE(_lock) MPFR_LOCK_C(mtx_unlock(&(_lock))) #define MPFR_LOCK_READ2WRITE(_lock) do {} while (0) #define MPFR_LOCK_WRITE2READ(_lock) do {} while (0) #define MPFR_ONCE_DECL(_once) \ once_flag _once; #define MPFR_ONCE_INIT_VALUE ONCE_FLAG_INIT #define MPFR_ONCE_CALL(_once, _func) do { \ call_once(&(_once), (_func)); \ } while (0) #define MPFR_NEED_DEFERRED_INIT 1 /**************************************************************************/ /**************************************************************************/ /* POSIX version */ /**************************************************************************/ /**************************************************************************/ #elif defined (HAVE_PTHREAD) #define MPFR_THREAD_LOCK_METHOD "pthread" #include #define MPFR_LOCK_DECL(_lock) \ pthread_rwlock_t _lock; #define MPFR_LOCK_C(E) \ do { \ if ((E) != 0) \ abort (); \ } while (0) #define MPFR_LOCK_INIT(_lock) MPFR_LOCK_C(pthread_rwlock_init(&(_lock), NULL)) #define MPFR_LOCK_CLEAR(_lock) do { \ pthread_rwlock_destroy(&(_lock)); \ } while (0) #define MPFR_LOCK_READ(_lock) MPFR_LOCK_C(pthread_rwlock_rdlock(&(_lock))) #define MPFR_UNLOCK_READ(_lock) MPFR_LOCK_C(pthread_rwlock_unlock(&(_lock))) #define MPFR_LOCK_WRITE(_lock) MPFR_LOCK_C(pthread_rwlock_wrlock(&(_lock))) #define MPFR_UNLOCK_WRITE(_lock) MPFR_LOCK_C(pthread_rwlock_unlock(&(_lock))) #define MPFR_LOCK_READ2WRITE(_lock) do { \ MPFR_UNLOCK_READ(_lock); \ MPFR_LOCK_WRITE(_lock); \ } while (0) #define MPFR_LOCK_WRITE2READ(_lock) do { \ MPFR_UNLOCK_WRITE(_lock); \ MPFR_LOCK_READ(_lock); \ } while (0) #define MPFR_ONCE_DECL(_once) \ pthread_once_t _once ; #define MPFR_ONCE_INIT_VALUE PTHREAD_ONCE_INIT #define MPFR_ONCE_CALL(_once, _func) \ MPFR_LOCK_C(pthread_once (&(_once), (_func))) #define MPFR_NEED_DEFERRED_INIT 1 #else /* TODO: Win32 */ # error "No thread lock / unsupported OS." #endif #else /**************************************************************************/ /**************************************************************************/ /* No lock thread version */ /**************************************************************************/ /**************************************************************************/ #define MPFR_LOCK_DECL(_lock) #define MPFR_LOCK_INIT(_lock) do {} while (0) #define MPFR_LOCK_CLEAR(_lock) do {} while (0) #define MPFR_LOCK_READ(_lock) do {} while (0) #define MPFR_UNLOCK_READ(_lock) do {} while (0) #define MPFR_LOCK_WRITE(_lock) do {} while (0) #define MPFR_UNLOCK_WRITE(_lock) do {} while (0) #define MPFR_LOCK_READ2WRITE(_lock) do {} while (0) #define MPFR_LOCK_WRITE2READ(_lock) do {} while (0) #define MPFR_ONCE_INIT_VALUE #define MPFR_ONCE_DECL(_once) #define MPFR_ONCE_CALL(_once,_func) do {} while (0) #endif /**************************************************************************/ /**************************************************************************/ /**************************************************************************/ /**************************************************************************/ /* If MPFR Needs a way to init data before using them */ #if defined(MPFR_NEED_DEFERRED_INIT) #if defined(MPFR_HAVE_CONSTRUCTOR_ATTR) /*********************** Use constructor extension ************************/ #define MPFR_DEFERRED_INIT_MASTER_DECL(_id, _init, _clear) \ __attribute__ ((constructor)) static void \ mpfr_init_cache_ ## _id (void) { \ _init ; \ } \ __attribute__ ((destructor)) static void \ mpfr_clean_cache_ ## _id (void) { \ _clear; \ } #define MPFR_DEFERRED_INIT_CALL(_master) do {} while (0) #define MPFR_DEFERRED_INIT_SLAVE_DECL() #define MPFR_DEFERRED_INIT_SLAVE_VALUE(_id) #else /**************************** Use once semantic ***************************/ #define MPFR_DEFERRED_INIT_MASTER_DECL(_id, _init, _clear) \ static void mpfr_once_ ## _id ## _clear_func (void) { \ _clear ; \ } \ static void mpfr_once_ ## _id ## _init_func (void) { \ _init; \ atexit(mpfr_once_ ## _id ## _clear_func); \ } #define MPFR_DEFERRED_INIT_CALL(_master) \ MPFR_ONCE_CALL((_master)->once, (_master)->init_once) #define MPFR_DEFERRED_INIT_SLAVE_DECL() \ MPFR_ONCE_DECL(once) \ void (*init_once)(void); #define MPFR_DEFERRED_INIT_SLAVE_VALUE(_id) \ , MPFR_ONCE_INIT_VALUE, mpfr_once_ ## _id ## _init_func #endif #else /* No need */ #define MPFR_DEFERRED_INIT_MASTER_DECL(_id_lock, _init, _clear) #define MPFR_DEFERRED_INIT_CALL(_master) do {} while (0) #define MPFR_DEFERRED_INIT_SLAVE_DECL() #define MPFR_DEFERRED_INIT_SLAVE_VALUE(_id) #endif /**************************************************************************/ #endif