~ubuntu-branches/ubuntu/trusty/erlang/trusty

« back to all changes in this revision

Viewing changes to erts/include/internal/ethread.h

  • Committer: Bazaar Package Importer
  • Author(s): Clint Byrum
  • Date: 2011-05-05 15:48:43 UTC
  • mfrom: (3.5.13 sid)
  • Revision ID: james.westby@ubuntu.com-20110505154843-0om6ekzg6m7ugj27
Tags: 1:14.b.2-dfsg-3ubuntu1
* Merge from debian unstable.  Remaining changes:
  - Drop libwxgtk2.8-dev build dependency. Wx isn't in main, and not
    supposed to.
  - Drop erlang-wx binary.
  - Drop erlang-wx dependency from -megaco, -common-test, and -reltool, they
    do not really need wx. Also drop it from -debugger; the GUI needs wx,
    but it apparently has CLI bits as well, and is also needed by -megaco,
    so let's keep the package for now.
  - debian/patches/series: Do what I meant, and enable build-options.patch
    instead.
* Additional changes:
  - Drop erlang-wx from -et
* Dropped Changes:
  - patches/pcre-crash.patch: CVE-2008-2371: outer level option with
    alternatives caused crash. (Applied Upstream)
  - fix for ssl certificate verification in newSSL: 
    ssl_cacertfile_fix.patch (Applied Upstream)
  - debian/patches/series: Enable native.patch again, to get stripped beam
    files and reduce the package size again. (build-options is what
    actually accomplished this)
  - Remove build-options.patch on advice from upstream and because it caused
    odd build failures.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * %CopyrightBegin%
3
 
 * 
4
 
 * Copyright Ericsson AB 2004-2009. All Rights Reserved.
5
 
 * 
 
3
 *
 
4
 * Copyright Ericsson AB 2004-2010. All Rights Reserved.
 
5
 *
6
6
 * The contents of this file are subject to the Erlang Public License,
7
7
 * Version 1.1, (the "License"); you may not use this file except in
8
8
 * compliance with the License. You should have received a copy of the
9
9
 * Erlang Public License along with this software. If not, it can be
10
10
 * retrieved online at http://www.erlang.org/.
11
 
 * 
 
11
 *
12
12
 * Software distributed under the License is distributed on an "AS IS"
13
13
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
14
14
 * the License for the specific language governing rights and limitations
15
15
 * under the License.
16
 
 * 
 
16
 *
17
17
 * %CopyrightEnd%
18
18
 */
19
19
 
33
33
#include <stdlib.h>
34
34
#include "erl_errno.h"
35
35
 
36
 
/*
37
 
 * Extra memory barrier requirements:
38
 
 * - ethr_atomic_or_old() needs to enforce a memory barrier sufficient
39
 
 *   for a lock operation.
40
 
 * - ethr_atomic_and_old() needs to enforce a memory barrier sufficient
41
 
 *   for an unlock operation.
42
 
 * - ethr_atomic_cmpxchg() needs to enforce a memory barrier sufficient
43
 
 *   for a lock and unlock operation.
44
 
 */
45
 
 
46
 
 
47
 
#undef ETHR_USE_RWMTX_FALLBACK
48
36
#undef ETHR_HAVE_OPTIMIZED_ATOMIC_OPS
49
 
#undef ETHR_HAVE_OPTIMIZED_LOCKS
50
 
 
51
 
typedef struct {
52
 
    long tv_sec;
53
 
    long tv_nsec;
54
 
} ethr_timeval;
 
37
#undef ETHR_HAVE_OPTIMIZED_SPINLOCK
 
38
#undef ETHR_HAVE_OPTIMIZED_RWSPINLOCK
55
39
 
56
40
#if defined(DEBUG)
 
41
#  define ETHR_DEBUG
 
42
#endif
 
43
 
 
44
#if defined(ETHR_DEBUG)
57
45
#  undef ETHR_XCHK
58
46
#  define  ETHR_XCHK 1
59
47
#else
68
56
#elif defined(__WIN32__)
69
57
#  define ETHR_INLINE __forceinline
70
58
#endif
71
 
#if defined(DEBUG) || !defined(ETHR_INLINE) || ETHR_XCHK \
 
59
#if defined(ETHR_DEBUG) || !defined(ETHR_INLINE) || ETHR_XCHK \
72
60
    || (defined(__GNUC__) && defined(ERTS_MIXED_CYGWIN_VC))
73
61
#  undef ETHR_INLINE
74
62
#  define ETHR_INLINE 
75
63
#  undef ETHR_TRY_INLINE_FUNCS
76
64
#endif
77
 
#ifdef ETHR_FORCE_INLINE_FUNCS
78
 
#  define ETHR_TRY_INLINE_FUNCS
79
 
#endif
80
65
 
81
 
#if !defined(ETHR_DISABLE_NATIVE_IMPLS) \
82
 
    && (defined(PURIFY) || defined(VALGRIND) || defined(ERTS_MIXED_CYGWIN_VC))
 
66
#if !defined(ETHR_DISABLE_NATIVE_IMPLS) && (defined(PURIFY)||defined(VALGRIND))
83
67
#  define ETHR_DISABLE_NATIVE_IMPLS
84
68
#endif
85
69
 
86
 
#define ETHR_RWMUTEX_INITIALIZED        0x99999999
87
 
#define ETHR_MUTEX_INITIALIZED          0x77777777
88
 
#define ETHR_COND_INITIALIZED           0x55555555
89
 
 
90
 
#define ETHR_CACHE_LINE_SIZE 64
91
 
 
92
 
#ifdef ETHR_INLINE_FUNC_NAME_
93
 
#  define ETHR_CUSTOM_INLINE_FUNC_NAME_
94
 
#else
 
70
/* Assume 64-byte cache line size */
 
71
#define ETHR_CACHE_LINE_SIZE ((ethr_uint_t) 64)
 
72
#define ETHR_CACHE_LINE_MASK (ETHR_CACHE_LINE_SIZE - 1)
 
73
 
 
74
#define ETHR_CACHE_LINE_ALIGN_SIZE(SZ) \
 
75
  (((((SZ) - 1) / ETHR_CACHE_LINE_SIZE) + 1) * ETHR_CACHE_LINE_SIZE)
 
76
 
 
77
#ifndef ETHR_INLINE_FUNC_NAME_
95
78
#  define ETHR_INLINE_FUNC_NAME_(X) X
96
79
#endif
97
80
 
98
 
#define ETHR_COMPILER_BARRIER ethr_compiler_barrier()
99
 
#ifdef __GNUC__
100
 
#  undef ETHR_COMPILER_BARRIER
101
 
#  define ETHR_COMPILER_BARRIER __asm__ __volatile__("":::"memory")
 
81
#if !defined(__func__)
 
82
#  if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L
 
83
#    if !defined(__GNUC__) ||  __GNUC__ < 2
 
84
#      define __func__ "[unknown_function]"
 
85
#    else
 
86
#      define __func__ __FUNCTION__
 
87
#    endif
 
88
#  endif
102
89
#endif
103
90
 
104
 
#ifdef DEBUG
 
91
int ethr_assert_failed(const char *file, int line, const char *func, char *a);
 
