Home | History | Annotate | Line # | Download | only in src
      1 /* MPFR internal header related to thread-local variables.
      2 
      3 Copyright 2005-2023 Free Software Foundation, Inc.
      4 Contributed by the AriC and Caramba projects, INRIA.
      5 
      6 This file is part of the GNU MPFR Library.
      7 
      8 The GNU MPFR Library is free software; you can redistribute it and/or modify
      9 it under the terms of the GNU Lesser General Public License as published by
     10 the Free Software Foundation; either version 3 of the License, or (at your
     11 option) any later version.
     12 
     13 The GNU MPFR Library is distributed in the hope that it will be useful, but
     14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     15 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
     16 License for more details.
     17 
     18 You should have received a copy of the GNU Lesser General Public License
     19 along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
     20 https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
     21 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
     22 
     23 #ifndef __MPFR_THREAD_H__
     24 #define __MPFR_THREAD_H__
     25 
     26 /* Note: MPFR_NEED_THREAD_LOCK shall be defined before including this
     27    header */
     28 
     29 /* Note: Let's define MPFR_THREAD_ATTR even after a #error to make the
     30    error message more visible (e.g. gcc doesn't immediately stop after
     31    the #error line and outputs many error messages if MPFR_THREAD_ATTR
     32    is not defined). But some compilers will just output a message and
     33    may build MPFR "successfully" (without thread support). */
     34 #ifndef MPFR_THREAD_ATTR
     35 # ifdef MPFR_USE_THREAD_SAFE
     36 #  if defined(_MSC_VER)
     37 #   define MPFR_THREAD_ATTR __declspec( thread )
     38 #  elif defined(MPFR_USE_C11_THREAD_SAFE)
     39 #   define MPFR_THREAD_ATTR _Thread_local
     40 #  else
     41 #   define MPFR_THREAD_ATTR __thread
     42 #  endif
     43 # else
     44 #  define MPFR_THREAD_ATTR
     45 # endif
     46 #endif
     47 
     48 /* If MPFR needs a lock mechanism for thread synchro */
     49 #ifdef MPFR_NEED_THREAD_LOCK
     50 
     51 /**************************************************************************/
     52 /**************************************************************************/
     53 /*                           ISO C11 version                              */
     54 /**************************************************************************/
     55 /**************************************************************************/
     56 
     57 #if defined (MPFR_HAVE_C11_LOCK)
     58 /* NOTE: This version has not been completely tested */
     59 
     60 #define MPFR_THREAD_LOCK_METHOD "C11"
     61 
     62 #include <threads.h>
     63 
     64 #define MPFR_LOCK_DECL(_lock)                   \
     65   mtx_t _lock;
     66 
     67 #define MPFR_LOCK_C(E)                                  \
     68   do {                                                  \
     69     if ((E) != thrd_success)                            \
     70       {                                                 \
     71         fprintf (stderr, "MPFR lock failure\n");        \
     72         abort ();                                       \
     73       }                                                 \
     74   } while (0)
     75 
     76 #define MPFR_LOCK_INIT(_lock)    MPFR_LOCK_C(mtx_init(&(_lock), mtx_plain))
     77 #define MPFR_LOCK_CLEAR(_lock)   do { mtx_destroy(&(_lock)); } while (0)
     78 #define MPFR_LOCK_READ(_lock)    MPFR_LOCK_C(mtx_lock(&(_lock)))
     79 #define MPFR_UNLOCK_READ(_lock)  MPFR_LOCK_C(mtx_unlock(&(_lock)))
     80 #define MPFR_LOCK_WRITE(_lock)   MPFR_LOCK_C(mtx_lock(&(_lock)))
     81 #define MPFR_UNLOCK_WRITE(_lock) MPFR_LOCK_C(mtx_unlock(&(_lock)))
     82 
     83 #define MPFR_LOCK_READ2WRITE(_lock) do {} while (0)
     84 #define MPFR_LOCK_WRITE2READ(_lock) do {} while (0)
     85 
     86 #define MPFR_ONCE_DECL(_once)                   \
     87   once_flag _once;
     88 
     89 #define MPFR_ONCE_INIT_VALUE ONCE_FLAG_INIT
     90 
     91 #define MPFR_ONCE_CALL(_once, _func) do {               \
     92     call_once(&(_once), (_func));                       \
     93   } while (0)
     94 
     95 #define MPFR_NEED_DEFERRED_INIT 1
     96 
     97 
     98 /**************************************************************************/
     99 /**************************************************************************/
    100 /*                           POSIX   version                              */
    101 /**************************************************************************/
    102 /**************************************************************************/
    103 
    104 #elif defined (HAVE_PTHREAD)
    105 
    106 #define MPFR_THREAD_LOCK_METHOD "pthread"
    107 
    108 #include <pthread.h>
    109 
    110 #define MPFR_LOCK_DECL(_lock)                   \
    111   pthread_rwlock_t _lock;
    112 
    113 #define MPFR_LOCK_C(E)                                  \
    114   do {                                                  \
    115     if ((E) != 0)                                       \
    116       {                                                 \
    117         fprintf (stderr, "MPFR lock failure\n");        \
    118         abort ();                                       \
    119       }                                                 \
    120   } while (0)
    121 
    122 #define MPFR_LOCK_INIT(_lock) MPFR_LOCK_C(pthread_rwlock_init(&(_lock), NULL))
    123 
    124 #define MPFR_LOCK_CLEAR(_lock) do {                     \
    125     pthread_rwlock_destroy(&(_lock));                   \
    126   } while (0)
    127 
    128 #define MPFR_LOCK_READ(_lock)    MPFR_LOCK_C(pthread_rwlock_rdlock(&(_lock)))
    129 #define MPFR_UNLOCK_READ(_lock)  MPFR_LOCK_C(pthread_rwlock_unlock(&(_lock)))
    130 #define MPFR_LOCK_WRITE(_lock)   MPFR_LOCK_C(pthread_rwlock_wrlock(&(_lock)))
    131 #define MPFR_UNLOCK_WRITE(_lock) MPFR_LOCK_C(pthread_rwlock_unlock(&(_lock)))
    132 
    133 #define MPFR_LOCK_READ2WRITE(_lock) do {                        \
    134     MPFR_UNLOCK_READ(_lock);                                    \
    135     MPFR_LOCK_WRITE(_lock);                                     \
    136   } while (0)
    137 
    138 #define MPFR_LOCK_WRITE2READ(_lock) do {                         \
    139   MPFR_UNLOCK_WRITE(_lock);                                      \
    140   MPFR_LOCK_READ(_lock);                                         \
    141   } while (0)
    142 
    143 #define MPFR_ONCE_DECL(_once)                   \
    144   pthread_once_t _once ;
    145 
    146 #define MPFR_ONCE_INIT_VALUE PTHREAD_ONCE_INIT
    147 
    148 #define MPFR_ONCE_CALL(_once, _func) \
    149   MPFR_LOCK_C(pthread_once (&(_once), (_func)))
    150 
    151 #define MPFR_NEED_DEFERRED_INIT 1
    152 
    153 #else
    154 
    155 /* TODO: Win32 */
    156 # error "No thread lock / unsupported OS."
    157 
    158 #endif
    159 
    160 #else
    161 
    162 /**************************************************************************/
    163 /**************************************************************************/
    164 /*                       No lock thread version                           */
    165 /**************************************************************************/
    166 /**************************************************************************/
    167 
    168 #define MPFR_LOCK_DECL(_lock)
    169 #define MPFR_LOCK_INIT(_lock)       do {} while (0)
    170 #define MPFR_LOCK_CLEAR(_lock)      do {} while (0)
    171 #define MPFR_LOCK_READ(_lock)       do {} while (0)
    172 #define MPFR_UNLOCK_READ(_lock)     do {} while (0)
    173 #define MPFR_LOCK_WRITE(_lock)      do {} while (0)
    174 #define MPFR_UNLOCK_WRITE(_lock)    do {} while (0)
    175 #define MPFR_LOCK_READ2WRITE(_lock) do {} while (0)
    176 #define MPFR_LOCK_WRITE2READ(_lock) do {} while (0)
    177 #define MPFR_ONCE_INIT_VALUE
    178 #define MPFR_ONCE_DECL(_once)
    179 #define MPFR_ONCE_CALL(_once,_func) do {} while (0)
    180 
    181 #endif
    182 
    183 
    184 
    185 /**************************************************************************/
    186 /**************************************************************************/
    187 
    188 /**************************************************************************/
    189 /**************************************************************************/
    190 
    191 /* If MPFR Needs a way to init data before using them */
    192 #if defined(MPFR_NEED_DEFERRED_INIT)
    193 
    194 #if defined(MPFR_HAVE_CONSTRUCTOR_ATTR)
    195 
    196 /*********************** Use constructor extension ************************/
    197 #define MPFR_DEFERRED_INIT_MASTER_DECL(_id, _init, _clear)              \
    198   __attribute__ ((constructor)) static void                             \
    199   mpfr_init_cache_ ## _id (void)        {                               \
    200     _init ;                                                             \
    201   }                                                                     \
    202   __attribute__ ((destructor)) static void                              \
    203   mpfr_clean_cache_ ## _id (void)       {                               \
    204     _clear;                                                             \
    205   }
    206 
    207 #define MPFR_DEFERRED_INIT_CALL(_master) do {} while (0)
    208 #define MPFR_DEFERRED_INIT_SLAVE_DECL()
    209 #define MPFR_DEFERRED_INIT_SLAVE_VALUE(_id)
    210 
    211 #else
    212 
    213 /**************************** Use once semantic ***************************/
    214 #define MPFR_DEFERRED_INIT_MASTER_DECL(_id, _init, _clear)       \
    215   static void mpfr_once_ ## _id ## _clear_func (void) {          \
    216     _clear ;                                                     \
    217   }                                                              \
    218   static void mpfr_once_ ## _id ## _init_func (void) {           \
    219     _init;                                                       \
    220     atexit(mpfr_once_ ## _id ## _clear_func);                    \
    221   }
    222 
    223 #define MPFR_DEFERRED_INIT_CALL(_master)                \
    224   MPFR_ONCE_CALL((_master)->once, (_master)->init_once)
    225 
    226 #define MPFR_DEFERRED_INIT_SLAVE_DECL()                         \
    227   MPFR_ONCE_DECL(once)                                          \
    228   void (*init_once)(void);
    229 
    230 #define MPFR_DEFERRED_INIT_SLAVE_VALUE(_id)                     \
    231   , MPFR_ONCE_INIT_VALUE, mpfr_once_ ## _id ## _init_func
    232 
    233 #endif
    234 
    235 #else
    236 
    237 /* No need */
    238 #define MPFR_DEFERRED_INIT_MASTER_DECL(_id_lock, _init, _clear)
    239 #define MPFR_DEFERRED_INIT_CALL(_master) do {} while (0)
    240 #define MPFR_DEFERRED_INIT_SLAVE_DECL()
    241 #define MPFR_DEFERRED_INIT_SLAVE_VALUE(_id)
    242 
    243 #endif
    244 
    245 /**************************************************************************/
    246 
    247 #endif
    248