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

« back to all changes in this revision

Viewing changes to erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c

  • 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
/*
 
2
 * %CopyrightBegin%
 
3
 *
 
4
 * Copyright Ericsson AB 2010. All Rights Reserved.
 
5
 *
 
6
 * The contents of this file are subject to the Erlang Public License,
 
7
 * Version 1.1, (the "License"); you may not use this file except in
 
8
 * compliance with the License. You should have received a copy of the
 
9
 * Erlang Public License along with this software. If not, it can be
 
10
 * retrieved online at http://www.erlang.org/.
 
11
 *
 
12
 * Software distributed under the License is distributed on an "AS IS"
 
13
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 
14
 * the License for the specific language governing rights and limitations
 
15
 * under the License.
 
16
 *
 
17
 * %CopyrightEnd%
 
18
 */
 
19
 
 
20
/*
 
21
 * Stress tests of rwmutex implementation.
 
22
 *
 
23
 * Author: Rickard Green
 
24
 */
 
25
 
 
26
#include "erl_nif.h"
 
27
 
 
28
#ifdef __WIN32__
 
29
#  ifndef WIN32_LEAN_AND_MEAN
 
30
#    define WIN32_LEAN_AND_MEAN
 
31
#  endif
 
32
#  include <windows.h>
 
33
#else
 
34
#  include "ethread.h"
 
35
#  include "erl_misc_utils.h"
 
36
#  include <unistd.h>
 
37
#endif
 
38
 
 
39
#include <errno.h>
 
40
#include <stdio.h>
 
41
 
 
42
static int
 
43
fail(const char *file, int line, const char *function, const char *assertion);
 
44
 
 
45
#undef ASSERT
 
46
#define ASSERT(X) ((void) ((X) ? 1 : fail(__FILE__, __LINE__, __func__, #X)))
 
47
 
 
48
#ifdef __WIN32__
 
49
/*
 
50
 * We cannot access the ethread symbols directly; test
 
51
 * what we got in the nif api instead...
 
52
 */
 
53
#define HAVE_FREQREAD_SUPPORT 0
 
54
#define RWMUTEX_T ErlNifRWLock
 
55
#define RWMUTEX_CREATE(FR) enif_rwlock_create("dummy")
 
56
#define RWMUTEX_DESTROY enif_rwlock_destroy
 
57
#define RWMUTEX_WLOCK enif_rwlock_rwlock
 
58
#define RWMUTEX_TRYWLOCK enif_rwlock_tryrwlock
 
59
#define RWMUTEX_WUNLOCK enif_rwlock_rwunlock
 
60
#define RWMUTEX_TRYRLOCK enif_rwlock_tryrlock
 
61
#define RWMUTEX_RLOCK enif_rwlock_rlock
 
62
#define RWMUTEX_RUNLOCK enif_rwlock_runlock
 
63
#define THR_ID ErlNifTid
 
64
#define THR_CREATE(A, B, C, D) enif_thread_create("dummy", (A), (B), (C), (D))
 
65
#define THR_JOIN enif_thread_join
 
66
#define ATOMIC_T volatile LONG
 
67
#define ATOMIC_INIT(VarP, Val) (*(VarP) = (Val))
 
68
#define ATOMIC_SET(VarP, Val) (*(VarP) = (Val))
 
69
#define ATOMIC_READ(VarP) (*(VarP))
 
70
#define ATOMIC_INC InterlockedIncrement
 
71
#define ATOMIC_DEC InterlockedDecrement
 
72
 
 
73
#else
 
74
 
 
75
#ifdef ETHR_USE_OWN_RWMTX_IMPL__
 
76
#  define HAVE_FREQREAD_SUPPORT 1
 
77
#else
 
78
#  define HAVE_FREQREAD_SUPPORT 0
 
79
#endif
 
80
 
 
81
#define RWMUTEX_T ethr_rwmutex
 
82
static ethr_rwmutex *
 
83
RWMUTEX_CREATE(int freqread)
 
84
{
 
85
    ethr_rwmutex *rwmtx = enif_alloc(sizeof(ethr_rwmutex));
 
86
    ethr_rwmutex_opt rwmtx_opt = ETHR_RWMUTEX_OPT_DEFAULT_INITER;
 
87
    if (freqread)
 
88
        rwmtx_opt.type = ETHR_RWMUTEX_TYPE_FREQUENT_READ;
 
89
    ASSERT(rwmtx);
 
90
    ASSERT(ethr_rwmutex_init_opt(rwmtx, &rwmtx_opt) == 0);
 
91
    return rwmtx;
 
92
}
 