92
#ifdef ETHR_DEBUG
105
93
#define ETHR_ASSERT(A) \
106
 
  ((void) ((A) ? 1 : ethr_assert_failed(__FILE__, __LINE__, #A)))
107
 
int ethr_assert_failed(char *f, int l, char *a);
 
94
  ((void) ((A) ? 1 : ethr_assert_failed(__FILE__, __LINE__, __func__, #A)))
108
95
#else
109
96
#define ETHR_ASSERT(A) ((void) 1)
110
97
#endif
111
98
 
 
99
#if defined(__GNUC__)
 
100
#  define ETHR_PROTO_NORETURN__ void __attribute__((noreturn))
 
101
#  define ETHR_IMPL_NORETURN__ void
 
102
#elif defined(__WIN32__) && defined(_MSC_VER)
 
103
#  define ETHR_PROTO_NORETURN__ __declspec(noreturn) void
 
104
#  define ETHR_IMPL_NORETURN__ __declspec(noreturn) void
 
105
#else
 
106
#  define ETHR_PROTO_NORETURN__ void
 
107
#  define ETHR_IMPL_NORETURN__ void
 
108
#endif
 
109
 
112
110
#if defined(ETHR_PTHREADS)
113
111
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
114
112
 * The pthread implementation                                                *
118
116
#error "_GNU_SOURCE not defined. Please, compile all files with -D_GNU_SOURCE."
119
117
#endif
120
118
 
121
 
#if defined(ETHR_HAVE_MIT_PTHREAD_H)
 
119
#if defined(ETHR_NEED_NPTL_PTHREAD_H)
 
120
#include <nptl/pthread.h>
 
121
#elif defined(ETHR_HAVE_MIT_PTHREAD_H)
122
122
#include <pthread/mit/pthread.h>
123
123
#elif defined(ETHR_HAVE_PTHREAD_H)
124
124
#include <pthread.h>
128
128
 
129
129
typedef pthread_t ethr_tid;
130
130
 
131
 
typedef struct ethr_mutex_ ethr_mutex;
132
 
struct ethr_mutex_ {
133
 
    pthread_mutex_t pt_mtx;
134
 
    int is_rec_mtx;
135
 
    ethr_mutex *prev;
136
 
    ethr_mutex *next;
137
 
#if ETHR_XCHK
138
 
    int initialized;
139
 
#endif
140
 
};
141
 
 
142
 
typedef struct ethr_cond_ ethr_cond;
143
 
struct ethr_cond_ {
144
 
    pthread_cond_t pt_cnd;
145
 
#if ETHR_XCHK
146
 
    int initialized;
147
 
#endif
148
 
};
149
 
 
150
 
#ifndef ETHR_HAVE_PTHREAD_RWLOCK_INIT
151
 
#define ETHR_USE_RWMTX_FALLBACK
152
 
#else
153
 
typedef struct ethr_rwmutex_ ethr_rwmutex;
154
 
struct ethr_rwmutex_ {
155
 
    pthread_rwlock_t pt_rwlock;
156
 
#if ETHR_XCHK
157
 
    int initialized;
158
 
#endif
159
 
};
160
 
#endif
161
 
 
162
 
/* Static initializers */
163
 
#if ETHR_XCHK
164
 
#define ETHR_MUTEX_XCHK_INITER  , ETHR_MUTEX_INITIALIZED
165
 
#define ETHR_COND_XCHK_INITER   , ETHR_COND_INITIALIZED
166
 
#else
167
 
#define ETHR_MUTEX_XCHK_INITER
168
 
#define ETHR_COND_XCHK_INITER
169
 
#endif
170
 
 
171
 
#define ETHR_MUTEX_INITER {PTHREAD_MUTEX_INITIALIZER, 0, NULL, NULL ETHR_MUTEX_XCHK_INITER}
172
 
#define ETHR_COND_INITER {PTHREAD_COND_INITIALIZER ETHR_COND_XCHK_INITER}
173
 
 
174
 
#if defined(ETHR_HAVE_PTHREAD_MUTEXATTR_SETTYPE) \
175
 
    || defined(ETHR_HAVE_PTHREAD_MUTEXATTR_SETKIND_NP)
176
 
#  define ETHR_HAVE_ETHR_REC_MUTEX_INIT 1
177
 
#  ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
178
 
#    define ETHR_REC_MUTEX_INITER \
179
 
            {PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, 1, NULL, NULL ETHR_MUTEX_XCHK_INITER}
180
 
#  endif
181
 
#else
182
 
#  undef ETHR_HAVE_ETHR_REC_MUTEX_INIT
183
 
#endif
184
 
 
185
 
#ifndef ETHR_HAVE_PTHREAD_ATFORK
186
 
#  define ETHR_NO_FORKSAFETY 1
187
 
#endif
188
 
 
189
131
typedef pthread_key_t ethr_tsd_key;
190
132
 
191
133
#define ETHR_HAVE_ETHR_SIG_FUNCS 1
192
134
 
193
 
#ifdef ETHR_TRY_INLINE_FUNCS
194
 
 
195
 
static ETHR_INLINE int
196
 
ETHR_INLINE_FUNC_NAME_(ethr_mutex_trylock)(ethr_mutex *mtx)
197
 
{
198
 
    return pthread_mutex_trylock(&mtx->pt_mtx);
199
 
}
200
 
 
201
 
static ETHR_INLINE int
202
 
ETHR_INLINE_FUNC_NAME_(ethr_mutex_lock)(ethr_mutex *mtx)
203
 
{
204
 
    return pthread_mutex_lock(&mtx->pt_mtx);
205
 
}
206
 
 
207
 
static ETHR_INLINE int
208
 
ETHR_INLINE_FUNC_NAME_(ethr_mutex_unlock)(ethr_mutex *mtx)
209
 
{
210
 
    return pthread_mutex_unlock(&mtx->pt_mtx);
211
 
}
212
 
 
213
 
#ifdef ETHR_HAVE_PTHREAD_RWLOCK_INIT
214
 
 
215
 
static ETHR_INLINE int
216
 
ETHR_INLINE_FUNC_NAME_(ethr_rwmutex_tryrlock)(ethr_rwmutex *rwmtx)
217
 
{
218
 
    return pthread_rwlock_tryrdlock(&rwmtx->pt_rwlock);
219
 
}
220
 
 
221
 
static ETHR_INLINE int
222
 
ETHR_INLINE_FUNC_NAME_(ethr_rwmutex_rlock)(ethr_rwmutex *rwmtx)
223
 
{
224
 
    return pthread_rwlock_rdlock(&rwmtx->pt_rwlock);
225
 
}
226
 
 
227
 
static ETHR_INLINE int
228
 
ETHR_INLINE_FUNC_NAME_(ethr_rwmutex_runlock)(ethr_rwmutex *rwmtx)
229
 
{
230
 
    return pthread_rwlock_unlock(&rwmtx->pt_rwlock);
231
 
}
232
 
 
233
 
static ETHR_INLINE int
234
 
ETHR_INLINE_FUNC_NAME_(ethr_rwmutex_tryrwlock)(ethr_rwmutex *rwmtx)
235
 
{
236
 
    return pthread_rwlock_trywrlock(&rwmtx->pt_rwlock);
237
 
}
238
 
 
239
 
static ETHR_INLINE int
240
 
ETHR_INLINE_FUNC_NAME_(ethr_rwmutex_rwlock)(ethr_rwmutex *rwmtx)
241
 
{
242
 
    return pthread_rwlock_wrlock(&rwmtx->pt_rwlock);
243
 
}
244
 
 
245
 
static ETHR_INLINE int
246
 
ETHR_INLINE_FUNC_NAME_(ethr_rwmutex_rwunlock)(ethr_rwmutex *rwmtx)
247
 
{
248
 
    return pthread_rwlock_unlock(&rwmtx->pt_rwlock);
249
 
}
250
 
 
251
 
#endif /* ETHR_HAVE_PTHREAD_RWLOCK_INIT */
252
 
 
253
 
#endif /* ETHR_TRY_INLINE_FUNCS */
 
135
#if defined(PURIFY) || defined(VALGRIND)
 
136
#  define ETHR_FORCE_PTHREAD_RWLOCK
 
137
#  define ETHR_FORCE_PTHREAD_MUTEX
 
138
#endif
 
139
 
 
140
#if !defined(ETHR_FORCE_PTHREAD_RWLOCK)
 
141
#  define ETHR_USE_OWN_RWMTX_IMPL__
 
142
#endif
 
143
 
 
144
#if !defined(ETHR_FORCE_PTHREAD_MUTEX) && 0
 
145
#  define ETHR_USE_OWN_MTX_IMPL__
 
146
#endif
254
147
 
255
148
#elif defined(ETHR_WIN32_THREADS)
256
149
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
273
166
#  undef WIN32_LEAN_AND_MEAN
274
167
#endif
275
168
 
 
169
#if defined(_MSC_VER)
 
170
 
 
171
#if ETHR_SIZEOF_LONG == 4
 
172
#define ETHR_HAVE_INT32_T 1
 
173
typedef long ethr_sint32_t;
 
174
typedef unsigned long ethr_uint32_t;
 
175
#endif
 
176
 
 
177
#if ETHR_SIZEOF___INT64 == 8
 
178
#define ETHR_HAVE_INT64_T 1
 
179
typedef __int64 ethr_sint64_t;
 
180
typedef unsigned __int64 ethr_uint64_t;
 
181
#endif
 
182
 
 
183
#endif
 
184
 
 
185
struct ethr_join_data_;
 
186
 
276
187
/* Types */
277
 
typedef long ethr_tid; /* thread id type */
278
 
typedef struct {
279
 
    volatile int initialized;
280
 
    CRITICAL_SECTION cs;
281
 
#if ETHR_XCHK
282
 
    int is_rec_mtx;
283
 
#endif
284
 
} ethr_mutex;
285
 
 
286
 
typedef struct cnd_wait_event__ cnd_wait_event_;
287
 
 
288
 
typedef struct {
289
 
    volatile int initialized;
290
 
    CRITICAL_SECTION cs;
291
 
    cnd_wait_event_ *queue;
292
 
    cnd_wait_event_ *queue_end;
293
 
} ethr_cond;
294
 
 
295
 
#define ETHR_USE_RWMTX_FALLBACK
296
 
 
297
 
/* Static initializers */
298
 
 
299
 
#define ETHR_MUTEX_INITER {0}
300
 
#define ETHR_COND_INITER {0}
301
 
 
302
 
#define ETHR_REC_MUTEX_INITER ETHR_MUTEX_INITER
303
 
 
304
 
#define ETHR_HAVE_ETHR_REC_MUTEX_INIT 1
 
188
typedef struct {
 
189
    long id;
 
190
    struct ethr_join_data_ *jdata;
 
191
} ethr_tid; /* thread id type */
305
192
 
306
193
typedef DWORD ethr_tsd_key;
307
194
 
308
195
#undef ETHR_HAVE_ETHR_SIG_FUNCS
309
196
 
310
 
#ifdef ETHR_TRY_INLINE_FUNCS
311
 
int ethr_fake_static_mutex_init(ethr_mutex *mtx);
312
 
 
313
 
static ETHR_INLINE int
314
 
ETHR_INLINE_FUNC_NAME_(ethr_mutex_trylock)(ethr_mutex *mtx)
315
 
{
316
 
    if (!mtx->initialized) {
317
 
        int res = ethr_fake_static_mutex_init(mtx);
318
 
        if (res != 0)
319
 
            return res;
320
 
    }
321
 
    return TryEnterCriticalSection(&mtx->cs) ? 0 : EBUSY;
322
 
}
323
 
 
324
 
static ETHR_INLINE int
325
 
ETHR_INLINE_FUNC_NAME_(ethr_mutex_lock)(ethr_mutex *mtx)
326
 
{
327
 
    if (!mtx->initialized) {
328
 
        int res = ethr_fake_static_mutex_init(mtx);
329
 
        if (res != 0)
330
 
            return res;
331
 
    }
332
 
    EnterCriticalSection(&mtx->cs);
333
 
    return 0;
334
 
}
335
 
 
336
 
static ETHR_INLINE int
337
 
ETHR_INLINE_FUNC_NAME_(ethr_mutex_unlock)(ethr_mutex *mtx)
338
 
{
339
 
    LeaveCriticalSection(&mtx->cs);
340
 
    return 0;
341
 
}
342
 
 
343
 
#endif /* #ifdef ETHR_TRY_INLINE_FUNCS */
344
 
 
345
 
#ifdef ERTS_MIXED_CYGWIN_VC
346
 
 
347
 
/* atomics */
348
 
 
349
 
#ifdef _MSC_VER
350
 
#  if _MSC_VER < 1300
351
 
#    define ETHR_IMMED_ATOMIC_SET_GET_SAFE__ 0 /* Dont trust really old compilers */
352
 
#  else
353
 
#    if defined(_M_IX86)
354
 
#      define ETHR_IMMED_ATOMIC_SET_GET_SAFE__ 1
355
 
#    else /* I.e. IA64 */
356
 
#      if _MSC_VER >= 1400 
357
 
#        define ETHR_IMMED_ATOMIC_SET_GET_SAFE__ 1
358
 
#      else
359
 
#        define ETHR_IMMED_ATOMIC_SET_GET_SAFE__ 0
360
 
#      endif
361
 
#    endif
362
 
#  endif
363
 
#  if _MSC_VER >= 1400
364
 
#    include <intrin.h>
365
 
#    undef ETHR_COMPILER_BARRIER
366
 
#    define ETHR_COMPILER_BARRIER _ReadWriteBarrier()
367
 
#  endif
368
 
#pragma intrinsic(_ReadWriteBarrier)
369
 
#pragma intrinsic(_InterlockedAnd)
370
 
#pragma intrinsic(_InterlockedOr)
371
 
#else
372
 
#    define ETHR_IMMED_ATOMIC_SET_GET_SAFE__ 0 
373
 
#endif
374
 
 
375
 
#define ETHR_HAVE_OPTIMIZED_ATOMIC_OPS 1
376
 
#define ETHR_HAVE_OPTIMIZED_LOCKS 1
377
 
 
378
 
typedef struct {
379
 
    volatile LONG value;
380
 
} ethr_atomic_t;
381
 
 
382
 
typedef struct {
383
 
    volatile LONG locked;
384
 
} ethr_spinlock_t;
385
 
 
386
 
typedef struct {
387
 
    volatile LONG counter;
388
 
} ethr_rwlock_t;
389
 
#define ETHR_WLOCK_FLAG__ (((LONG) 1) << 30)
390
 
 
391
 
#ifdef ETHR_TRY_INLINE_FUNCS
392
 
 
393
 
static ETHR_INLINE int
394
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_init)(ethr_atomic_t *var, long i)
395
 
{
396
 
#if ETHR_IMMED_ATOMIC_SET_GET_SAFE__
397
 
    var->value = (LONG) i;
398
 
#else
399
 
    (void) InterlockedExchange(&var->value, (LONG) i);
400
 
#endif
401
 
    return 0;
402
 
}
403
 
 
404
 
static ETHR_INLINE int
405
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_set)(ethr_atomic_t *var, long i)
406
 
{
407
 
#if ETHR_IMMED_ATOMIC_SET_GET_SAFE__
408
 
    var->value = (LONG) i;
409
 
#else
410
 
    (void) InterlockedExchange(&var->value, (LONG) i);
411
 
#endif
412
 
    return 0;
413
 
}
414
 
 
415
 
static ETHR_INLINE int
416
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_read)(ethr_atomic_t *var, long *i)
417
 
{
418
 
#if ETHR_IMMED_ATOMIC_SET_GET_SAFE__
419
 
    *i = var->value;
420
 
#else
421
 
    *i = InterlockedExchangeAdd(&var->value, (LONG) 0);
422
 
#endif
423
 
    return 0;
424
 
}
425
 
 
426
 
static ETHR_INLINE int
427
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_add)(ethr_atomic_t *var, long incr)
428
 
{
429
 
    (void) InterlockedExchangeAdd(&var->value, (LONG) incr);
430
 
    return 0;
431
 
}   
432
 
    
433
 
static ETHR_INLINE int
434
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_addtest)(ethr_atomic_t *var,
435
 
                                            long i,
436
 
                                            long *testp)
437
 
{
438
 
    *testp = InterlockedExchangeAdd(&var->value, (LONG) i);
439
 
    *testp += i;
440
 
    return 0;
441
 
}
442
 
 
443
 
static ETHR_INLINE int
444
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_inc)(ethr_atomic_t *var)
445
 
