Coverage Report

Created: 2018-08-29 13:53

/src/libevent/evthread.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2008-2012 Niels Provos, Nick Mathewson
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 * 1. Redistributions of source code must retain the above copyright
8
 *    notice, this list of conditions and the following disclaimer.
9
 * 2. Redistributions in binary form must reproduce the above copyright
10
 *    notice, this list of conditions and the following disclaimer in the
11
 *    documentation and/or other materials provided with the distribution.
12
 * 3. The name of the author may not be used to endorse or promote products
13
 *    derived from this software without specific prior written permission.
14
 *
15
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
 */
26
27
#include "event2/event-config.h"
28
#include "evconfig-private.h"
29
30
#ifndef EVENT__DISABLE_THREAD_SUPPORT
31
32
#include "event2/thread.h"
33
34
#include <stdlib.h>
35
#include <string.h>
36
37
#include "log-internal.h"
38
#include "mm-internal.h"
39
#include "util-internal.h"
40
#include "evthread-internal.h"
41
42
#ifdef EVTHREAD_EXPOSE_STRUCTS
43
#define GLOBAL
44
#else
45
#define GLOBAL static
46
#endif
47
48
#ifndef EVENT__DISABLE_DEBUG_MODE
49
extern int event_debug_created_threadable_ctx_;
50
extern int event_debug_mode_on_;
51
#endif
52
53
/* globals */
54
GLOBAL int evthread_lock_debugging_enabled_ = 0;
55
GLOBAL struct evthread_lock_callbacks evthread_lock_fns_ = {
56
  0, 0, NULL, NULL, NULL, NULL
57
};
58
GLOBAL unsigned long (*evthread_id_fn_)(void) = NULL;
59
GLOBAL struct evthread_condition_callbacks evthread_cond_fns_ = {
60
  0, NULL, NULL, NULL, NULL
61
};
62
63
/* Used for debugging */
64
static struct evthread_lock_callbacks original_lock_fns_ = {
65
  0, 0, NULL, NULL, NULL, NULL
66
};
67
static struct evthread_condition_callbacks original_cond_fns_ = {
68
  0, NULL, NULL, NULL, NULL
69
};
70
71
void
72
evthread_set_id_callback(unsigned long (*id_fn)(void))
73
0
{
74
0
  evthread_id_fn_ = id_fn;
75
0
}
76
77
struct evthread_lock_callbacks *evthread_get_lock_callbacks()
78
0
{
79
0
  return evthread_lock_debugging_enabled_
80
0
      ? &original_lock_fns_ : &evthread_lock_fns_;
81
0
}
82
struct evthread_condition_callbacks *evthread_get_condition_callbacks()
83
0
{
84
0
  return evthread_lock_debugging_enabled_
85
0
      ? &original_cond_fns_ : &evthread_cond_fns_;
86
0
}
87
void evthreadimpl_disable_lock_debugging_(void)
88
0
{
89
0
  evthread_lock_debugging_enabled_ = 0;
90
0
}
91
92
int
93
evthread_set_lock_callbacks(const struct evthread_lock_callbacks *cbs)
94
0
{
95
0
  struct evthread_lock_callbacks *target = evthread_get_lock_callbacks();
96
0
97
0
#ifndef EVENT__DISABLE_DEBUG_MODE
98
0
  if (event_debug_mode_on_) {
99
0
    if (event_debug_created_threadable_ctx_) {
100
0
        event_errx(1, "evthread initialization must be called BEFORE anything else!");
101
0
    }
102
0
  }
103
0
#endif
104
0
105
0
  if (!cbs) {
106
0
    if (target->alloc)
107
0
      event_warnx("Trying to disable lock functions after "
108
0
          "they have been set up will probaby not work.");
109
0
    memset(target, 0, sizeof(evthread_lock_fns_));
110
0
    return 0;
111
0
  }
112
0
  if (target->alloc) {
113
0
    /* Uh oh; we already had locking callbacks set up.*/
114
0
    if (target->lock_api_version == cbs->lock_api_version &&
115
0
      target->supported_locktypes == cbs->supported_locktypes &&
116
0
      target->alloc == cbs->alloc &&
117
0
      target->free == cbs->free &&
118
0
      target->lock == cbs->lock &&
119
0
      target->unlock == cbs->unlock) {
120
0
      /* no change -- allow this. */
121
0
      return 0;
122
0
    }
123
0
    event_warnx("Can't change lock callbacks once they have been "
124
0
        "initialized.");
125
0
    return -1;
126
0
  }
127
0
  if (cbs->alloc && cbs->free && cbs->lock && cbs->unlock) {
128
0
    memcpy(target, cbs, sizeof(evthread_lock_fns_));
129
0
    return event_global_setup_locks_(1);
130
0
  } else {
131
0
    return -1;
132
0
  }
133
0
}
134
135
int
136
evthread_set_condition_callbacks(const struct evthread_condition_callbacks *cbs)
137
0
{
138
0
  struct evthread_condition_callbacks *target = evthread_get_condition_callbacks();
139
0
140
0
#ifndef EVENT__DISABLE_DEBUG_MODE
141
0
  if (event_debug_mode_on_) {
142
0
    if (event_debug_created_threadable_ctx_) {
143
0
        event_errx(1, "evthread initialization must be called BEFORE anything else!");
144
0
    }
145
0
  }
146
0
#endif
147
0
148
0
  if (!cbs) {
149
0
    if (target->alloc_condition)
150
0
      event_warnx("Trying to disable condition functions "
151
0
          "after they have been set up will probaby not "
152
0
          "work.");
153
0
    memset(target, 0, sizeof(evthread_cond_fns_));
154
0
    return 0;
155
0
  }
156
0
  if (target->alloc_condition) {
157
0
    /* Uh oh; we already had condition callbacks set up.*/
158
0
    if (target->condition_api_version == cbs->condition_api_version &&
159
0
      target->alloc_condition == cbs->alloc_condition &&
160
0
      target->free_condition == cbs->free_condition &&
161
0
      target->signal_condition == cbs->signal_condition &&
162
0
      target->wait_condition == cbs->wait_condition) {
163
0
      /* no change -- allow this. */
164
0
      return 0;
165
0
    }
166
0
    event_warnx("Can't change condition callbacks once they "
167
0
        "have been initialized.");
168
0
    return -1;
169
0
  }
170
0
  if (cbs->alloc_condition && cbs->free_condition &&
171
0
      cbs->signal_condition && cbs->wait_condition) {
172
0
    memcpy(target, cbs, sizeof(evthread_cond_fns_));
173
0
  }
174
0
  if (evthread_lock_debugging_enabled_) {
175
0
    evthread_cond_fns_.alloc_condition = cbs->alloc_condition;
176
0
    evthread_cond_fns_.free_condition = cbs->free_condition;
177
0
    evthread_cond_fns_.signal_condition = cbs->signal_condition;
178
0
  }
179
0
  return 0;
180
0
}
181
182
0
#define DEBUG_LOCK_SIG  0xdeb0b10c
183
184
struct debug_lock {
185
  unsigned signature;
186
  unsigned locktype;
187
  unsigned long held_by;
188
  /* XXXX if we ever use read-write locks, we will need a separate
189
   * lock to protect count. */
190
  int count;
191
  void *lock;
192
};
193
194
static void *
195
debug_lock_alloc(unsigned locktype)
196
0
{
197
0
  struct debug_lock *result = mm_malloc(sizeof(struct debug_lock));
198
0
  if (!result)
199
0
    return NULL;
200
0
  if (original_lock_fns_.alloc) {
201
0
    if (!(result->lock = original_lock_fns_.alloc(
202
0
        locktype|EVTHREAD_LOCKTYPE_RECURSIVE))) {
203
0
      mm_free(result);
204
0
      return NULL;
205
0
    }
206
0
  } else {
207
0
    result->lock = NULL;
208
0
  }
209
0
  result->signature = DEBUG_LOCK_SIG;
210
0
  result->locktype = locktype;
211
0
  result->count = 0;
212
0
  result->held_by = 0;
213
0
  return result;
214
0
}
215
216
static void
217
debug_lock_free(void *lock_, unsigned locktype)
218
0
{
219
0
  struct debug_lock *lock = lock_;
220
0
  EVUTIL_ASSERT(lock->count == 0);
221
0
  EVUTIL_ASSERT(locktype == lock->locktype);
222
0
  EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
223
0
  if (original_lock_fns_.free) {
224
0
    original_lock_fns_.free(lock->lock,
225
0
        lock->locktype|EVTHREAD_LOCKTYPE_RECURSIVE);
226
0
  }
227
0
  lock->lock = NULL;
228
0
  lock->count = -100;
229
0
  lock->signature = 0x12300fda;
230
0
  mm_free(lock);
231
0
}
232
233
static void
234
evthread_debug_lock_mark_locked(unsigned mode, struct debug_lock *lock)
235
0
{
236
0
  EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
237
0
  ++lock->count;
238
0
  if (!(lock->locktype & EVTHREAD_LOCKTYPE_RECURSIVE))
239
0
    EVUTIL_ASSERT(lock->count == 1);
240
0
  if (evthread_id_fn_) {
241
0
    unsigned long me;
242
0
    me = evthread_id_fn_();
243
0
    if (lock->count > 1)
244
0
      EVUTIL_ASSERT(lock->held_by == me);
245
0
    lock->held_by = me;
246
0
  }
247
0
}
248
249
static int
250
debug_lock_lock(unsigned mode, void *lock_)
251
0
{
252
0
  struct debug_lock *lock = lock_;
253
0
  int res = 0;
254
0
  if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE)
