-
Notifications
You must be signed in to change notification settings - Fork 1
/
reentrant_lock.c
90 lines (78 loc) · 1.89 KB
/
reentrant_lock.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#define _GNU_SOURCE
#ifdef __APPLE__
#define _XOPEN_SOURCE
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include "reentrant_lock.h"
// Allocates and returns a new reentrant lock. Sets errno and returns NULL if
// initialization failed.
reentrant_lock_t* reentrant_lock_init()
{
mutex_t* mu = mutex_init();
if (!mu)
{
return NULL;
}
mutex_t* owner_mu = mutex_init();
if (!owner_mu)
{
mutex_dispose(mu);
return NULL;
}
reentrant_lock_t* lock = (reentrant_lock_t*) malloc(sizeof(reentrant_lock_t));
if (!lock)
{
errno = ENOMEM;
mutex_dispose(mu);
mutex_dispose(owner_mu);
return NULL;
}
lock->mu = mu;
lock->owner = NULL;
lock->owner_mu = owner_mu;
lock->count = 0;
return lock;
}
// Releases the lock resources.
void reentrant_lock_dispose(reentrant_lock_t* lock)
{
mutex_dispose(lock->owner_mu);
mutex_dispose(lock->mu);
free(lock);
}
// Acquires the lock. This will block if the calling thread does not own the
// lock. Once the lock has been acquired, its counter will be incremented.
void reentrant_lock(reentrant_lock_t* lock)
{
pthread_t tid = pthread_self();
mutex_lock(lock->owner_mu);
if (pthread_equal(lock->owner, tid))
{
// Reentrant acquire.
lock->count++;
mutex_unlock(lock->owner_mu);
return;
}
mutex_unlock(lock->owner_mu);
mutex_lock(lock->mu);
mutex_lock(lock->owner_mu);
lock->owner = tid;
lock->count++;
mutex_unlock(lock->owner_mu);
}
// Decrements the lock's counter. If the counter reaches zero, the lock is
// released.
void reentrant_unlock(reentrant_lock_t* lock)
{
mutex_lock(lock->owner_mu);
lock->count--;
if (lock->count == 0)
{
mutex_unlock(lock->mu);
lock->owner = NULL;
}
mutex_unlock(lock->owner_mu);
}