{
446
 
    (void) InterlockedIncrement(&var->value);
447
 
    return 0;
448
 
}
449
 
 
450
 
static ETHR_INLINE int
451
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_dec)(ethr_atomic_t *var)
452
 
{
453
 
    (void) InterlockedDecrement(&var->value);
454
 
    return 0;
455
 
}
456
 
 
457
 
static ETHR_INLINE int
458
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_inctest)(ethr_atomic_t *var, long *testp)
459
 
{
460
 
    *testp = (long) InterlockedIncrement(&var->value);
461
 
    return 0;
462
 
}
463
 
 
464
 
static ETHR_INLINE int
465
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_dectest)(ethr_atomic_t *var, long *testp)
466
 
{
467
 
    *testp = (long) InterlockedDecrement(&var->value);
468
 
    return 0;
469
 
}
470
 
 
471
 
static ETHR_INLINE int
472
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_and_old)(ethr_atomic_t *var,
473
 
                                            long mask,
474
 
                                            long *old)
475
 
{
476
 
    /*
477
 
     * See "Extra memory barrier requirements" note at the top
478
 
     * of the file.
479
 
     *
480
 
     * According to msdn _InterlockedAnd() provides a full
481
 
     * memory barrier.
482
 
     */
483
 
    *old = (long) _InterlockedAnd(&var->value, mask);
484
 
    return 0;
485
 
}
486
 
 
487
 
static ETHR_INLINE int
488
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_or_old)(ethr_atomic_t *var,
489
 
                                           long mask,
490
 
                                           long *old)
491
 
{
492
 
    /*
493
 
     * See "Extra memory barrier requirements" note at the top
494
 
     * of the file.
495
 
     *
496
 
     * According to msdn _InterlockedOr() provides a full
497
 
     * memory barrier.
498
 
     */
499
 
    *old = (long) _InterlockedOr(&var->value, mask);
500
 
    return 0;
501
 
}
502
 
 
503
 
static ETHR_INLINE int
504
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_cmpxchg)(ethr_atomic_t *var,
505
 
                                            long new,
506
 
                                            long expected,
507
 
                                            long *old)
508
 
{
509
 
    /*
510
 
     * See "Extra memory barrier requirements" note at the top
511
 
     * of the file.
512
 
     *
513
 
     * According to msdn _InterlockedCompareExchange() provides a full
514
 
     * memory barrier.
515
 
     */
516
 
    *old = _InterlockedCompareExchange(&var->value, (LONG) new, (LONG) expected);
517
 
    return 0;
518
 
}
519
 
 
520
 
static ETHR_INLINE int
521
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_xchg)(ethr_atomic_t *var,
522
 
                                         long new,
523
 
                                         long *old)
524
 
{
525
 
    *old = (long) InterlockedExchange(&var->value, (LONG) new);
526
 
    return 0;
527
 
}
528
 
 
529
 
/*
530
 
 * According to msdn InterlockedExchange() provides a full
531
 
 * memory barrier. 
532
 
 */
533
 
 
534
 
static ETHR_INLINE int
535
 
ETHR_INLINE_FUNC_NAME_(ethr_spinlock_init)(ethr_spinlock_t *lock)
536
 
{
537
 
#if ETHR_IMMED_ATOMIC_SET_GET_SAFE__
538
 
    lock->locked = (LONG) 0;
539
 
#else
540
 
    (void) InterlockedExchange(&lock->locked, (LONG) 0);
541
 
#endif
542
 
    return 0;
543
 
}
544
 
 
545
 
static ETHR_INLINE int
546
 
ETHR_INLINE_FUNC_NAME_(ethr_spinlock_destroy)(ethr_spinlock_t *lock)
547
 
{
548
 
    return 0;
549
 
}
550
 
 
551
 
 
552
 
static ETHR_INLINE int
553
 
ETHR_INLINE_FUNC_NAME_(ethr_spin_unlock)(ethr_spinlock_t *lock)
554
 
{
555
 
    ETHR_COMPILER_BARRIER;
556
 
    {
557
 
#ifdef DEBUG
558
 
        LONG old =
559
 
#endif
560
 
            InterlockedExchange(&lock->locked, (LONG) 0);
561
 
#ifdef DEBUG
562
 
        ETHR_ASSERT(old == 1);
563
 
#endif
564
 
    }
565
 
    return 0;
566
 
}
567
 
 
568
 
static ETHR_INLINE int
569
 
ETHR_INLINE_FUNC_NAME_(ethr_spin_lock)(ethr_spinlock_t *lock)
570
 
{
571
 
    LONG old;
572
 
    do {
573
 
        old = InterlockedExchange(&lock->locked, (LONG) 1);
574
 
    } while (old != (LONG) 0);
575
 
    ETHR_COMPILER_BARRIER;
576
 
    return 0;
577
 
}
578
 
 
579
 
/*
580
 
 * According to msdn InterlockedIncrement, InterlockedDecrement,
581
 
 * and InterlockedExchangeAdd(), _InterlockedAnd, and _InterlockedOr
582
 
 * provides full memory barriers.
583
 
 */
584
 
static ETHR_INLINE int
585
 
ETHR_INLINE_FUNC_NAME_(ethr_rwlock_init)(ethr_rwlock_t *lock)
586
 
{
587
 
#if ETHR_IMMED_ATOMIC_SET_GET_SAFE__
588
 
    lock->counter = (LONG) 0;
589
 
#else
590
 
    (void) InterlockedExchange(&lock->counter, (LONG) 0);
591
 
#endif
592
 
    return 0;
593
 
}
594
 
 
595
 
static ETHR_INLINE int
596
 
ETHR_INLINE_FUNC_NAME_(ethr_rwlock_destroy)(ethr_rwlock_t *lock)
597
 
{
598
 
    return 0;
599
 
}
600
 
 
601
 
static ETHR_INLINE int
602
 
ETHR_INLINE_FUNC_NAME_(ethr_read_unlock)(ethr_rwlock_t *lock)
603
 
{
604
 
    ETHR_COMPILER_BARRIER;
605
 
    {
606
 
#ifdef DEBUG
607
 
        LONG old =
608
 
#endif
609
 
            InterlockedDecrement(&lock->counter);
610
 
        ETHR_ASSERT(old != 0);
611
 
    }
612
 
    return 0;
613
 
}
614
 
 
615
 
static ETHR_INLINE int
616
 
ETHR_INLINE_FUNC_NAME_(ethr_read_lock)(ethr_rwlock_t *lock)
617
 
{
618
 
    while (1) {
619
 
        LONG old = InterlockedIncrement(&lock->counter);
620
 
        if ((old & ETHR_WLOCK_FLAG__) == 0)
621
 
            break; /* Got read lock */
622
 
        /* Restore and wait for writers to unlock */
623
 
        old = InterlockedDecrement(&lock->counter);
624
 
        while (old & ETHR_WLOCK_FLAG__) {
625
 
#if ETHR_IMMED_ATOMIC_SET_GET_SAFE__
626
 
            old = lock->counter;
627
 
#else
628
 
            old = InterlockedExchangeAdd(&lock->counter, (LONG) 0);
629
 
#endif
630
 
        }
631
 
    }
632
 
    ETHR_COMPILER_BARRIER;
633
 
    return 0;
634
 
}
635
 
 
636
 
static ETHR_INLINE int
637
 
ETHR_INLINE_FUNC_NAME_(ethr_write_unlock)(ethr_rwlock_t *lock)
638
 
{
639
 
    ETHR_COMPILER_BARRIER;
640
 
    {
641
 
#ifdef DEBUG
642
 
        LONG old =
643
 
#endif
644
 
            _InterlockedAnd(&lock->counter, ~ETHR_WLOCK_FLAG__);
645
 
        ETHR_ASSERT(old & ETHR_WLOCK_FLAG__);
646
 
    }
647
 
    return 0;
648
 
}
649
 
 
650
 
static ETHR_INLINE int
651
 
ETHR_INLINE_FUNC_NAME_(ethr_write_lock)(ethr_rwlock_t *lock)
652
 
{
653
 
    LONG old;
654
 
    do {
655
 
        old = _InterlockedOr(&lock->counter, ETHR_WLOCK_FLAG__);
656
 
    } while (old & ETHR_WLOCK_FLAG__);
657
 
    /* We got the write part of the lock; wait for readers to unlock */
658
 
    while ((old & ~ETHR_WLOCK_FLAG__) != 0) {
659
 
#if ETHR_IMMED_ATOMIC_SET_GET_SAFE__
660
 
        old = lock->counter;
661
 
#else
662
 
        old = InterlockedExchangeAdd(&lock->counter, (LONG) 0);
663
 
#endif
664
 
        ETHR_ASSERT(old & ETHR_WLOCK_FLAG__);
665
 
    }
666
 
    ETHR_COMPILER_BARRIER;
667
 
    return 0;
668
 
}
669
 
 
670
 
#endif /* #ifdef ETHR_TRY_INLINE_FUNCS */
671
 
 
672
 
#endif /* #ifdef ERTS_MIXED_CYGWIN_VC */
 
197
#define ETHR_USE_OWN_RWMTX_IMPL__
 
198
#define ETHR_USE_OWN_MTX_IMPL__
 
199
 
 
200
#define ETHR_YIELD() (Sleep(0), 0)
673
201
 
674
202
#else /* No supported thread lib found */
675
203
 
681
209
 
682
210
#endif
683
211
 
 
212
#ifndef ETHR_HAVE_INT32_T
 
213
#if ETHR_SIZEOF_INT == 4
 
214
#define ETHR_HAVE_INT32_T 1
 
215
typedef int ethr_sint32_t;
 