255
0
    EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE));
256
0
  else
257
0
    EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0);
258
0
  if (original_lock_fns_.lock)
259
0
    res = original_lock_fns_.lock(mode, lock->lock);
260
0
  if (!res) {
261
0
    evthread_debug_lock_mark_locked(mode, lock);
262
0
  }
263
0
  return res;
264
0
}
265
266
static void
267
evthread_debug_lock_mark_unlocked(unsigned mode, struct debug_lock *lock)
268
0
{
269
0
  EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
270
0
  if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE)
271
0
    EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE));
272
0
  else
273
0
    EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0);
274
0
  if (evthread_id_fn_) {
275
0
    unsigned long me;
276
0
    me = evthread_id_fn_();
277
0
    EVUTIL_ASSERT(lock->held_by == me);
278
0
    if (lock->count == 1)
279
0
      lock->held_by = 0;
280
0
  }
281
0
  --lock->count;
282
0
  EVUTIL_ASSERT(lock->count >= 0);
283
0
}
284
285
static int
286
debug_lock_unlock(unsigned mode, void *lock_)
287
0
{
288
0
  struct debug_lock *lock = lock_;
289
0
  int res = 0;
290
0
  evthread_debug_lock_mark_unlocked(mode, lock);
291
0
  if (original_lock_fns_.unlock)
292
0
    res = original_lock_fns_.unlock(mode, lock->lock);
293
0
  return res;
294
0
}
295
296
static int
297
debug_cond_wait(void *cond_, void *lock_, const struct timeval *tv)
298
0
{
299
0
  int r;
300
0
  struct debug_lock *lock = lock_;
301
0
  EVUTIL_ASSERT(lock);
302
0
  EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature);
