-
Notifications
You must be signed in to change notification settings - Fork 0
/
pintos_thread.h
118 lines (105 loc) · 3.46 KB
/
pintos_thread.h
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/*
* Trivial wrapper of pthread(3) calls to Pintos-compatible
* API calls for CS140 PS1 (Winter Quarter, 2012).
*
* Should run under Unix/Linux/OS X. Just #include this header
* in your code and compile with the '-lpthread' flag, e.g.:
* cc -o myBinary myCode.c -lpthread
*/
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
// So we can hopefully ensure that locks and condition variables
// are initialised before use.
#define LOCK_COND_INIT_MAGIC 0x4a3acd94
struct lock {
int init;
pthread_mutex_t mutex;
};
struct condition {
int init;
pthread_cond_t cond;
};
// Sush up -Wall if any of these are unused.
static void lock_init(struct lock *lock) __attribute__((unused));
static void lock_acquire(struct lock *lock) __attribute__((unused));
static void lock_release(struct lock *lock) __attribute__((unused));
static void cond_init(struct condition *cond) __attribute__((unused));
static void cond_wait(struct condition *cond, struct lock *lock) __attribute__((unused));
static void cond_signal(struct condition *cond, struct lock *lock) __attribute__((unused));
static void cond_broadcast(struct condition *cond, struct lock *lock) __attribute__((unused));
static void
__assert(int satisfied, const char *message)
{
if (!satisfied) {
fprintf(stderr, "FATAL ERROR: %s\n", message);
exit(1);
}
}
static void
lock_init(struct lock *lock)
{
lock->init = LOCK_COND_INIT_MAGIC;
pthread_mutex_init(&lock->mutex, NULL);
}
static void
lock_acquire(struct lock *lock)
{
__assert(lock->init == LOCK_COND_INIT_MAGIC,
"lock_acquire used before lock was initialised!");
pthread_mutex_lock(&lock->mutex);
}
static void
lock_release(struct lock *lock)
{
__assert(lock->init == LOCK_COND_INIT_MAGIC,
"lock_release used before lock was initialised!");
__assert(pthread_mutex_trylock(&lock->mutex) != 0,
"lock_release on unlocked lock!");
pthread_mutex_unlock(&lock->mutex);
}
static void
cond_init(struct condition *cond)
{
cond->init = LOCK_COND_INIT_MAGIC;
pthread_cond_init(&cond->cond, NULL);
}
static void
cond_wait(struct condition *cond, struct lock *lock)
{
// Assert the lock is already held. It should be held
// by this caller, so while this simple check won't
// catch all bad invocations (somebody else could have
// locked it, rather than us) at least it's a start...
__assert(pthread_mutex_trylock(&lock->mutex) != 0,
"cond_wait not called with lock held!");
__assert(cond->init == LOCK_COND_INIT_MAGIC,
"cond_wait used before cond was initialised!");
__assert(lock->init == LOCK_COND_INIT_MAGIC,
"cond_wait used before lock was initialised!");
pthread_cond_wait(&cond->cond, &lock->mutex);
}
static void
cond_signal(struct condition *cond, struct lock *lock)
{
// See comment in cond_wait().
__assert(pthread_mutex_trylock(&lock->mutex) != 0,
"cond_signal not called with lock held!");
__assert(cond->init == LOCK_COND_INIT_MAGIC,
"cond_signal used before cond was initialised!");
__assert(lock->init == LOCK_COND_INIT_MAGIC,
"cond_signal used before lock was initialised!");
pthread_cond_signal(&cond->cond);
}
static void
cond_broadcast(struct condition *cond, struct lock *lock)
{
// See comment in cond_wait().
__assert(pthread_mutex_trylock(&lock->mutex) != 0,
"cond_broadcast not called with lock held!");
__assert(cond->init == LOCK_COND_INIT_MAGIC,
"cond_broadcast used before cond was initialised!");
__assert(lock->init == LOCK_COND_INIT_MAGIC,
"cond_broadcast used before lock was initialised!");
pthread_cond_broadcast(&cond->cond);
}