216
typedef unsigned int ethr_uint32_t;
 
217
#elif ETHR_SIZEOF_LONG == 4
 
218
#define ETHR_HAVE_INT32_T 1
 
219
typedef long ethr_sint32_t;
 
220
typedef unsigned long ethr_uint32_t;
 
221
#endif
 
222
#endif
 
223
 
 
224
#ifndef ETHR_HAVE_INT64_T
 
225
#if ETHR_SIZEOF_INT == 8
 
226
#define ETHR_HAVE_INT64_T 1
 
227
typedef int ethr_sint64_t;
 
228
typedef unsigned int ethr_uint64_t;
 
229
#elif ETHR_SIZEOF_LONG == 8
 
230
#define ETHR_HAVE_INT64_T 1
 
231
typedef long ethr_sint64_t;
 
232
typedef unsigned long ethr_uint64_t;
 
233
#elif ETHR_SIZEOF_LONG_LONG == 8
 
234
#define ETHR_HAVE_INT64_T 1
 
235
typedef long long ethr_sint64_t;
 
236
typedef unsigned long long ethr_uint64_t;
 
237
#endif
 
238
#endif
 
239
 
 
240
#if ETHR_SIZEOF_PTR == 4
 
241
#ifndef ETHR_HAVE_INT32_T
 
242
#error "No 32-bit integer type found"
 
243
#endif
 
244
typedef ethr_sint32_t ethr_sint_t;
 
245
typedef ethr_uint32_t ethr_uint_t;
 
246
#elif ETHR_SIZEOF_PTR == 8
 
247
#ifndef ETHR_HAVE_INT64_T
 
248
#error "No 64-bit integer type found"
 
249
#endif
 
250
typedef ethr_sint64_t ethr_sint_t;
 
251
typedef ethr_uint64_t ethr_uint_t;
 
252
#endif
 
253
 
684
254
/* __builtin_expect() is needed by both native atomics code 
685
255
 * and the fallback code */
686
256
#if !defined(__GNUC__) || (__GNUC__ < 2) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
688
258
#endif
689
259
 
690
260
/* For CPU-optimised atomics, spinlocks, and rwlocks. */
691
 
#if !defined(ETHR_DISABLE_NATIVE_IMPLS) && defined(__GNUC__)
692
 
#  if ETHR_SIZEOF_PTR == 4
693
 
#    if defined(__i386__)
694
 
#      include "i386/ethread.h"
695
 
#    elif (defined(__powerpc__) || defined(__ppc__)) && !defined(__powerpc64__)
696
 
#      include "ppc32/ethread.h"
 
261
#if !defined(ETHR_DISABLE_NATIVE_IMPLS)
 
262
#  if defined(__GNUC__)
 
263
#    if defined(ETHR_PREFER_GCC_NATIVE_IMPLS)
 
264
#      include "gcc/ethread.h"
 
265
#    elif defined(ETHR_PREFER_LIBATOMIC_OPS_NATIVE_IMPLS)
 
266
#      include "libatomic_ops/ethread.h"
 
267
#    endif
 
268
#    ifndef ETHR_HAVE_NATIVE_ATOMICS
 
269
#      if ETHR_SIZEOF_PTR == 4
 
270
#        if defined(__i386__)
 
271
#          include "i386/ethread.h"
 
272
#        elif (defined(__powerpc__)||defined(__ppc__))&&!defined(__powerpc64__)
 
273
#          include "ppc32/ethread.h"
 
274
#        elif defined(__sparc__)
 
275
#          include "sparc32/ethread.h"
 
276
#        elif defined(__tile__)
 
277
#          include "tile/ethread.h"
 
278
#        endif
 
279
#      elif ETHR_SIZEOF_PTR == 8
 
280
#        if defined(__x86_64__)
 
281
#          include "x86_64/ethread.h"
 
282
#        elif defined(__sparc__) && defined(__arch64__)
 
283
#          include "sparc64/ethread.h"
 
284
#        endif
 
285
#      endif
 
286
#      include "gcc/ethread.h"
 
287
#      include "libatomic_ops/ethread.h"
 
288
#    endif
 
289
#  elif defined(ETHR_HAVE_LIBATOMIC_OPS)
 
290
#    include "libatomic_ops/ethread.h"
 
291
#  elif defined(ETHR_WIN32_THREADS)
 
292
#    include "win/ethread.h"
 
293
#  endif
 
294
#endif /* !ETHR_DISABLE_NATIVE_IMPLS */
 
295
 
 
296
#if defined(__GNUC__)
 
297
#  ifndef ETHR_COMPILER_BARRIER
 
298
#    define ETHR_COMPILER_BARRIER __asm__ __volatile__("" : : : "memory")
 
299
#  endif
 
300
#  ifndef ETHR_SPIN_BODY
 
301
#    if defined(__i386__) || defined(__x86_64__)
 
302
#      define ETHR_SPIN_BODY __asm__ __volatile__("rep;nop" : : : "memory")
 
303
#    elif defined(__ia64__)
 
304
#      define ETHR_SPIN_BODY __asm__ __volatile__("hint @pause" : : : "memory")
697
305
#    elif defined(__sparc__)
698
 
#      include "sparc32/ethread.h"
699
 
#    elif defined(__tile__)
700
 
#      include "tile/ethread.h"
701
 
#    endif
702
 
#  elif ETHR_SIZEOF_PTR == 8
703
 
#    if defined(__x86_64__)
704
 
#      include "x86_64/ethread.h"
705
 
#    elif defined(__sparc__) && defined(__arch64__)
706
 
#      include "sparc64/ethread.h"
707
 
#    endif
708
 
#  endif
709
 
#endif /* !defined(ETHR_DISABLE_NATIVE_IMPLS) && defined(__GNUC__) */
710
 
 
711
 
#ifdef ETHR_HAVE_OPTIMIZED_ATOMIC_OPS
712
 
#  undef ETHR_HAVE_NATIVE_ATOMICS
713
 
#endif
714
 
#ifdef ETHR_HAVE_OPTIMIZED_LOCKS
715
 
#  undef ETHR_HAVE_NATIVE_LOCKS
716
 
#endif
717
 
 
718
 
#ifdef ETHR_HAVE_NATIVE_ATOMICS
719
 
#define ETHR_HAVE_OPTIMIZED_ATOMIC_OPS 1
720
 
#endif
721
 
#ifdef ETHR_HAVE_NATIVE_LOCKS
722
 
#define ETHR_HAVE_OPTIMIZED_LOCKS 1
723
 
#endif
724
 
 
725
 
typedef struct {
726
 
    unsigned open;
727
 
    ethr_mutex mtx;
728
 
    ethr_cond cnd;
729
 
} ethr_gate;
730
 
 
731
 
#ifdef ETHR_HAVE_NATIVE_ATOMICS
732
 
/*
733
 
 * Map ethread native atomics to ethread API atomics.
734
 
 */
735
 
typedef ethr_native_atomic_t ethr_atomic_t;
736
 
#endif
737
 
 
738
 
#ifdef ETHR_HAVE_NATIVE_LOCKS
739
 
/*
740
 
 * Map ethread native spinlocks to ethread API spinlocks.
741
 
 */
742
 
typedef ethr_native_spinlock_t ethr_spinlock_t;
743
 
/*
744
 
 * Map ethread native rwlocks to ethread API rwlocks.
745
 
 */
746
 
typedef ethr_native_rwlock_t ethr_rwlock_t;
747
 
#endif
748
 
 
749
 
#ifdef ETHR_USE_RWMTX_FALLBACK
750
 
typedef struct {
751
 
    ethr_mutex mtx;
752
 
    ethr_cond rcnd;
753
 
    ethr_cond wcnd;
754
 
    unsigned readers;
755
 
    unsigned waiting_readers;
756
 
    unsigned waiting_writers;
757
 
#if ETHR_XCHK
758
 
    int initialized;
759
 
#endif
760
 
} ethr_rwmutex;
761
 
#endif
762
 
 
763
 
#ifndef ETHR_HAVE_OPTIMIZED_ATOMIC_OPS
764
 
typedef long ethr_atomic_t;
765
 
#endif
766
 
 
767
 
#ifndef ETHR_HAVE_OPTIMIZED_LOCKS
768
 
 
769
 
#if defined(ETHR_WIN32_THREADS)
770
 
typedef struct {
771
 
    CRITICAL_SECTION cs;
772
 
} ethr_spinlock_t;
773
 
typedef struct {
774
 
    CRITICAL_SECTION cs;
775
 
    unsigned counter;
776
 
} ethr_rwlock_t;
777
 
 
778
 
int ethr_do_spinlock_init(ethr_spinlock_t *lock);
779
 
int ethr_do_rwlock_init(ethr_rwlock_t *lock);
780
 
 
781
 
#define ETHR_RWLOCK_WRITERS (((unsigned) 1) << 31)
782
 
 
783
 
#elif defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
784
 
typedef struct {
785
 
    pthread_spinlock_t spnlck;
786
 
} ethr_spinlock_t;
787
 
typedef struct {
788
 
    pthread_spinlock_t spnlck;
789
 
    unsigned counter;
790
 
} ethr_rwlock_t;
791
 
#define ETHR_RWLOCK_WRITERS (((unsigned) 1) << 31)
792
 
 
793
 
#else /* ethr mutex/rwmutex */
794
 
 
795
 
typedef struct {
796
 
    ethr_mutex mtx;
797
 
} ethr_spinlock_t;
798
 
 
799
 
typedef struct {
800
 
    ethr_rwmutex rwmtx;
801
 
} ethr_rwlock_t;
802
 
 
803
 
#endif /* end mutex/rwmutex */
804
 
#endif /* ETHR_HAVE_OPTIMIZED_LOCKS */
805
 
 
806
 