303
0
  EVLOCK_ASSERT_LOCKED(lock_);
304
0
  evthread_debug_lock_mark_unlocked(0, lock);
305
0
  r = original_cond_fns_.wait_condition(cond_, lock->lock, tv);
306
0
  evthread_debug_lock_mark_locked(0, lock);
307
0
  return r;
308
0
}
309
310
/* misspelled version for backward compatibility */
311
void
312
evthread_enable_lock_debuging(void)
313
0
{
314
0
  evthread_enable_lock_debugging();
315
0
}
316
317
void
318
evthread_enable_lock_debugging(void)
319
0
{
320
0
  struct evthread_lock_callbacks cbs = {
321
0
    EVTHREAD_LOCK_API_VERSION,
322
0
    EVTHREAD_LOCKTYPE_RECURSIVE,
323
0
    debug_lock_alloc,
324
0
    debug_lock_free,
325
0
    debug_lock_lock,
326
0
    debug_lock_unlock
327
0
  };
328
0
  if (evthread_lock_debugging_enabled_)
329
0
    return;
330
0
  memcpy(&original_lock_fns_, &evthread_lock_fns_,
331
0
      sizeof(struct evthread_lock_callbacks));
332
0
  memcpy(&evthread_lock_fns_, &cbs,
333
0
      sizeof(struct evthread_lock_callbacks));
334
0
335
0
  memcpy(&original_cond_fns_, &evthread_cond_fns_,
336
0
      sizeof(struct evthread_condition_callbacks));
337
0
  evthread_cond_fns_.wait_condition = debug_cond_wait;
338
0
  evthread_lock_debugging_enabled_ = 1;
339
0
340
0
  /* XXX return value should get checked. */
341
0
  event_global_setup_locks_(0);
342
0
}
343
344
int
345
evthread_is_debug_lock_held_(void *lock_)
346
0
{
347
0
  struct debug_lock *lock = lock_;
348
0
  if (! lock->count)
349
0
    return 0;
350
0
  if (evthread_id_fn_) {
351
0
    unsigned long me = evthread_id_fn_();
352
0
    if (lock->held_by != me)
353
0
      return 0;
354
0
  }
355
0
  return 1;
356
0
}
357
358
void *
359
evthread_debug_get_real_lock_(void *lock_)
360
0
{
361
0
  struct debug_lock *lock = lock_;
362
0
  return lock->lock;
363
0
}
364
365
void *
366
evthread_setup_global_lock_(void *lock_, unsigned locktype, int enable_locks)
367
0
{
368
0
  /* there are four cases here:
369
0
     1) we're turning on debugging; locking is not on.
370
0
     2) we're turning on debugging; locking is on.
371
0
     3) we're turning on locking; debugging is not on.
372
0
     4) we're turning on locking; debugging is on. */
373
0
374
0
  if (!enable_locks && original_lock_fns_.alloc == NULL) {
375
0
    /* Case 1: allocate a debug lock. */
376
0
    EVUTIL_ASSERT(lock_ == NULL);
377
0
    return debug_lock_alloc(locktype);
378
0
  } else if (!enable_locks && original_lock_fns_.alloc != NULL) {
379
0
    /* Case 2: wrap the lock in a debug lock. */
380
0
    struct debug_lock *lock;
381
0
    EVUTIL_ASSERT(lock_ != NULL);
382
0
383
0
    if (!(locktype & EVTHREAD_LOCKTYPE_RECURSIVE)) {
384
0
      /* We can't wrap it: We need a recursive lock */
385
0
      original_lock_fns_.free(lock_, locktype);
386
0
      return debug_lock_alloc(locktype);
387
0
    }
388
0
    lock = mm_malloc(sizeof(struct debug_lock));
389
0
    if (!lock) {
390
0
      original_lock_fns_.free(lock_, locktype);
391
0
      return NULL;
392
0
    }
393
0
    lock->lock = lock_;
394
0
    lock->locktype = locktype;
395
0
    lock->count = 0;
396
0
    lock->held_by = 0;
397
0
    return lock;
398
0
  } else if (enable_locks && ! evthread_lock_debugging_enabled_) {
399
0
    /* Case 3: allocate a regular lock */
400
0
    EVUTIL_ASSERT(lock_ == NULL);
401
0
    return evthread_lock_fns_.alloc(locktype);
402
0
  } else {
403
0
    /* Case 4: Fill in a debug lock with a real lock */
404
0
    struct debug_lock *lock = lock_ ? lock_ : debug_lock_alloc(locktype);
405
0
    EVUTIL_ASSERT(enable_locks &&
406
0
                  evthread_lock_debugging_enabled_);
407
0
    EVUTIL_ASSERT(lock->locktype == locktype);
408
0
    if (!lock->lock) {
409
0
      lock->lock = original_lock_fns_.alloc(
410
0
        locktype|EVTHREAD_LOCKTYPE_RECURSIVE);
411
0
      if (!lock->lock) {
412
0
        lock->count = -200;
413
0
        mm_free(lock);
414
0
        return NULL;
415
0
      }
416
0
    }
417
0
    return lock;
418
0
  }
419
0
}
420
421
422
#ifndef EVTHREAD_EXPOSE_STRUCTS
423
unsigned long
424
evthreadimpl_get_id_()
425
{
426
  return evthread_id_fn_ ? evthread_id_fn_() : 1;
427
}
428
void *
429
evthreadimpl_lock_alloc_(unsigned locktype)
430
{
431
#ifndef EVENT__DISABLE_DEBUG_MODE
432
  if (event_debug_mode_on_) {
433
    event_debug_created_threadable_ctx_ = 1;
434
  }
435
#endif
436
437
  return evthread_lock_fns_.alloc ?
438
      evthread_lock_fns_.alloc(locktype) : NULL;
439
}
440
void
441
evthreadimpl_lock_free_(void *lock, unsigned locktype)
442
{
443
  if (evthread_lock_fns_.free)
444
    evthread_lock_fns_.free(lock, locktype);
445
}
446
int
447
evthreadimpl_lock_lock_(unsigned mode, void *lock)
448
{
449
  if (evthread_lock_fns_.lock)
450
    return evthread_lock_fns_.lock(mode, lock);
451
  else
452
    return 0;
453
}
454
int
455
evthreadimpl_lock_unlock_(unsigned mode, void *lock)
456
{
457
  if (evthread_lock_fns_.unlock)
458
    return evthread_lock_fns_.unlock(mode, lock);
459
  else
460
    return 0;
461
}
462
void *
463
evthreadimpl_cond_alloc_(unsigned condtype)
464
{
465
#ifndef EVENT__DISABLE_DEBUG_MODE
466
  if (event_debug_mode_on_) {
467
    event_debug_created_threadable_ctx_ = 1;
468
  }
469
#endif
470
471
  return evthread_cond_fns_.alloc_condition ?
472
      evthread_cond_fns_.alloc_condition(condtype) : NULL;
473
}
474
void
475
evthreadimpl_cond_free_(void *cond)
476
{
477
  if (evthread_cond_fns_.free_condition)
478
    evthread_cond_fns_.free_condition(cond);
479
}
480
int
481
evthreadimpl_cond_signal_(void *cond, int broadcast)
482
{
483
  if (evthread_cond_fns_.signal_condition)
484
    return evthread_cond_fns_.signal_condition(cond, broadcast);
485
  else
486
    return 0;
487
}
488
int
489
evthreadimpl_cond_wait_(void *cond, void *lock, const struct timeval *tv)
490
{
491
  if (evthread_cond_fns_.wait_condition)
492
    return evthread_cond_fns_.wait_condition(cond, lock, tv);
493
  else
494
    return 0;
495
}
496
int
497
evthreadimpl_is_lock_debugging_enabled_(void)
498
{
499
  return evthread_lock_debugging_enabled_;
500
}
501
502
int
503
evthreadimpl_locking_enabled_(void)
504
{
505
  return evthread_lock_fns_.lock != NULL;
506
}
507
#endif
508
509
#endif