1/* MPFR internal header related to thread-local variables.
2
3Copyright 2005-2023 Free Software Foundation, Inc.
4Contributed by the AriC and Caramba projects, INRIA.
5
6This file is part of the GNU MPFR Library.
7
8The GNU MPFR Library is free software; you can redistribute it and/or modify
9it under the terms of the GNU Lesser General Public License as published by
10the Free Software Foundation; either version 3 of the License, or (at your
11option) any later version.
12
13The GNU MPFR Library is distributed in the hope that it will be useful, but
14WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16License for more details.
17
18You should have received a copy of the GNU Lesser General Public License
19along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
20https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
2151 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