-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy paththread.c
More file actions
113 lines (100 loc) · 3.19 KB
/
thread.c
File metadata and controls
113 lines (100 loc) · 3.19 KB
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
#include "thread.h"
#include <stdlib.h>
#include <pthread.h>
/** Post-cancel/post-exit cleanup routing. Will call the thread-defined
* cancel routine if there is any.
*/
void thread_cleanup (void *dt) {
thread *self = (thread *) dt;
if (self->cancel) { self->cancel (self); }
conditional_signal (self->cshutdown);
}
/** Call a thread's run function */
void *thread_spawn (void *dt) {
thread *self = (thread *) dt;
self->isrunning = 1;
pthread_cleanup_push (thread_cleanup, self);
self->run (self);
pthread_cleanup_pop(0);
self->isrunning = 0;
thread_cleanup (self);
return NULL;
}
/** Allocate and spawn a thread */
thread *thread_create (run_f run, cancel_f cancel) {
thread *self = (thread *) malloc (sizeof (thread));
thread_init (self, run, cancel);
return self;
}
/** Allocate and initialize a conditional object */
conditional *conditional_create (void) {
conditional *c = (conditional *) malloc (sizeof (conditional));
conditional_init (c);
return c;
}
/** Initialize a conditional */
void conditional_init (conditional *self) {
pthread_mutexattr_init (&self->mattr);
pthread_mutex_init (&self->mutex, &self->mattr);
pthread_cond_init (&self->cond, NULL);
self->queue = 0;
}
/** Add a signal to a conditional's queue and send it out */
void conditional_signal (conditional *self) {
pthread_mutex_lock (&self->mutex);
self->queue++;
pthread_cond_signal (&self->cond);
pthread_mutex_unlock (&self->mutex);
}
/** Wait for a signal (or pick a backlogged one off the queue) */
void conditional_wait (conditional *self) {
pthread_mutex_lock (&self->mutex);
if (self->queue) {
self->queue--;
pthread_mutex_unlock (&self->mutex);
return;
}
while (pthread_cond_wait (&self->cond, &self->mutex)!=0) {}
self->queue--;
pthread_mutex_unlock (&self->mutex);
}
/** Wait for a new signal (queued doesn't count) */
void conditional_wait_fresh (conditional *self) {
pthread_mutex_lock (&self->mutex);
self->queue = 0;
while (pthread_cond_wait (&self->cond, &self->mutex)!=0) {}
self->queue--;
pthread_mutex_unlock (&self->mutex);
}
/** Clean up pthread data inside a conditional */
void conditional_cleanup (conditional *c) {
pthread_mutex_destroy (&c->mutex);
pthread_mutexattr_destroy (&c->mattr);
pthread_cond_destroy (&c->cond);
}
/** Demolish a conditional */
void conditional_free (conditional *c) {
conditional_cleanup (c);
free (c);
}
/** Initialize a thread structure and spawn it */
void thread_init (thread *self, run_f run, cancel_f cancel) {
self->run = run;
self->cancel = cancel;
self->isrunning = 0;
self->cshutdown = conditional_create();
pthread_attr_init (&self->tattr);
pthread_create (&self->thread, &self->tattr, thread_spawn, self);
}
/** Free up a thread's resources. Thread should already be
* canceled or shut down at this point.
*/
void thread_free (thread *self) {
conditional_free (self->cshutdown);
free (self); /* and your mind will follow */
}
/** Cancel a thread and wait for it to exit */
void thread_cancel (thread *self) {
pthread_cancel (self->thread);
conditional_wait (self->cshutdown);
}