-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy paththread.h
225 lines (178 loc) · 7.95 KB
/
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#ifndef _THREAD_H_
#define _THREAD_H_
/* Macro to flag places where implementation is needed in thread.c */
#define TBD() do { \
printf("%s:%d: %s: please implement this functionality\n", \
__FILE__, __LINE__, __FUNCTION__); \
exit(1); \
} while (0)
#define THREAD_MAX_THREADS 1024 /* maximum number of threads */
#define THREAD_MIN_STACK 32768 /* minimum per-thread execution stack */
typedef int Tid; /* A thread identifier */
/*
* Valid thread identifiers (Tid) range between 0 and THREAD_MAX_THREADS-1. The
* first thread to run must have a thread id of 0. Note that this thread is the
* main thread, i.e., it is created before the first call to thread_create.
*
* Negative Tid values are used for error codes or control codes.
*/
enum {
THREAD_ANY = -1,
THREAD_SELF = -2,
THREAD_INVALID = -3,
THREAD_NONE = -4,
THREAD_NOMORE = -5,
THREAD_NOMEMORY = -6,
THREAD_FAILED = -7
};
/* Returns TRUE (1) if the ret is a non-negative value. Note that this does not
* catch invalid thread ids that are too large (i.e., >THREAD_MAX_THREADS-1).
*/
static inline int
thread_ret_ok(Tid ret)
{
return (ret >= 0 ? 1 : 0);
}
/*******************************************************
* Assignment 1: Implement the following six functions *
*******************************************************/
/* Perform any initialization needed by your threading system. */
void thread_init(void);
/* Return the thread identifier of the currently running thread. */
Tid thread_id(void);
/* thread_create should create a thread that starts running the function
* fn(arg). Upon success, return the thread identifier. On failure, return the
* following:
*
* THREAD_NOMORE: no more threads can be created.
* THREAD_NOMEMORY: no more memory available to create a thread stack.
*/
Tid thread_create(void (*fn) (void *), void *arg);
/* thread_yield should suspend the calling thread and run the thread with
* identifier tid. The calling thread is put in the ready queue.
* tid can be the identifier of any available thread or the following constants:
*
* THREAD_ANY: run any thread in the ready queue.
* THREAD_SELF: continue executing calling thread, for debugging purposes.
*
* Upon success, return the identifier of the thread that was switched to when
* the calling thread yielded. Note that this function will not return to the
* calling thread until it runs again later.
* Upon failure, the calling thread continues running, and returns the
* following:
*
* THREAD_INVALID: identifier tid does not correspond to a valid thread.
* THREAD_NONE: no more threads, other than the caller, are available to
* run; this can happen in response to a call with tid set to
* THREAD_ANY.
*/
Tid thread_yield(Tid tid);
/* thread_exit should ensure that the calling thread does not run after this
* call, i.e., this function should never return. In the future, a new thread
* should be able to reuse this thread's identifier. If there are other threads
* in the system, one of them should be run. If there are no other threads
* (i.e., this is the last thread invoking thread_exit), then the process
* should exit. The function has no return values.
*
* In A1, the exit_code is unused. In A2, the exit_code should be copied to a
* thread that waits for the exiting thread.
*/
void thread_exit(int exit_code);
/* Kill a thread whose identifier is tid. When a thread is killed, it should not
* run any further. The calling thread continues to execute and receives the
* result of the call. tid can be the identifier of any available thread.
*
* Upon success, return the identifier of the thread that was killed. Upon
* failure, return the following:
*
* THREAD_INVALID: identifier tid does not correspond to a valid thread (e.g.,
* any negative value of tid), or it is the current thread.
*/
Tid thread_kill(Tid tid);
/***************************************************
* Assignment 2: Implement the following functions *
**************************************************/
/* Create a queue of waiting threads. Initially, the queue is empty. */
struct wait_queue *wait_queue_create(void);
/* Destroy the wait queue. Be sure to check that the queue is empty when it is
* being destroyed.
*/
void wait_queue_destroy(struct wait_queue *wq);
/* Suspend the calling thread and run some other thread. The calling thread is
* put in the wait queue.
*
* Upon success, return the identifier of the thread that was switched to when
* the calling thread was put to sleep. Note that this function will not return
* to the calling thread until it runs again later.
* Upon failure, the calling thread continues running, and returns the
* following:
*
* THREAD_INVALID: queue is invalid, e.g., it is NULL.
* THREAD_NONE: no more threads, other than the caller, are available to
* run.
*/
Tid thread_sleep(struct wait_queue *queue);
/* Wake up one or more threads that are suspended in the wait queue. These
* threads are put in the ready queue. The calling thread continues to execute
* and receives the result of the call. When "all" is 0, then one thread is
* woken up. When "all" is 1, all suspended threads are woken up. Wake up
* threads in FIFO order, i.e., first thread to sleep must be woken up
* first. The function returns the number of threads that were woken up. It can
* return zero if there were no suspended threads in the wait queue.
*/
int thread_wakeup(struct wait_queue *queue, int all);
/* Suspend the current thread until the target thread (i.e., the thread whose
* identifier is tid) exits. If the target thread has already exited, then
* thread_wait() returns immediately.
* If exit_code is not NULL, then thread_wait() copies the exit status of the
* target thread (i.e., the value that the target thread supplied to
* thread_exit) into the location pointed to by exit_code.
* Upon success, returns 0.
* Upon failure, returns THREAD_INVALID. Failure can occur for the following
* reasons:
* - Identifier tid is not a feasible thread id (e.g., tid < 0 or
* tid >= THREAD_MAX_THREADS)
* - No thread with the identifier tid could be found.
* - The identifier tid refers to the calling thread.
* - Another thread is already waiting for the thread with identifier tid.
*/
int thread_wait(Tid tid, int *exit_code);
/* Create a blocking lock. Initially, the lock is available.
* Associate a wait queue with the lock so that threads that need to acquire
* the lock can wait in this queue.
*/
struct lock *lock_create();
/* Destroy the lock. Be sure to check that the lock is available when it is
* being destroyed.
*/
void lock_destroy(struct lock *lock);
/* Acquire the lock. Calling threads should be suspended on the lock's wait
* queue until they can acquire the lock.
*/
void lock_acquire(struct lock *lock);
/* Release the lock. Be sure to check that the lock had been acquired by the
* calling thread, before it is released. Wakeup all threads that are waiting
* to acquire the lock.
*/
void lock_release(struct lock *lock);
/* Create a condition variable. Associate a wait queue with the condition
* variable so that threads issuing cv_wait can wait in this queue.
*/
struct cv *cv_create();
/* Destroy the condition variable. */
void cv_destroy(struct cv *cv);
/* Suspend the calling thread on the condition variable cv. Be sure to check
* that the calling thread had acquired lock when this call is made. You will
* need to release the lock before waiting, and reacquire it before returning
* from cv_wait.
*/
void cv_wait(struct cv *cv, struct lock *lock);
/* Wake up one thread that is waiting on the condition variable cv. Be sure to
* check that the calling thread had acquired lock when this call is made.
*/
void cv_signal(struct cv *cv, struct lock *lock);
/* Wake up all threads that are waiting on the condition variable cv. Be sure to
* check that the calling thread had acquired lock when this call is made.
*/
void cv_broadcast(struct cv *cv, struct lock *lock);
#endif /* _THREAD_H_ */