typedef struct {
807
 
    void *(*alloc)(size_t);
808
 
    void *(*realloc)(void *, size_t);
809
 
    void (*free)(void *);
 
306
#      define ETHR_SPIN_BODY __asm__ __volatile__("membar #LoadLoad")
 
307
#    else
 
308
#      define ETHR_SPIN_BODY ETHR_COMPILER_BARRIER
 
309
#    endif
 
310
#  endif
 
311
#elif defined(ETHR_WIN32_THREADS)
 
312
#  ifndef ETHR_COMPILER_BARRIER
 
313
#    include <intrin.h>
 
314
#    pragma intrinsic(_ReadWriteBarrier)
 
315
#    define ETHR_COMPILER_BARRIER _ReadWriteBarrier()
 
316
#  endif
 
317
#  ifndef ETHR_SPIN_BODY
 
318
#    define ETHR_SPIN_BODY do {YieldProcessor();ETHR_COMPILER_BARRIER;} while(0)
 
319
#  endif
 
320
#endif
 
321
 
 
322
#define ETHR_YIELD_AFTER_BUSY_LOOPS 50
 
323
 
 
324
#ifndef ETHR_HAVE_NATIVE_ATOMICS
 
325
/*
 
326
 * ETHR_*MEMORY_BARRIER orders between locked and atomic accesses only,
 
327
 * i.e. when our lock based atomic fallback is used, a noop is sufficient.
 
328
 */
 
329
#define ETHR_MEMORY_BARRIER do { } while (0)
 
330
#define ETHR_WRITE_MEMORY_BARRIER do { } while (0)
 
331
#define ETHR_READ_MEMORY_BARRIER do { } while (0)
 
332
#define ETHR_READ_DEPEND_MEMORY_BARRIER do { } while (0)
 
333
#endif
 
334
 
 
335
#ifndef ETHR_WRITE_MEMORY_BARRIER
 
336
#  define ETHR_WRITE_MEMORY_BARRIER ETHR_MEMORY_BARRIER
 
337
#  define ETHR_WRITE_MEMORY_BARRIER_IS_FULL
 
338
#endif
 
339
#ifndef ETHR_READ_MEMORY_BARRIER
 
340
#  define ETHR_READ_MEMORY_BARRIER ETHR_MEMORY_BARRIER
 
341
#  define ETHR_READ_MEMORY_BARRIER_IS_FULL
 
342
#endif
 
343
#ifndef ETHR_READ_DEPEND_MEMORY_BARRIER
 
344
#  define ETHR_READ_DEPEND_MEMORY_BARRIER ETHR_COMPILER_BARRIER
 
345
#  define ETHR_READ_DEPEND_MEMORY_BARRIER_IS_COMPILER_BARRIER
 
346
#endif
 
347
 
 
348
#define ETHR_FATAL_ERROR__(ERR) \
 
349
  ethr_fatal_error__(__FILE__, __LINE__, __func__, (ERR))
 
350
 
 
351
ETHR_PROTO_NORETURN__ ethr_fatal_error__(const char *file,
 
352
                                         int line,
 
353
                                         const char *func,
 
354
                                         int err);
 
355
 
 
356
void ethr_compiler_barrier_fallback(void);
 
357
#ifndef ETHR_COMPILER_BARRIER
 
358
#  define ETHR_COMPILER_BARRIER ethr_compiler_barrier_fallback()
 
359
#endif
 
360
 
 
361
#ifndef ETHR_SPIN_BODY
 
362
#  define ETHR_SPIN_BODY ETHR_COMPILER_BARRIER
 
363
#endif
 
364
 
 
365
#ifndef ETHR_YIELD
 
366
#  if defined(ETHR_HAVE_SCHED_YIELD)
 
367
#    ifdef ETHR_HAVE_SCHED_H
 
368
#      include <sched.h>
 
369
#    endif
 
370
#    include <errno.h>
 
371
#    if defined(ETHR_SCHED_YIELD_RET_INT)
 
372
#      define ETHR_YIELD() (sched_yield() < 0 ? errno : 0)
 
373
#    else
 
374
#      define ETHR_YIELD() (sched_yield(), 0)
 
375
#    endif
 
376
#  elif defined(ETHR_HAVE_PTHREAD_YIELD)
 
377
#    if defined(ETHR_PTHREAD_YIELD_RET_INT)
 
378
#      define ETHR_YIELD() pthread_yield()
 
379
#    else
 
380
#      define ETHR_YIELD() (pthread_yield(), 0)
 
381
#    endif
 
382
#  else
 
383
#    define ETHR_YIELD() (ethr_compiler_barrier(), 0)
 
384
#  endif
 
385
#endif
 
386
 
 
387
#include "ethr_optimized_fallbacks.h"
 
388
 
 
389
typedef struct {
810
390
    void *(*thread_create_prepare_func)(void);
811
391
    void (*thread_create_parent_func)(void *);
812
392
    void (*thread_create_child_func)(void *);
813
393
} ethr_init_data;
814
394
 
815
 
#define ETHR_INIT_DATA_DEFAULT_INITER {malloc, realloc, free, NULL, NULL, NULL}
 
395
#define ETHR_INIT_DATA_DEFAULT_INITER {NULL, NULL, NULL}
 
396
 
 
397
typedef struct {
 
398
    void *(*alloc)(size_t);
 
399
    void *(*realloc)(void *, size_t);
 
400
    void (*free)(void *);
 
401
} ethr_memory_allocator;
 
402
 
 
403
#define ETHR_MEM_ALLOC_DEF_INITER__ {NULL, NULL, NULL}
 
404
 
 
405
typedef struct {
 
406
    ethr_memory_allocator std;
 
407
    ethr_memory_allocator sl;
 
408
    ethr_memory_allocator ll;
 
409
} ethr_memory_allocators;
 
410
 
 
411
#define ETHR_MEM_ALLOCS_DEF_INITER__                                    \
 
412
  {ETHR_MEM_ALLOC_DEF_INITER__,                                         \
 
413
   ETHR_MEM_ALLOC_DEF_INITER__,                                         \
 
414
   ETHR_MEM_ALLOC_DEF_INITER__}
 
415
 
 
416
typedef struct {
 
417
    ethr_memory_allocators mem;
 
418
    int reader_groups;
 
419
    int main_threads;
 
420
} ethr_late_init_data;
 
421
 
 
422
#define ETHR_LATE_INIT_DATA_DEFAULT_INITER                              \
 
423
  {ETHR_MEM_ALLOCS_DEF_INITER__, 0, 0}
816
424
 
817
425
typedef struct {
818
426
    int detached;                       /* boolean (default false) */
821
429
 
822
430
#define ETHR_THR_OPTS_DEFAULT_INITER {0, -1}
823
431
 
824
 
#if defined(ETHR_CUSTOM_INLINE_FUNC_NAME_) || !defined(ETHR_TRY_INLINE_FUNCS)
825
 
#  define ETHR_NEED_MTX_PROTOTYPES__
826
 
#  define ETHR_NEED_RWMTX_PROTOTYPES__
 
432
 
 
433
#if !defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
827
434
#  define ETHR_NEED_SPINLOCK_PROTOTYPES__
828
 
#  define ETHR_NEED_ATOMIC_PROTOTYPES__
829
 
#endif
830
 
 
831
 
#if !defined(ETHR_NEED_RWMTX_PROTOTYPES__) && defined(ETHR_USE_RWMTX_FALLBACK)
832
 
#  define ETHR_NEED_RWMTX_PROTOTYPES__
 
435
#  define ETHR_NEED_RWSPINLOCK_PROTOTYPES__
833
436
#endif
834
437
 
835
438
int ethr_init(ethr_init_data *);
 
439
int ethr_late_init(ethr_late_init_data *);
836
440
int ethr_install_exit_handler(void (*funcp)(void));
837
441
int ethr_thr_create(ethr_tid *, void * (*)(void *), void *, ethr_thr_opts *);
838
442
int ethr_thr_join(ethr_tid, void **);
840
444
void ethr_thr_exit(void *);
841
445
ethr_tid ethr_self(void);
842
446
int ethr_equal_tids(ethr_tid, ethr_tid);
843
 
int ethr_mutex_init(ethr_mutex *);
844
 
#ifdef ETHR_HAVE_ETHR_REC_MUTEX_INIT
845
 
int ethr_rec_mutex_init(ethr_mutex *);
846
 
#endif
847
 
int ethr_mutex_destroy(ethr_mutex *);
848
 
int ethr_mutex_set_forksafe(ethr_mutex *);
849
 
int ethr_mutex_unset_forksafe(ethr_mutex *);
850
 
#ifdef ETHR_NEED_MTX_PROTOTYPES__
851
 
int ethr_mutex_trylock(ethr_mutex *);
852
 
int ethr_mutex_lock(ethr_mutex *);
853
 
int ethr_mutex_unlock(ethr_mutex *);
854
 
#endif
855
 
int ethr_cond_init(ethr_cond *);
856
 
int ethr_cond_destroy(ethr_cond *);
857
 
int ethr_cond_signal(ethr_cond *);
858
 
int ethr_cond_broadcast(ethr_cond *);
859
 
int ethr_cond_wait(ethr_cond *, ethr_mutex *);
860
 
int ethr_cond_timedwait(ethr_cond *, ethr_mutex *, ethr_timeval *);
861
 
 
862
 
int ethr_rwmutex_init(ethr_rwmutex *);
863
 
int ethr_rwmutex_destroy(ethr_rwmutex *);
864
 
#ifdef ETHR_NEED_RWMTX_PROTOTYPES__
865
 
int ethr_rwmutex_tryrlock(ethr_rwmutex *);
866
 
int ethr_rwmutex_rlock(ethr_rwmutex *);
867
 
int ethr_rwmutex_runlock(ethr_rwmutex *);
868
 
int ethr_rwmutex_tryrwlock(ethr_rwmutex *);
869
 
int ethr_rwmutex_rwlock(ethr_rwmutex *);
870
 
int ethr_rwmutex_rwunlock(ethr_rwmutex *);
871
 
#endif
872
 
 
873
 
#ifdef ETHR_NEED_ATOMIC_PROTOTYPES__
874
 
int ethr_atomic_init(ethr_atomic_t *, long);
875
 
int ethr_atomic_set(ethr_atomic_t *, long);
876
 
int ethr_atomic_read(ethr_atomic_t *, long *);
877
 
int ethr_atomic_inctest(ethr_atomic_t *, long *);
878
 
int ethr_atomic_dectest(ethr_atomic_t *, long *);
879
 
int ethr_atomic_inc(ethr_atomic_t *);
880
 
int ethr_atomic_dec(ethr_atomic_t *);
881
 
int ethr_atomic_addtest(ethr_atomic_t *, long, long *);
882
 
int ethr_atomic_add(ethr_atomic_t *, long);
883
 
int ethr_atomic_and_old(ethr_atomic_t *, long, long *);
884
 
int ethr_atomic_or_old(ethr_atomic_t *, long, long *);
885
 
int ethr_atomic_xchg(ethr_atomic_t *, long, long *);
886
 
int ethr_atomic_cmpxchg(ethr_atomic_t *, long, long, long *);
887
 
#endif
888
 
 
889
 
#ifdef ETHR_NEED_SPINLOCK_PROTOTYPES__
890
 
int ethr_spinlock_init(ethr_spinlock_t *);
891
 
int ethr_spinlock_destroy(ethr_spinlock_t *);
892
 
int ethr_spin_unlock(ethr_spinlock_t *);
893
 
int ethr_spin_lock(ethr_spinlock_t *);
894
 
 
895
 
int ethr_rwlock_init(ethr_rwlock_t *);
896
 
int ethr_rwlock_destroy(ethr_rwlock_t *);
897
 
int ethr_read_unlock(ethr_rwlock_t *);
898
 
int ethr_read_lock(ethr_rwlock_t *);
899
 
int ethr_write_unlock(ethr_rwlock_t *);
900
 
int ethr_write_lock(ethr_rwlock_t *);
901
 
#endif
902
 
 
903
 
int ethr_time_now(ethr_timeval *);
 
447
 
904
448
int ethr_tsd_key_create(ethr_tsd_key *);
905
449
int ethr_tsd_key_delete(ethr_tsd_key);
906
450
int ethr_tsd_set(ethr_tsd_key, void *);
907
451
void *ethr_tsd_get(ethr_tsd_key);
908
452
 
909
 
int ethr_gate_init(ethr_gate *);
910
 
int ethr_gate_destroy(ethr_gate *);
911
 
int ethr_gate_close(ethr_gate *);
912
 
int ethr_gate_let_through(ethr_gate *, unsigned);
913
 
int ethr_gate_wait(ethr_gate *);
914
 
int ethr_gate_swait(ethr_gate *, int);
915
 
 
916
453
#ifdef ETHR_HAVE_ETHR_SIG_FUNCS
917
454
#include <signal.h>
918
455
int ethr_sigmask(int how, const sigset_t *set, sigset_t *oset);
921
458
 
922
459
void ethr_compiler_barrier(void);
923
460
 
924
 
#ifdef ETHR_TRY_INLINE_FUNCS
925
 
 
926
 
#ifdef ETHR_HAVE_NATIVE_ATOMICS
927
 
 
928
 
static ETHR_INLINE int
929
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_init)(ethr_atomic_t *var, long i)
930
 
{
931
 
    ethr_native_atomic_init(var, i);
932
 
    return 0;
933
 
}
934
 
 
935
 
static ETHR_INLINE int
936
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_set)(ethr_atomic_t *var, long i)
937
 