93
static void
 
94
RWMUTEX_DESTROY(ethr_rwmutex *rwmtx)
 
95
{
 
96
    ASSERT(ethr_rwmutex_destroy(rwmtx) == 0);
 
97
    enif_free(rwmtx);
 
98
}
 
99
#define RWMUTEX_TRYWLOCK ethr_rwmutex_tryrwlock
 
100
#define RWMUTEX_WLOCK ethr_rwmutex_rwlock
 
101
#define RWMUTEX_WUNLOCK ethr_rwmutex_rwunlock
 
102
#define RWMUTEX_TRYRLOCK ethr_rwmutex_tryrlock
 
103
#define RWMUTEX_RLOCK ethr_rwmutex_rlock
 
104
#define RWMUTEX_RUNLOCK ethr_rwmutex_runlock
 
105
#define THR_ID ethr_tid
 
106
#define THR_CREATE ethr_thr_create
 
107
#define THR_JOIN ethr_thr_join
 
108
#define ATOMIC_T ethr_atomic_t
 
109
#define ATOMIC_INIT ethr_atomic_init
 
110
#define ATOMIC_SET ethr_atomic_set
 
111
#define ATOMIC_READ ethr_atomic_read
 
112
#define ATOMIC_INC ethr_atomic_inc
 
113
#define ATOMIC_DEC ethr_atomic_dec
 
114
 
 
115
#endif
 
116
 
 
117
 
 
118
#if !defined(__func__)
 
119
#  if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L
 
120
#    if !defined(__GNUC__) ||  __GNUC__ < 2
 
121
#      define __func__ "[unknown_function]"
 
122
#    else
 
123
#      define __func__ __FUNCTION__
 
124
#    endif
 
125
#  endif
 
126
#endif
 
127
 
 
128
static void milli_sleep(int ms);
 
129
static int get_bool(ErlNifEnv* env, ERL_NIF_TERM term);
 
130
 
 
131
/*
 
132
 * Long rwlock testcase
 
133
 */
 
134
 
 
135
#define LONG_RW_NO_W_THREADS 6
 
136
#define LONG_RW_NO_THREADS 20
 
137
#define LONG_RW_NO_WLOCK_COUNT 100
 
138
 
 
139
typedef struct {
 
140
    RWMUTEX_T *rwlock;
 
141
    ATOMIC_T *is_wlocked;
 
142
    ATOMIC_T *is_rlocked;
 
143
    int *stop;
 
144
    int *count;
 
145
    int sleep;
 
146
} long_rw_t;
 
147
 
 
148
static void *
 
149
long_rw_w(void *varg)
 
150
{
 
151
    long_rw_t *arg = varg;
 
152
    int stop = 0;
 
153
    do {
 
154
        RWMUTEX_WLOCK(arg->rwlock);
 
155
        ASSERT(!ATOMIC_READ(arg->is_wlocked));
 
156
        ATOMIC_SET(arg->is_wlocked, 1);
 
157
        ASSERT(!ATOMIC_READ(arg->is_rlocked));
 
158
        milli_sleep(arg->sleep);
 
159
        if (++(*arg->count) > LONG_RW_NO_WLOCK_COUNT)
 
160
            stop = *arg->stop = 1;
 
161
        ATOMIC_SET(arg->is_wlocked, 0);
 
162
        ASSERT(!ATOMIC_READ(arg->is_rlocked));
 
163
        RWMUTEX_WUNLOCK(arg->rwlock);
 
164
    } while (!stop);
 
165
    return NULL;
 
166
}
 
167
 
 
168
static void *
 
169
long_rw_r(void *varg)
 
170
{
 
171
    long_rw_t *arg = varg;
 
172
    int stop;
 
173
    do {
 
174
        RWMUTEX_RLOCK(arg->rwlock);
 
175
        ASSERT(!ATOMIC_READ(arg->is_wlocked));
 
176
        ATOMIC_INC(arg->is_rlocked);
 
177
        milli_sleep(arg->sleep);
 
178
        stop = *arg->stop;
 
179
        ATOMIC_DEC(arg->is_rlocked);
 
180
        ASSERT(!ATOMIC_READ(arg->is_wlocked));
 
181
        RWMUTEX_RUNLOCK(arg->rwlock);
 
182
    } while (!stop);
 
183
    return NULL;
 
184
}
 