{
938
 
    ethr_native_atomic_set(var, i);
939
 
    return 0;
940
 
}
941
 
 
942
 
static ETHR_INLINE int
943
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_read)(ethr_atomic_t *var, long *i)
944
 
{
945
 
    *i = ethr_native_atomic_read(var);
946
 
    return 0;
947
 
}
948
 
 
949
 
static ETHR_INLINE int
950
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_add)(ethr_atomic_t *var, long incr)
951
 
{
952
 
    ethr_native_atomic_add(var, incr);
953
 
    return 0;
954
 
}   
955
 
    
956
 
static ETHR_INLINE int
957
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_addtest)(ethr_atomic_t *var,
958
 
                                            long i,
959
 
                                            long *testp)
960
 
{
961
 
    *testp = ethr_native_atomic_add_return(var, i);
962
 
    return 0;
963
 
}
964
 
 
965
 
static ETHR_INLINE int
966
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_inc)(ethr_atomic_t *var)
967
 
{
968
 
    ethr_native_atomic_inc(var);
969
 
    return 0;
970
 
}
971
 
 
972
 
static ETHR_INLINE int
973
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_dec)(ethr_atomic_t *var)
974
 
{
975
 
    ethr_native_atomic_dec(var);
976
 
    return 0;
977
 
}
978
 
 
979
 
static ETHR_INLINE int
980
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_inctest)(ethr_atomic_t *var, long *testp)
981
 
{
982
 
    *testp = ethr_native_atomic_inc_return(var);
983
 
    return 0;
984
 
}
985
 
 
986
 
static ETHR_INLINE int
987
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_dectest)(ethr_atomic_t *var, long *testp)
988
 
{
989
 
    *testp = ethr_native_atomic_dec_return(var);
990
 
    return 0;
991
 
}
992
 
 
993
 
static ETHR_INLINE int
994
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_and_old)(ethr_atomic_t *var,
995
 
                                            long mask,
996
 
                                            long *old)
997
 
{
998
 
    /*
999
 
     * See "Extra memory barrier requirements" note at the top
1000
 
     * of the file.
1001
 
     */
1002
 
    *old = ethr_native_atomic_and_retold(var, mask);
1003
 
    return 0;
1004
 
}
1005
 
 
1006
 
static ETHR_INLINE int
1007
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_or_old)(ethr_atomic_t *var,
1008
 
                                           long mask,
1009
 
                                           long *old)
1010
 
{
1011
 
    /*
1012
 
     * See "Extra memory barrier requirements" note at the top
1013
 
     * of the file.
1014
 
     */
1015
 
    *old = ethr_native_atomic_or_retold(var, mask);
1016
 
    return 0;
1017
 
}
1018
 
 
1019
 
static ETHR_INLINE int
1020
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_xchg)(ethr_atomic_t *var,
1021
 
                                         long new,
1022
 
                                         long *old)
1023
 
{
1024
 
    *old = ethr_native_atomic_xchg(var, new);
1025
 
    return 0;
1026
 
}   
1027
 
 
1028
 
/*
1029
 
 * If *var == *old, replace *old with new, else do nothing.
1030
 
 * In any case return the original value of *var in *old.
1031
 
 */
1032
 
static ETHR_INLINE int
1033
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_cmpxchg)(ethr_atomic_t *var,
1034
 
                                            long new,
1035
 
                                            long expected,
1036
 
                                            long *old)
1037
 
{
1038
 
    /*
1039
 
     * See "Extra memory barrier requirements" note at the top
1040
 
     * of the file.
1041
 
     */
1042
 
    *old = ethr_native_atomic_cmpxchg(var, new, expected);
1043
 
    return 0;
1044
 
}
1045
 
 
1046
 
#endif /* ETHR_HAVE_NATIVE_ATOMICS */
1047
 
 
1048
 
#ifdef ETHR_HAVE_NATIVE_LOCKS
 
461
#if defined(ETHR_HAVE_NATIVE_SPINLOCKS)
 
462
typedef ethr_native_spinlock_t ethr_spinlock_t;
 
463
#elif defined(ETHR_HAVE_OPTIMIZED_SPINLOCKS)
 
464
typedef ethr_opt_spinlock_t ethr_spinlock_t;
 
465
#elif defined(__WIN32__)
 
466
typedef CRITICAL_SECTION ethr_spinlock_t;
 
467
#else
 
468
typedef pthread_mutex_t ethr_spinlock_t;
 
469
#endif
 
470
 
 
471
#ifdef ETHR_NEED_SPINLOCK_PROTOTYPES__
 
472
int ethr_spinlock_init(ethr_spinlock_t *);
 
473
int ethr_spinlock_destroy(ethr_spinlock_t *);
 
474
void ethr_spin_unlock(ethr_spinlock_t *);
 
475
void ethr_spin_lock(ethr_spinlock_t *);
 
476
#endif
 
477
 
 
478
#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
1049
479
 
1050
480
static ETHR_INLINE int
1051
481
ETHR_INLINE_FUNC_NAME_(ethr_spinlock_init)(ethr_spinlock_t *lock)
1052
482
{
 
483
#ifdef ETHR_HAVE_NATIVE_SPINLOCKS
1053
484
    ethr_native_spinlock_init(lock);
1054
485
    return 0;
 
486
#elif defined(ETHR_HAVE_OPTIMIZED_SPINLOCKS)
 
487
    return ethr_opt_spinlock_init((ethr_opt_spinlock_t *) lock);
 
488
#elif defined(__WIN32__)
 
489
    if (!InitializeCriticalSectionAndSpinCount((CRITICAL_SECTION *) lock, INT_MAX))
 
490
        return ethr_win_get_errno__();
 
491
    return 0;
 
492
#else
 
493
    return pthread_mutex_init((pthread_mutex_t *) lock, NULL);
 
494
#endif
1055
495
}
1056
496
 
1057
497
static ETHR_INLINE int
1058
498
ETHR_INLINE_FUNC_NAME_(ethr_spinlock_destroy)(ethr_spinlock_t *lock)
1059
499
{
1060
 
    return 0;
 
500
#ifdef ETHR_HAVE_NATIVE_SPINLOCKS
 
501
    return 0;
 
502
#elif defined(ETHR_HAVE_OPTIMIZED_SPINLOCKS)
 
503
    return ethr_opt_spinlock_destroy((ethr_opt_spinlock_t *) lock);
 
504
#elif defined(__WIN32__)
 
505
    DeleteCriticalSection((CRITICAL_SECTION *) lock);
 
506
    return 0;
 
507
#else
 
508
    return pthread_mutex_destroy((pthread_mutex_t *) lock);
 
509
#endif
1061
510
}
1062
511
 
1063
 
static ETHR_INLINE int
 
512
static ETHR_INLINE void
1064
513
ETHR_INLINE_FUNC_NAME_(ethr_spin_unlock)(ethr_spinlock_t *lock)
1065
514
{
 
515
#ifdef ETHR_HAVE_NATIVE_SPINLOCKS
1066
516
    ethr_native_spin_unlock(lock);
1067
 
    return 0;
 
517
#elif defined(ETHR_HAVE_OPTIMIZED_SPINLOCKS)
 
518
    int err = ethr_opt_spin_unlock((ethr_opt_spinlock_t *) lock);
 
519
    if (err)
 
520
        ETHR_FATAL_ERROR__(err);
 
521
#elif defined(__WIN32__)
 
522
    LeaveCriticalSection((CRITICAL_SECTION *) lock);
 
523
#else
 
524
    int err = pthread_mutex_unlock((pthread_mutex_t *) lock);
 
525
    if (err)
 
526
        ETHR_FATAL_ERROR__(err);
 
527
#endif
1068
528
}
1069
529
 
1070
 
static ETHR_INLINE int
 
530
static ETHR_INLINE void
1071
531
ETHR_INLINE_FUNC_NAME_(ethr_spin_lock)(ethr_spinlock_t *lock)
1072
532
{
 
533
#ifdef ETHR_HAVE_NATIVE_SPINLOCKS
1073
534
    ethr_native_spin_lock(lock);
1074
 
    return 0;
1075
 
}
 
535
#elif defined(ETHR_HAVE_OPTIMIZED_SPINLOCKS)
 
536
    int err = ethr_opt_spin_lock((ethr_opt_spinlock_t *) lock);
 
537
    if (err)
 
538
        ETHR_FATAL_ERROR__(err);
 
539
#elif defined(__WIN32__)
 
540
    EnterCriticalSection((CRITICAL_SECTION *) lock);
 
541
#else
 
542
    int err = pthread_mutex_lock((pthread_mutex_t *) lock);
 
543
    if (err)
 
544
        ETHR_FATAL_ERROR__(err);
 
545
#endif
 
546
}
 
547
 
 
548
#endif /* ETHR_TRY_INLINE_FUNCS */
 
549
 
 
550
#include "ethr_atomics.h"
 
551
 
 
552
typedef struct ethr_ts_event_ ethr_ts_event; /* Needed by ethr_mutex.h */
 
553
 
 
554
#if defined(ETHR_WIN32_THREADS)
 
555
#  include "win/ethr_event.h"
 
556
#else
 
557
#  include "pthread/ethr_event.h"
 
558
#endif
 
559
 
 
560
int ethr_set_main_thr_status(int, int);
 
561
int ethr_get_main_thr_status(int *);
 
562
 
 
563
struct ethr_ts_event_ {
 
564
    ethr_ts_event *next;
 
565
    ethr_ts_event *prev;
 
566
    ethr_event event;
 
567
    void *udata;
 
568
    ethr_atomic32_t uaflgs;
 
569
    unsigned uflgs;
 
570
    unsigned iflgs;             /* for ethr lib only */
 
571
    short rgix;                 /* for ethr lib only */
 
572
    short mtix;                 /* for ethr lib only */
 
573
};
 
574
 
 
575
#define ETHR_TS_EV_ETHREAD      (((unsigned) 1) << 0)
 
576
#define ETHR_TS_EV_INITED       (((unsigned) 1) << 1)
 
577
#define ETHR_TS_EV_TMP          (((unsigned) 1) << 2)
 
578
#define ETHR_TS_EV_MAIN_THR     (((unsigned) 1) << 3)
 
579
 
 
580
int ethr_get_tmp_ts_event__(ethr_ts_event **tsepp);
 
581
int ethr_free_ts_event__(ethr_ts_event *tsep);
 
582
int ethr_make_ts_event__(ethr_ts_event **tsepp);
 
583
 
 
584
#if !defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHREAD_IMPL__)
 
585
ethr_ts_event *ethr_get_ts_event(void);
 
586
void ethr_leave_ts_event(ethr_ts_event *);
 
587
#endif
 
588
 
 
589
#if defined(ETHR_PTHREADS)
 
590
 
 
591
#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHREAD_IMPL__)
 
592
 
 
593
extern pthread_key_t ethr_ts_event_key__;
 
594
 
 
595
static ETHR_INLINE ethr_ts_event *
 
596
ETHR_INLINE_FUNC_NAME_(ethr_get_ts_event)(void)
 
597
{
 
598
    ethr_ts_event *tsep = pthread_getspecific(ethr_ts_event_key__);
 
599
    if (!tsep) {
 
600
        int res = ethr_make_ts_event__(&tsep);
 
601
        if (res != 0)
 
602
            ETHR_FATAL_ERROR__(res);
 
603
        ETHR_ASSERT(tsep);
 
604
    }
 
605
    return tsep;
 
606
}
 
607
 
 
608
static ETHR_INLINE void
 
609
ETHR_INLINE_FUNC_NAME_(ethr_leave_ts_event)(ethr_ts_event *tsep)
 
610
{
 
611
 
 
612
}
 
613
 
 
614
#endif
 
615
 
 
616
#elif defined(ETHR_WIN32_THREADS)
 
617
 
 
618
#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHREAD_IMPL__)
 
619
 
 
620
extern DWORD ethr_ts_event_key__;
 
621
 
 
622
static ETHR_INLINE ethr_ts_event *
 
623
ETHR_INLINE_FUNC_NAME_(ethr_get_ts_event)(void)
 
624
{
 
625
    ethr_ts_event *tsep = TlsGetValue(ethr_ts_event_key__);
 
626
    if (!tsep) {
 
627
        int res = ethr_get_tmp_ts_event__(&tsep);
 
628
        if (res != 0)
 
629
            ETHR_FATAL_ERROR__(res);
 
630
        ETHR_ASSERT(tsep);
 
631
    }
 
632
    return tsep;
 
633
}
 
634
 
 
635
static ETHR_INLINE void
 
636
ETHR_INLINE_FUNC_NAME_(ethr_leave_ts_event)(ethr_ts_event *tsep)
 
637
{
 
638
    if (tsep->iflgs & ETHR_TS_EV_TMP) {
 
639
        int res = ethr_free_ts_event__(tsep);
 
640
        if (res != 0)
 
641
            ETHR_FATAL_ERROR__(res);
 
642
    }
 
643
}
 
644
 
 
645
#endif
 
646
 
 
647
#endif
 
648
 
 
649
#include "ethr_mutex.h" /* Need atomic declarations and tse */
 
650
 
 
651
#ifdef ETHR_HAVE_NATIVE_RWSPINLOCKS
 
652
typedef ethr_native_rwlock_t ethr_rwlock_t;
 
653
#else
 
654
typedef ethr_rwmutex ethr_rwlock_t;
 
655
#endif
 
656
 
 
657
#ifdef ETHR_NEED_RWSPINLOCK_PROTOTYPES__
 
658
int ethr_rwlock_init(ethr_rwlock_t *);
 
659
int ethr_rwlock_destroy(ethr_rwlock_t *);
 
660
void ethr_read_unlock(ethr_rwlock_t *);
 
661
void ethr_read_lock(ethr_rwlock_t *);
 
662
void ethr_write_unlock(ethr_rwlock_t *);
 
663
void ethr_write_lock(ethr_rwlock_t *);
 
664
#endif
 
665
 
 
666
#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)
1076
667
 
1077
668
static ETHR_INLINE int
1078
669
ETHR_INLINE_FUNC_NAME_(ethr_rwlock_init)(ethr_rwlock_t *lock)
1079
670
{
 
671
#ifdef ETHR_HAVE_NATIVE_RWSPINLOCKS
1080
672
    ethr_native_rwlock_init(lock);
1081
673
    return 0;
 
674
#else
 
675
    return ethr_rwmutex_init_opt((ethr_rwmutex *) lock, NULL);
 
676
#endif
1082
677
}
1083
678
 
1084
679
static ETHR_INLINE int
1085
680
ETHR_INLINE_FUNC_NAME_(ethr_rwlock_destroy)(ethr_rwlock_t *lock)
1086
681
{
 
682
#ifdef ETHR_HAVE_NATIVE_RWSPINLOCKS
1087
683
    return 0;
 
684
#else
 
685
    return ethr_rwmutex_destroy((ethr_rwmutex *) lock);
 
686
#endif
1088
687
}
1089
688
 
1090
 
static ETHR_INLINE int
 
689
static ETHR_INLINE void
1091
690
ETHR_INLINE_FUNC_NAME_(ethr_read_unlock)(ethr_rwlock_t *lock)
1092
691
{
 
692
#ifdef ETHR_HAVE_NATIVE_RWSPINLOCKS
1093
693
    ethr_native_read_unlock(lock);
1094
 
    return 0;
 
694
#else
 
695
    ethr_rwmutex_runlock((ethr_rwmutex *) lock);
 
696
#endif
1095
697
}
1096
698
 
1097
 
static ETHR_INLINE int
 
699
static ETHR_INLINE void
1098
700
ETHR_INLINE_FUNC_NAME_(ethr_read_lock)(ethr_rwlock_t *lock)
1099
701
{
 
702
#ifdef ETHR_HAVE_NATIVE_RWSPINLOCKS
1100
703
    ethr_native_read_lock(lock);
1101
 
    return 0;
 
704
#else
 
705
    ethr_rwmutex_rlock((ethr_rwmutex *) lock);
 
706
#endif
1102
707
}
1103
708
 
1104
 
static ETHR_INLINE int
 
709
static ETHR_INLINE void
1105
710
ETHR_INLINE_FUNC_NAME_(ethr_write_unlock)(ethr_rwlock_t *lock)
1106
711
{
 
712
#ifdef ETHR_HAVE_NATIVE_RWSPINLOCKS
1107
713
    ethr_native_write_unlock(lock);
1108
 
    return 0;
 
714
#else
 
715
    ethr_rwmutex_rwunlock((ethr_rwmutex *) lock);
 
716
#endif
1109
717
}
1110
718
 
1111
 
static ETHR_INLINE int
 
719
static ETHR_INLINE void
1112
720
ETHR_INLINE_FUNC_NAME_(ethr_write_lock)(ethr_rwlock_t *lock)
1113
721
{
 
722
#ifdef ETHR_HAVE_NATIVE_RWSPINLOCKS
1114
723
    ethr_native_write_lock(lock);
1115
 
    return 0;
 
724
#else
 
725
    ethr_rwmutex_rwlock((ethr_rwmutex *) lock);
 
726
#endif
1116
727
}
1117
728
 
1118
 
#endif /* ETHR_HAVE_NATIVE_LOCKS */
1119
 
 
1120
729
#endif /* ETHR_TRY_INLINE_FUNCS */
1121
730
 
1122
 
/*
1123
 
 * Fallbacks for atomics used in absence of optimized implementation.
1124
 
 */
1125
 
#ifndef ETHR_HAVE_OPTIMIZED_ATOMIC_OPS
1126
 
 
1127
 
#define ETHR_ATOMIC_ADDR_BITS 4
1128
 
#define ETHR_ATOMIC_ADDR_SHIFT 3
1129
 
 
1130
 
typedef struct {
1131
 
    union {
1132
 
#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
1133
 
        pthread_spinlock_t spnlck;
1134
 
#else
1135
 
        ethr_mutex mtx;
1136
 
#endif
1137
 
        char buf[ETHR_CACHE_LINE_SIZE];
1138
 
    } u;
1139
 
} ethr_atomic_protection_t;
1140
 
 
1141
 
extern ethr_atomic_protection_t ethr_atomic_protection__[1 << ETHR_ATOMIC_ADDR_BITS];
1142
 
 
1143
 
 
1144
 
#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
1145
 
 
1146
 
#define ETHR_ATOMIC_PTR2LCK__(PTR) \
1147
 
(&ethr_atomic_protection__[((((unsigned long) (PTR)) >> ETHR_ATOMIC_ADDR_SHIFT) \
1148
 
                        & ((1 << ETHR_ATOMIC_ADDR_BITS) - 1))].u.spnlck)
1149
 
 
1150
 
 
1151
 
#define ETHR_ATOMIC_OP_FALLBACK_IMPL__(AP, EXPS)                        \
1152
 
do {                                                                    \
1153
 
    pthread_spinlock_t *slp__ = ETHR_ATOMIC_PTR2LCK__((AP));            \
1154
 
    int res__ = pthread_spin_lock(slp__);                               \
1155
 
    if (res__ != 0)                                                     \
1156
 
        return res__;                                                   \
1157
 
    { EXPS; }                                                           \
1158
 
    return pthread_spin_unlock(slp__);                                  \
1159
 
} while (0)
1160
 
 
1161
 
#else /* ethread mutex */
1162
 
 
1163
 
#define ETHR_ATOMIC_PTR2LCK__(PTR) \
1164
 
(&ethr_atomic_protection__[((((unsigned long) (PTR)) >> ETHR_ATOMIC_ADDR_SHIFT) \
1165
 
                     & ((1 << ETHR_ATOMIC_ADDR_BITS) - 1))].u.mtx)
1166
 
 
1167
 
#define ETHR_ATOMIC_OP_FALLBACK_IMPL__(AP, EXPS)                        \
1168
 
do {                                                                    \
1169
 
    ethr_mutex *mtxp__ = ETHR_ATOMIC_PTR2LCK__((AP));                   \
1170
 
    int res__ = ETHR_INLINE_FUNC_NAME_(ethr_mutex_lock)(mtxp__);        \
1171
 
    if (res__ != 0)                                                     \
1172
 
        return res__;                                                   \
1173
 
    { EXPS; }                                                           \
1174
 
    return ETHR_INLINE_FUNC_NAME_(ethr_mutex_unlock)(mtxp__);           \
1175
 
} while (0)
1176
 
 
1177
 
#endif /* end ethread mutex */
1178
 
 
1179
 
#ifdef ETHR_TRY_INLINE_FUNCS
1180
 
 
1181
 
static ETHR_INLINE int
1182
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_init)(ethr_atomic_t *var, long i)
1183
 
{
1184
 
    ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, *var = (ethr_atomic_t) i);
1185
 
}
1186
 
 
1187
 
static ETHR_INLINE int
1188
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_set)(ethr_atomic_t *var, long i)
1189
 
{
1190
 
    ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, *var = (ethr_atomic_t) i);
1191
 
}
1192
 
 
1193
 
static ETHR_INLINE int
1194
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_read)(ethr_atomic_t *var, long *i)
1195
 