185
 
 
186
 
 
187
static ERL_NIF_TERM long_rw_test(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
 
188
{
 
189
    int res, freqread, i, count, stop;
 
190
    ATOMIC_T is_wlocked, is_rlocked;
 
191
    THR_ID tid[LONG_RW_NO_THREADS];
 
192
    long_rw_t arg;
 
193
    long_rw_t targ[LONG_RW_NO_THREADS];
 
194
 
 
195
    ATOMIC_INIT(&is_wlocked, 0);
 
196
    ATOMIC_INIT(&is_rlocked, 0);
 
197
 
 
198
    freqread = 0;
 
199
 
 
200
    arg.is_wlocked = &is_wlocked;
 
201
    arg.is_rlocked = &is_rlocked;
 
202
    arg.count = &count;
 
203
    arg.stop = &stop;
 
204
 
 
205
 restart:
 
206
 
 
207
    stop = 0;
 
208
    count = 0;
 
209
 
 
210
    arg.rwlock = RWMUTEX_CREATE(freqread);
 
211
 
 
212
    ASSERT(arg.rwlock);
 
213
 
 
214
    for (i = 0; i < LONG_RW_NO_W_THREADS; i++) {
 
215
        targ[i] = arg;
 
216
        targ[i].sleep = 100 + i*10;
 
217
        ASSERT(THR_CREATE(&tid[i], long_rw_w, &targ[i], NULL) == 0);
 
218
    }
 
219
    for (; i < LONG_RW_NO_THREADS; i++) {
 
220
        targ[i] = arg;
 
221
        targ[i].sleep = 100;
 
222
        ASSERT(THR_CREATE(&tid[i], long_rw_r, &targ[i], NULL) == 0);
 
223
    }
 
224
    for (i = 0; i < LONG_RW_NO_THREADS; i++)
 
225
        ASSERT(THR_JOIN(tid[i], NULL) == 0);
 
226
 
 
227
    ASSERT(!ATOMIC_READ(arg.is_wlocked));
 
228
    ASSERT(!ATOMIC_READ(arg.is_rlocked));
 
229
 
 
230
    RWMUTEX_DESTROY(arg.rwlock);
 
231
 
 
232
    if (HAVE_FREQREAD_SUPPORT && !freqread) {
 
233
        freqread = 1;
 
234
        goto restart;
 
235
    }
 
236
 
 
237
    if (freqread)
 
238
        return enif_make_atom(env, "ok");
 
239
    else
 
240
        return enif_make_tuple2(env,
 
241
                                enif_make_atom(env,
 
242
                                               "comment"),
 
243
                                enif_make_string(env,
 
244
                                                 "No frequent read test made.",
 
245
                                                 ERL_NIF_LATIN1));
 
246
}
 
247
 
 
248
/*
 
249
 * Hammer rwlock testcase
 
250
 */
 
251
 
 
252
#define HAMMER_RW_NO_W_THREADS 6
 
253
#define HAMMER_RW_NO_THREADS 20
 
254
#define HAMMER_RW_NO_WLOCK_COUNT 1000000
 
255
 
 
256
typedef struct {
 
257
    RWMUTEX_T *rwlock;
 
258
    ATOMIC_T is_locked;
 
259
    int lock_check;
 
260
    int stop;
 
261
    int count;
 
262
} hammer_rw_t;
 
263
 
 
264
static void *
 
265
hammer_rw_w(void *varg)
 
266
{
 
267
    hammer_rw_t *arg = varg;
 
268
    int stop = 0;
 
269
    do {
 
270
        RWMUTEX_WLOCK(arg->rwlock);
 
271
        if (arg->lock_check) {
 
272
            ASSERT(!ATOMIC_READ(&arg->is_locked));
 
273
            ATOMIC_SET(&arg->is_locked, -1);
 
274
        }
 
275
        if (++arg->count > HAMMER_RW_NO_WLOCK_COUNT)
 
276
            stop = arg->stop = 1;
 
277
        if (arg->lock_check) {
 
278
            ASSERT(ATOMIC_READ(&arg->is_locked) == -1);
 
279
            ATOMIC_SET(&arg->is_locked, 0);
 
280
        }
 
281
        RWMUTEX_WUNLOCK(arg->rwlock);
 
282
    } while (!stop);
 
283
    return NULL;
 
284
}
 
285
 
 
286
static void *
 
287
hammer_rw_r(void *varg)
 
288
{
 
289
    hammer_rw_t *arg = varg;
 
290
    int stop;
 
291
    do {
 
292
        RWMUTEX_RLOCK(arg->rwlock);
 
293
        if (arg->lock_check) {
 
294
            ASSERT(ATOMIC_READ(&arg->is_locked) >= 0);
 
295
            ATOMIC_INC(&arg->is_locked);
 
296
        }
 
297
        stop = arg->stop;
 
298
        if (arg->lock_check) {
 
299
            ASSERT(ATOMIC_READ(&arg->is_locked) > 0);
 
300
            ATOMIC_DEC(&arg->is_locked);
 
301
        }
 
302
        RWMUTEX_RUNLOCK(arg->rwlock);
 
303
    } while (!stop); 
 
304
    return NULL;
 
305
}
 
306
 
 
307
 
 
308
static ERL_NIF_TERM hammer_rw_test(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
 
309
{
 
310
    hammer_rw_t arg;
 
311
    char buf[10];
 
312
    int res, freqread, i;
 
313
    THR_ID tid[HAMMER_RW_NO_THREADS];
 
314
 
 
315
    if (argc != 1)
 
316
        goto badarg;
 
317
 
 
318
    arg.lock_check = get_bool(env, argv[0]);
 
319
    if (arg.lock_check < 0)
 
320
        goto badarg;
 
321
 
 
322
    ATOMIC_INIT(&arg.is_locked, 0);
 
323
 
 
324
    freqread = 0;
 
325
 
 
326
 restart:
 
327
    arg.stop = 0;
 
328
    arg.count = 0;
 
329
 
 
330
    arg.rwlock = RWMUTEX_CREATE(freqread);
 
331
 
 
332
    ASSERT(arg.rwlock);
 
333
 
 
334
    for (i = 0; i < HAMMER_RW_NO_W_THREADS; i++)
 
335
        ASSERT(THR_CREATE(&tid[i], hammer_rw_w, &arg, NULL) == 0);
 
336
    for (; i < HAMMER_RW_NO_THREADS; i++)
 
337
        ASSERT(THR_CREATE(&tid[i], hammer_rw_r, &arg, NULL) == 0);
 
338
    for (i = 0; i < HAMMER_RW_NO_THREADS; i++)
 
339
        ASSERT(THR_JOIN(tid[i], NULL) == 0);
 
340
 
 
341
    ASSERT(!ATOMIC_READ(&arg.is_locked));
 
342
 
 
343
    RWMUTEX_DESTROY(arg.rwlock);
 
344
 
 
345
    if (HAVE_FREQREAD_SUPPORT && !freqread) {
 
346
        freqread = 1;
 
347
        goto restart;
 
348
    }
 
349
 
 
350
    if (freqread)
 
351
        return enif_make_atom(env, "ok");
 
352
    else
 
353
        return enif_make_tuple2(env,
 
354
                                enif_make_atom(env,
 
355
                                               "comment"),
 
356
                                enif_make_string(env,
 
357
                                                 "No frequent read test made.",
 
358
                                                 ERL_NIF_LATIN1));
 
359
 badarg:
 
360
    return enif_make_badarg(env);
 
361
}
 
362
 
 
363
/*
 
364
 * Hammer try rwlock testcase
 
365
 */
 
366
 
 
367
#define HAMMER_TRYRW_NO_W_THREADS 10
 
368
#define HAMMER_TRYRW_NO_THREADS 20
 
369
#define HAMMER_TRYRW_NO_WLOCK_COUNT 10000000
 
370
#define HAMMER_TRYRW_NO_RLOCK_COUNT 10000000
 
371
#define HAMMER_TRYRW_NO_WLOCK_WAIT_COUNT ((10*HAMMER_TRYRW_NO_WLOCK_COUNT)/8)
 
372
#define HAMMER_TRYRW_NO_RLOCK_WAIT_COUNT ((10*HAMMER_TRYRW_NO_RLOCK_COUNT)/8)
 
373
 
 
374
typedef struct {
 
375
    RWMUTEX_T *rwlock;
 
376
    ATOMIC_T is_locked;
 
377
    int lock_check;
 
378
    int w_count;
 
379
    ATOMIC_T r_count;
 
380
} hammer_tryrw_t;
 
381
 
 
382
static void *
 
383
hammer_tryrw_w(void *varg)
 
384
{
 
385
    hammer_tryrw_t *arg = varg;
 
386
    int stop = 0;
 
387
    int wait = 0;
 
388
    do {
 
389
        while (EBUSY == RWMUTEX_TRYWLOCK(arg->rwlock));
 
390
        if (arg->lock_check) {
 
391
            ASSERT(!ATOMIC_READ(&arg->is_locked));
 
392
            ATOMIC_SET(&arg->is_locked, -1);
 
393
        }
 
394
        if (++arg->w_count > HAMMER_TRYRW_NO_WLOCK_COUNT)
 
395
            stop = 1;
 
396
        else if (arg->w_count > HAMMER_TRYRW_NO_RLOCK_WAIT_COUNT)
 
397
            wait = 1;
 
398
        if (arg->lock_check) {
 
399
            ASSERT(ATOMIC_READ(&arg->is_locked) == -1);
 
400
            ATOMIC_SET(&arg->is_locked, 0);
 
401
        }
 
402
        RWMUTEX_WUNLOCK(arg->rwlock);
 
403
        if (wait)
 
404
            milli_sleep(1);
 
405
    } while (!stop);
 
406
    return NULL;
 
407
}
 
408
 
 
409
static void *
 
410
hammer_tryrw_r(void *varg)
 
411
{
 
412
    hammer_tryrw_t *arg = varg;
 
413
    long r_count;
 
414
    int stop = 0;
 
415
    int wait = 0;
 
416
    do {
 
417
        while (EBUSY == RWMUTEX_TRYRLOCK(arg->rwlock));
 
418
        if (arg->lock_check) {
 
419
            ASSERT(ATOMIC_READ(&arg->is_locked) >= 0);
 
420
            ATOMIC_INC(&arg->is_locked);
 
421
        }
 
422
        ATOMIC_INC(&arg->r_count);
 
423
        r_count = ATOMIC_READ(&arg->r_count);
 
424
        if (r_count > HAMMER_TRYRW_NO_RLOCK_COUNT)
 
425
            stop = 1;
 
426
        else if (r_count > HAMMER_TRYRW_NO_RLOCK_WAIT_COUNT)
 
427
            wait = 1;
 
428
        if (arg->lock_check) {
 
429
            ASSERT(ATOMIC_READ(&arg->is_locked) > 0);
 
430
            ATOMIC_DEC(&arg->is_locked);
 
431
        }
 
432
        RWMUTEX_RUNLOCK(arg->rwlock);
 
433
        if (wait)
 
434
            milli_sleep(1);
 
435
    } while (!stop);
 
436
    return NULL;
 
437
}
 
438
 
 
439
 
 
440
static ERL_NIF_TERM hammer_tryrw_test(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
 
441
{
 
442
    hammer_tryrw_t arg;
 
443
    char buf[10];
 
444
    int res, freqread, i;
 
445
    THR_ID tid[HAMMER_TRYRW_NO_THREADS];
 
446
 
 
447
    if (argc != 1)
 
448
        goto badarg;
 
449
 
 
450
    arg.lock_check = get_bool(env, argv[0]);
 
451
    if (arg.lock_check < 0)
 
452
        goto badarg;
 
453
 
 
454
    ATOMIC_INIT(&arg.is_locked, 0);
 
455
    freqread = 0;
 
456
 
 
457
 restart:
 
458
 
 
459
    arg.w_count = 0;
 
460
    ATOMIC_INIT(&arg.r_count, 0);
 
461
 
 
462
    arg.rwlock = RWMUTEX_CREATE(freqread);
 
463
 
 
464
    ASSERT(arg.rwlock);
 
465
 
 
466
    for (i = 0; i < HAMMER_TRYRW_NO_W_THREADS; i++)
 
467
        ASSERT(THR_CREATE(&tid[i], hammer_tryrw_w, &arg, NULL) == 0);
 
468
    for (; i < HAMMER_TRYRW_NO_THREADS; i++)
 
469
        ASSERT(THR_CREATE(&tid[i], hammer_tryrw_r, &arg, NULL) == 0);
 
470
    for (i = 0; i < HAMMER_TRYRW_NO_THREADS; i++)
 
471
        ASSERT(THR_JOIN(tid[i], NULL) == 0);
 
472
 
 
473
    ASSERT(!ATOMIC_READ(&arg.is_locked));
 
474
 
 
475
    RWMUTEX_DESTROY(arg.rwlock);
 
476
 
 
477
    if (HAVE_FREQREAD_SUPPORT && !freqread) {
 
478
        freqread = 1;
 
479
        goto restart;
 
480
    }
 
481
 
 
482
    if (freqread)
 
483
        return enif_make_atom(env, "ok");
 
484
    else
 
485
        return enif_make_tuple2(env,
 
486
                                enif_make_atom(env,
 
487
                                               "comment"),
 
488
                                enif_make_string(env,
 
489
                                                 "No frequent read test made.",
 
490
                                                 ERL_NIF_LATIN1));
 
491
 badarg:
 
492
    return enif_make_badarg(env);
 
493
}
 
494
 
 
495
typedef struct {
 
496
    int lock_check;
 
497
    ATOMIC_T is_locked;
 
498
    RWMUTEX_T *rwlock;
 
499
} rwlock_resource_t;
 
500
 
 
501
static void
 
502
rwlock_destructor(ErlNifEnv* env, void* obj)
 
503
{
 
504
    rwlock_resource_t *rwlr = obj;
 
505
    if (rwlr->lock_check)
 
506
        ASSERT(!ATOMIC_READ(&rwlr->is_locked));
 
507
    RWMUTEX_DESTROY(rwlr->rwlock);
 
508
}
 
509
 
 
510
/*
 
511
 * create_rwlock(FreqRead, LockCheck)
 
512
 */
 
513
 
 
514
static ERL_NIF_TERM
 
515
create_rwlock(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
 
516
{
 
517
    int lock_check, freqread;
 
518
    ERL_NIF_TERM rwlock_term;
 
519
    rwlock_resource_t *rwlr;
 
520
    char buf[100];
 
521
 
 
522
    if (argc != 2)
 
523
        goto badarg;
 
524
 
 
525
    freqread = get_bool(env, argv[0]);
 
526
    if (freqread < 0)
 
527
        goto badarg;
 
528
 
 
529
    if (!HAVE_FREQREAD_SUPPORT && freqread)
 
530
        return enif_make_atom(env, "enotsup");
 
531
 
 
532
    lock_check = get_bool(env, argv[1]);
 
533
    if (lock_check < 0)
 
534
        goto badarg;
 
535
 
 
536
    rwlr = enif_alloc_resource(enif_priv_data(env), sizeof(rwlock_resource_t));
 
537
    rwlr->lock_check = lock_check;
 
538
    ATOMIC_INIT(&rwlr->is_locked, 0);
 
539
    rwlr->rwlock = RWMUTEX_CREATE(freqread);
 
540
    rwlock_term = enif_make_resource(env, rwlr);
 
541
    enif_release_resource(rwlr);
 
542
    return rwlock_term;
 
543
 
 
544
 badarg:
 
545
    return enif_make_badarg(env);
 
546
}
 
547
 
 
548
/*
 
549
 * rwlock_op(RWLock, Blocking, WriteOp, WaitTime) 
 
550
 */
 
551
 
 
552
static ERL_NIF_TERM
 
553
rwlock_op(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
 
554
{
 
555
    rwlock_resource_t *rwlr;
 
556
    int blocking, write, wait_locked, wait_unlocked;
 
557
 
 
558
    if (argc != 5)
 
559
        goto badarg;
 
560
 
 
561
    if (!enif_get_resource(env, argv[0], enif_priv_data(env), (void **) &rwlr))
 
562
        goto badarg;
 
563
 
 
564
    blocking = get_bool(env, argv[1]);
 
565
    if (blocking < 0)
 
566
        goto badarg;
 
567
 
 
568
    write = get_bool(env, argv[2]);
 
569
    if (write < 0)
 
570
        goto badarg;
 
571
 
 
572
    if (!enif_get_int(env, argv[3], &wait_locked))
 
573
        goto badarg;
 
574
    if (wait_locked < 0)
 
575
        goto badarg;
 
576
 
 
577
    if (!enif_get_int(env, argv[4], &wait_unlocked))
 
578
        goto badarg;
 
579
    if (wait_unlocked < 0)
 
580
        goto badarg;
 
581
 
 
582
    if (write) {
 
583
        if (blocking)
 
584
            RWMUTEX_WLOCK(rwlr->rwlock);
 
585
        else
 
586
            while (EBUSY == RWMUTEX_TRYWLOCK(rwlr->rwlock));
 
587
        if (rwlr->lock_check) {
 
588
            ASSERT(!ATOMIC_READ(&rwlr->is_locked));
 
589
            ATOMIC_SET(&rwlr->is_locked, -1);
 
590
        }
 
591
    }
 
592
    else {
 
593
        if (blocking)
 
594
            RWMUTEX_RLOCK(rwlr->rwlock);
 
595
        else
 
596
            while (EBUSY == RWMUTEX_TRYRLOCK(rwlr->rwlock));
 
597
        if (rwlr->lock_check) {
 
598
            ASSERT(ATOMIC_READ(&rwlr->is_locked) >= 0);
 
599
            ATOMIC_INC(&rwlr->is_locked);
 
600
        }
 
601
    }
 
602
 
 
603
    if (wait_locked)
 
604
        milli_sleep(wait_locked);
 
605
 
 
606
    if (write) {
 
607
        if (rwlr->lock_check) {
 
608
            ASSERT(ATOMIC_READ(&rwlr->is_locked) == -1);
 
609
            ATOMIC_SET(&rwlr->is_locked, 0);
 
610
        }
 
611
        RWMUTEX_WUNLOCK(rwlr->rwlock);
 
612
    }
 
613
    else {
 
614
        if (rwlr->lock_check) {
 
615
            ASSERT(ATOMIC_READ(&rwlr->is_locked) > 0);
 
616
            ATOMIC_DEC(&rwlr->is_locked);
 
617
        }
 
618
        RWMUTEX_RUNLOCK(rwlr->rwlock);
 
619
    }
 
620
 
 
621
    if (wait_unlocked)
 
622
        milli_sleep(wait_unlocked);
 
623
 
 
624
    return enif_make_atom(env, "ok");
 
625
 badarg:
 
626
    return enif_make_badarg(env);
 
627
}
 
628
 
 
629
static int load_nif_lib(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
 
630
{
 
631
    *priv_data = enif_open_resource_type(env,
 
632
                                         NULL,
 
633
                                         "rwlock_resource",
 
634
                                         rwlock_destructor,
 
635
                                         ERL_NIF_RT_CREATE,
 
636
                                         NULL);
 
637
    if (*priv_data)
 
638
        return 0;
 
639
    else
 
640
        return -1;
 
641
}
 
642
 
 
643
/*
 
644
 * 0 -> false
 
645
 * >0 -> true
 
646
 * <0 -> error
 
647
 */
 
648
 
 
649
static int
 
650
get_bool(ErlNifEnv* env, ERL_NIF_TERM term)
 
651
{
 
652
    int res;
 
653
    char buf[10];
 
654
 
 
655
    res = enif_get_atom(env, term, buf, sizeof(buf), ERL_NIF_LATIN1);
 
656
    if (res == 0)
 
657
        return -1;
 
658
    if (strcmp("false", buf) == 0)
 
659
        return 0;
 
660
    else if (strcmp("true", buf) == 0)
 
661
        return 1;
 
662
    else
 
663
        return -1;
 
664
}
 
665
 
 
666
static int
 
667
fail(const char *file, int line, const char *function, const char *assertion)
 
668
{
 
669
    fprintf(stderr, "%s:%d: Assertion failed in %s(): %s\n",
 
670
            file, line, function, assertion);
 
671
    abort();
 
672
}
 
673
 
 
674
static void
 
675
milli_sleep(int ms)
 
676
{
 
677
#ifdef __WIN32__
 
678
    Sleep(ms);
 
679
#else
 
680
    while (erts_milli_sleep(ms) != 0);
 
681
#endif
 
682
}
 
683
 
 
684
static ErlNifFunc nif_funcs[] = {
 
685
    {"long_rw_test", 0, long_rw_test},
 
686
    {"hammer_rw_test", 1, hammer_rw_test},
 
687
    {"hammer_tryrw_test", 1, hammer_tryrw_test},
 
688
    {"create_rwlock", 2, create_rwlock},
 
689
    {"rwlock_op", 5, rwlock_op}
 
690
};
 
691
 
 
692
ERL_NIF_INIT(mtx_SUITE, nif_funcs, load_nif_lib, NULL, NULL, NULL)