{
1196
 
    ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, *i = (long) *var);
1197
 
}
1198
 
 
1199
 
static ETHR_INLINE int
1200
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_inctest)(ethr_atomic_t *incp, long *testp)
1201
 
{
1202
 
    ETHR_ATOMIC_OP_FALLBACK_IMPL__(incp, *testp = (long) ++(*incp));
1203
 
}
1204
 
 
1205
 
static ETHR_INLINE int
1206
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_dectest)(ethr_atomic_t *decp, long *testp)
1207
 
{
1208
 
    ETHR_ATOMIC_OP_FALLBACK_IMPL__(decp, *testp = (long) --(*decp));
1209
 
}
1210
 
 
1211
 
static ETHR_INLINE int
1212
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_add)(ethr_atomic_t *var, long incr)
1213
 
{
1214
 
    ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, *var += incr);
1215
 
}   
1216
 
    
1217
 
static ETHR_INLINE int
1218
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_addtest)(ethr_atomic_t *incp,
1219
 
                                            long i,
1220
 
                                            long *testp)
1221
 
{
1222
 
    ETHR_ATOMIC_OP_FALLBACK_IMPL__(incp, *incp += i; *testp = *incp);
1223
 
}
1224
 
 
1225
 
static ETHR_INLINE int
1226
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_inc)(ethr_atomic_t *incp)
1227
 
{
1228
 
    ETHR_ATOMIC_OP_FALLBACK_IMPL__(incp, ++(*incp));
1229
 
}
1230
 
 
1231
 
static ETHR_INLINE int
1232
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_dec)(ethr_atomic_t *decp)
1233
 
{
1234
 
    ETHR_ATOMIC_OP_FALLBACK_IMPL__(decp, --(*decp));
1235
 
}
1236
 
 
1237
 
static ETHR_INLINE int
1238
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_and_old)(ethr_atomic_t *var,
1239
 
                                            long mask,
1240
 
                                            long *old)
1241
 
{
1242
 
    /*
1243
 
     * See "Extra memory barrier requirements" note at the top
1244
 
     * of the file.
1245
 
     */
1246
 
    ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, *old = *var; *var &= mask);
1247
 
}
1248
 
 
1249
 
static ETHR_INLINE int
1250
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_or_old)(ethr_atomic_t *var,
1251
 
                                           long mask,
1252
 
                                           long *old)
1253
 
{
1254
 
    /*
1255
 
     * See "Extra memory barrier requirements" note at the top
1256
 
     * of the file.
1257
 
     */
1258
 
    ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, *old = *var; *var |= mask);
1259
 
}
1260
 
 
1261
 
static ETHR_INLINE int
1262
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_xchg)(ethr_atomic_t *var,
1263
 
                                         long new,
1264
 
                                         long *old)
1265
 
{
1266
 
    ETHR_ATOMIC_OP_FALLBACK_IMPL__(var, *old = *var; *var = new);
1267
 
}   
1268
 
 
1269
 
/*
1270
 
 * If *var == *old, replace *old with new, else do nothing.
1271
 
 * In any case return the original value of *var in *old.
1272
 
 */
1273
 
static ETHR_INLINE int
1274
 
ETHR_INLINE_FUNC_NAME_(ethr_atomic_cmpxchg)(ethr_atomic_t *var,
1275
 
                                            long new,
1276
 
                                            long expected,
1277
 
                                            long *old)
1278
 
{
1279
 
    /*
1280
 
     * See "Extra memory barrier requirements" note at the top
1281
 
     * of the file.
1282
 
     */
1283
 
    ETHR_ATOMIC_OP_FALLBACK_IMPL__(
1284
 
      var,
1285
 
      long old_val = *var;
1286
 
      *old = old_val;
1287
 
      if (__builtin_expect(old_val == expected, 1))
1288
 
          *var = new;
1289
 
      );
1290
 
    return 0;
1291
 
}
1292
 
 
1293
 
#endif /* #ifdef ETHR_TRY_INLINE_FUNCS */
1294
 
#endif /* #ifndef ETHR_HAVE_OPTIMIZED_ATOMIC_OPS */
1295
 
 
1296
 
/*
1297
 
 * Fallbacks for spin locks, and rw spin locks used in absence of
1298
 
 * optimized implementation.
1299
 
 */
1300
 
#ifndef ETHR_HAVE_OPTIMIZED_LOCKS
1301
 
 
1302
 
#ifdef ETHR_TRY_INLINE_FUNCS
1303
 
 
1304
 
static ETHR_INLINE int
1305
 
ETHR_INLINE_FUNC_NAME_(ethr_spinlock_init)(ethr_spinlock_t *lock)
1306
 
{
1307
 
#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
1308
 
    return pthread_spin_init(&lock->spnlck, 0);
1309
 
#else
1310
 
    return ethr_mutex_init(&lock->mtx);
1311
 
#endif
1312
 
}
1313
 
 
1314
 
static ETHR_INLINE int
1315
 
ETHR_INLINE_FUNC_NAME_(ethr_spinlock_destroy)(ethr_spinlock_t *lock)
1316
 
{
1317
 
#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
1318
 
    return pthread_spin_destroy(&lock->spnlck);
1319
 
#else
1320
 
    return ethr_mutex_destroy(&lock->mtx);
1321
 
#endif
1322
 
}
1323
 
 
1324
 
 
1325
 
static ETHR_INLINE int
1326
 
ETHR_INLINE_FUNC_NAME_(ethr_spin_unlock)(ethr_spinlock_t *lock)
1327
 
{
1328
 
#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
1329
 
    return pthread_spin_unlock(&lock->spnlck);
1330
 
#else
1331
 
    return ETHR_INLINE_FUNC_NAME_(ethr_mutex_unlock)(&lock->mtx);
1332
 
#endif
1333
 
}
1334
 
 
1335
 
static ETHR_INLINE int
1336
 
ETHR_INLINE_FUNC_NAME_(ethr_spin_lock)(ethr_spinlock_t *lock)
1337
 
{
1338
 
#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
1339
 
    return pthread_spin_lock(&lock->spnlck);
1340
 
#else
1341
 
    return ETHR_INLINE_FUNC_NAME_(ethr_mutex_lock)(&lock->mtx);
1342
 
#endif
1343
 
}
1344
 
 
1345
 
#ifdef ETHR_USE_RWMTX_FALLBACK
1346
 
#define ETHR_RWLOCK_RWMTX_FALLBACK_NAME_(X) X
1347
 
#else
1348
 
#define ETHR_RWLOCK_RWMTX_FALLBACK_NAME_(X) ETHR_INLINE_FUNC_NAME_(X)
1349
 
#endif
1350
 
 
1351
 
static ETHR_INLINE int
1352
 
ETHR_INLINE_FUNC_NAME_(ethr_rwlock_init)(ethr_rwlock_t *lock)
1353
 
{
1354
 
#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
1355
 
    lock->counter = 0;
1356
 
    return pthread_spin_init(&lock->spnlck, 0);
1357
 
#else
1358
 
    return ethr_rwmutex_init(&lock->rwmtx);
1359
 
#endif
1360
 
}
1361
 
 
1362
 
static ETHR_INLINE int
1363
 
ETHR_INLINE_FUNC_NAME_(ethr_rwlock_destroy)(ethr_rwlock_t *lock)
1364
 
{
1365
 
#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
1366
 
    return pthread_spin_destroy(&lock->spnlck);
1367
 
#else
1368
 
    return ethr_rwmutex_destroy(&lock->rwmtx);
1369
 
#endif
1370
 
}
1371
 
 
1372
 
static ETHR_INLINE int
1373
 
ETHR_INLINE_FUNC_NAME_(ethr_read_unlock)(ethr_rwlock_t *lock)
1374
 
{
1375
 
#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
1376
 
    int res = pthread_spin_lock(&lock->spnlck);
1377
 
    if (res != 0)
1378
 
        return res;
1379
 
    lock->counter--;
1380
 
    return pthread_spin_unlock(&lock->spnlck);
1381
 
#else
1382
 
    return ETHR_RWLOCK_RWMTX_FALLBACK_NAME_(ethr_rwmutex_runlock)(&lock->rwmtx);
1383
 
#endif
1384
 
}
1385
 
 
1386
 
static ETHR_INLINE int
1387
 
ETHR_INLINE_FUNC_NAME_(ethr_read_lock)(ethr_rwlock_t *lock)
1388
 
{
1389
 
#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
1390
 
    int locked = 0;
1391
 
    do {
1392
 
        int res = pthread_spin_lock(&lock->spnlck);
1393
 
        if (res != 0)
1394
 
            return res;
1395
 
        if ((lock->counter & ETHR_RWLOCK_WRITERS) == 0) {
1396
 
            lock->counter++;
1397
 
            locked = 1;
1398
 
        }
1399
 
        res = pthread_spin_unlock(&lock->spnlck);
1400
 
        if (res != 0)
1401
 
            return res;
1402
 
    } while (!locked);
1403
 
    return 0;
1404
 
#else
1405
 
    return ETHR_RWLOCK_RWMTX_FALLBACK_NAME_(ethr_rwmutex_rlock)(&lock->rwmtx);
1406
 
#endif
1407
 
}
1408
 
 
1409
 
static ETHR_INLINE int
1410
 
ETHR_INLINE_FUNC_NAME_(ethr_write_unlock)(ethr_rwlock_t *lock)
1411
 
{
1412
 
#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
1413
 
    lock->counter = 0;
1414
 
    return pthread_spin_unlock(&lock->spnlck);
1415
 
#else
1416
 
    return ETHR_RWLOCK_RWMTX_FALLBACK_NAME_(ethr_rwmutex_rwunlock)(&lock->rwmtx);
1417
 
#endif
1418
 
}
1419
 
 
1420
 
static ETHR_INLINE int
1421
 
ETHR_INLINE_FUNC_NAME_(ethr_write_lock)(ethr_rwlock_t *lock)
1422
 
{
1423
 
#if defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
1424
 
    while (1) {
1425
 
        int res = pthread_spin_lock(&lock->spnlck);
1426
 
        if (res != 0)
1427
 
            return res;
1428
 
        lock->counter |= ETHR_RWLOCK_WRITERS;
1429
 
        if (lock->counter == ETHR_RWLOCK_WRITERS)
1430
 
            return 0;
1431
 
        res = pthread_spin_unlock(&lock->spnlck);
1432
 
        if (res != 0)
1433
 
            return res;
1434
 
    }
1435
 
#else
1436
 
    return ETHR_RWLOCK_RWMTX_FALLBACK_NAME_(ethr_rwmutex_rwlock)(&lock->rwmtx);
1437
 
#endif
1438
 
}
1439
 
 
1440
 
#endif /* #ifdef ETHR_TRY_INLINE_FUNCS */
1441
 
 
1442
 
#endif /* ETHR_HAVE_OPTIMIZED_LOCKS */
1443
 
 
1444
 
#if defined(ETHR_HAVE_OPTIMIZED_LOCKS) || defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
1445
 
# define ETHR_HAVE_OPTIMIZED_SPINLOCK
1446
 
#endif
1447
 
 
1448
731
#endif /* #ifndef ETHREAD_H__ */