diff options
author | Thomas Martitz <kugel@rockbox.org> | 2014-01-28 15:33:40 +0100 |
---|---|---|
committer | Thomas Martitz <kugel@rockbox.org> | 2014-02-02 16:59:29 +0100 |
commit | d66346789ccdf685a6720a739b88f194f56a60e2 (patch) | |
tree | b9c69c8801c787adbc7ec3f46f985c09599e565e /firmware/kernel | |
parent | d608d2203aff93d6d68e7afbac7767cf95c03b8b (diff) | |
download | rockbox-d66346789ccdf685a6720a739b88f194f56a60e2.tar.gz rockbox-d66346789ccdf685a6720a739b88f194f56a60e2.zip |
buflib: Check the validity of of handles passed to buflib_get_data() in DEBUG builds.
Change-Id: Ic274bfb4a8e1a1a10f9a54186b9173dbc0faa4c8
Diffstat (limited to 'firmware/kernel')
-rw-r--r-- | firmware/kernel/pthread/corelock.c | 18 | ||||
-rw-r--r-- | firmware/kernel/pthread/mutex.c | 21 | ||||
-rw-r--r-- | firmware/kernel/pthread/thread.c | 272 |
3 files changed, 311 insertions, 0 deletions
diff --git a/firmware/kernel/pthread/corelock.c b/firmware/kernel/pthread/corelock.c new file mode 100644 index 0000000000..10b4329639 --- /dev/null +++ b/firmware/kernel/pthread/corelock.c | |||
@@ -0,0 +1,18 @@ | |||
1 | #include <pthread.h> | ||
2 | #include "kernel.h" | ||
3 | |||
4 | void corelock_init(struct corelock *lk) | ||
5 | { | ||
6 | lk->mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER; | ||
7 | } | ||
8 | |||
9 | void corelock_lock(struct corelock *lk) | ||
10 | { | ||
11 | pthread_mutex_lock(&lk->mutex); | ||
12 | } | ||
13 | |||
14 | |||
15 | void corelock_unlock(struct corelock *lk) | ||
16 | { | ||
17 | pthread_mutex_unlock(&lk->mutex); | ||
18 | } | ||
diff --git a/firmware/kernel/pthread/mutex.c b/firmware/kernel/pthread/mutex.c new file mode 100644 index 0000000000..49503b5d82 --- /dev/null +++ b/firmware/kernel/pthread/mutex.c | |||
@@ -0,0 +1,21 @@ | |||
1 | #include <pthread.h> | ||
2 | #include "kernel.h" | ||
3 | |||
4 | void mutex_init(struct mutex *m) | ||
5 | { | ||
6 | pthread_mutexattr_t attr; | ||
7 | pthread_mutexattr_init(&attr); | ||
8 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); | ||
9 | pthread_mutex_init(&m->mutex, &attr); | ||
10 | pthread_mutexattr_destroy(&attr); | ||
11 | } | ||
12 | |||
13 | void mutex_lock(struct mutex *m) | ||
14 | { | ||
15 | pthread_mutex_lock(&m->mutex); | ||
16 | } | ||
17 | |||
18 | void mutex_unlock(struct mutex *m) | ||
19 | { | ||
20 | pthread_mutex_unlock(&m->mutex); | ||
21 | } | ||
diff --git a/firmware/kernel/pthread/thread.c b/firmware/kernel/pthread/thread.c new file mode 100644 index 0000000000..a80ce876e8 --- /dev/null +++ b/firmware/kernel/pthread/thread.c | |||
@@ -0,0 +1,272 @@ | |||
1 | #include <stdlib.h> | ||
2 | #include <stdbool.h> | ||
3 | #include <errno.h> | ||
4 | #include <pthread.h> | ||
5 | #include "/usr/include/semaphore.h" | ||
6 | #include "kernel.h" | ||
7 | #include "thread.h" | ||
8 | |||
9 | #define NSEC_PER_SEC 1000000000L | ||
10 | static inline void timespec_add_ns(struct timespec *a, uint64_t ns) | ||
11 | { | ||
12 | lldiv_t q = lldiv(a->tv_nsec + ns, NSEC_PER_SEC); | ||
13 | a->tv_sec += q.quot; | ||
14 | a->tv_nsec = q.rem; | ||
15 | } | ||
16 | |||
17 | static int threads_initialized; | ||
18 | |||
19 | struct thread_init_data { | ||
20 | void (*function)(void); | ||
21 | bool start_frozen; | ||
22 | sem_t init_sem; | ||
23 | struct thread_entry *entry; | ||
24 | }; | ||
25 | |||
26 | __thread struct thread_entry *_current; | ||
27 | |||
28 | struct thread_entry* thread_self_entry(void) | ||
29 | { | ||
30 | return _current; | ||
31 | } | ||
32 | |||
33 | unsigned int thread_self(void) | ||
34 | { | ||
35 | return (unsigned) pthread_self(); | ||
36 | } | ||
37 | |||
38 | static struct thread_entry_item { | ||
39 | unsigned thread_id; | ||
40 | struct thread_entry *entry; | ||
41 | } entry_lookup[32]; | ||
42 | |||
43 | |||
44 | |||
45 | static struct thread_entry_item *__find_thread_entry(unsigned thread_id) | ||
46 | { | ||
47 | int i; | ||
48 | |||
49 | for (i = 0; i < 32; i++) | ||
50 | { | ||
51 | if (entry_lookup[i].thread_id == thread_id) | ||
52 | return &entry_lookup[i]; | ||
53 | } | ||
54 | return NULL; | ||
55 | } | ||
56 | |||
57 | static struct thread_entry *find_thread_entry(unsigned thread_id) | ||
58 | { | ||
59 | return __find_thread_entry(thread_id)->entry; | ||
60 | } | ||
61 | |||
62 | static void *trampoline(void *arg) | ||
63 | { | ||
64 | struct thread_init_data *data = arg; | ||
65 | |||
66 | void (*thread_fn)(void) = data->function; | ||
67 | |||
68 | _current = data->entry; | ||
69 | |||
70 | if (data->start_frozen) | ||
71 | { | ||
72 | struct corelock thaw_lock; | ||
73 | struct thread_entry *queue = NULL; | ||
74 | corelock_init(&thaw_lock); | ||
75 | corelock_lock(&thaw_lock); | ||
76 | |||
77 | _current->lock = &thaw_lock; | ||
78 | _current->bqp = &queue; | ||
79 | sem_post(&data->init_sem); | ||
80 | block_thread_switch(_current, _current->lock); | ||
81 | _current->lock = NULL; | ||
82 | |||
83 | corelock_unlock(&thaw_lock); | ||
84 | } | ||
85 | else | ||
86 | sem_post(&data->init_sem); | ||
87 | |||
88 | free(data); | ||
89 | thread_fn(); | ||
90 | |||
91 | return NULL; | ||
92 | } | ||
93 | |||
94 | void thread_thaw(unsigned int thread_id) | ||
95 | { | ||
96 | struct thread_entry *e = find_thread_entry(thread_id); | ||
97 | if (e->lock) | ||
98 | { | ||
99 | corelock_lock(e->lock); | ||
100 | wakeup_thread(e->bqp); | ||
101 | corelock_unlock(e->lock); | ||
102 | } | ||
103 | /* else: no lock. must be running already */ | ||
104 | } | ||
105 | |||
106 | void init_threads(void) | ||
107 | { | ||
108 | struct thread_entry_item *item0 = &entry_lookup[0]; | ||
109 | item0->entry = calloc(1, sizeof(struct thread_entry)); | ||
110 | item0->thread_id = pthread_self(); | ||
111 | |||
112 | _current = item0->entry; | ||
113 | pthread_cond_init(&item0->entry->cond, NULL); | ||
114 | threads_initialized = 1; | ||
115 | } | ||
116 | |||
117 | |||
118 | unsigned int create_thread(void (*function)(void), | ||
119 | void* stack, size_t stack_size, | ||
120 | unsigned flags, const char *name | ||
121 | //~ IF_PRIO(, int priority) | ||
122 | IF_COP(, unsigned int core)) | ||
123 | { | ||
124 | pthread_t retval; | ||
125 | |||
126 | struct thread_init_data *data = calloc(1, sizeof(struct thread_init_data)); | ||
127 | struct thread_entry *entry = calloc(1, sizeof(struct thread_entry)); | ||
128 | struct thread_entry_item *item; | ||
129 | |||
130 | if (!threads_initialized) | ||
131 | abort(); | ||
132 | |||
133 | data->function = function; | ||
134 | data->start_frozen = flags & CREATE_THREAD_FROZEN; | ||
135 | data->entry = entry; | ||
136 | pthread_cond_init(&entry->cond, NULL); | ||
137 | entry->runnable = true; | ||
138 | entry->l = (struct thread_list) { NULL, NULL }; | ||
139 | sem_init(&data->init_sem, 0, 0); | ||
140 | |||
141 | if (pthread_create(&retval, NULL, trampoline, data) < 0) | ||
142 | return -1; | ||
143 | |||
144 | sem_wait(&data->init_sem); | ||
145 | |||
146 | item = __find_thread_entry(0); | ||
147 | item->thread_id = retval; | ||
148 | item->entry = entry; | ||
149 | |||
150 | pthread_setname_np(retval, name); | ||
151 | |||
152 | |||
153 | return retval; | ||
154 | } | ||
155 | |||
156 | static void add_to_list_l(struct thread_entry **list, | ||
157 | struct thread_entry *thread) | ||
158 | { | ||
159 | if (*list == NULL) | ||
160 | { | ||
161 | /* Insert into unoccupied list */ | ||
162 | thread->l.next = thread; | ||
163 | thread->l.prev = thread; | ||
164 | *list = thread; | ||
165 | } | ||
166 | else | ||
167 | { | ||
168 | /* Insert last */ | ||
169 | thread->l.next = *list; | ||
170 | thread->l.prev = (*list)->l.prev; | ||
171 | thread->l.prev->l.next = thread; | ||
172 | (*list)->l.prev = thread; | ||
173 | } | ||
174 | } | ||
175 | |||
176 | static void remove_from_list_l(struct thread_entry **list, | ||
177 | struct thread_entry *thread) | ||
178 | { | ||
179 | if (thread == thread->l.next) | ||
180 | { | ||
181 | /* The only item */ | ||
182 | *list = NULL; | ||
183 | return; | ||
184 | } | ||
185 | |||
186 | if (thread == *list) | ||
187 | { | ||
188 | /* List becomes next item */ | ||
189 | *list = thread->l.next; | ||
190 | } | ||
191 | |||
192 | /* Fix links to jump over the removed entry. */ | ||
193 | thread->l.prev->l.next = thread->l.next; | ||
194 | thread->l.next->l.prev = thread->l.prev; | ||
195 | } | ||
196 | |||
197 | unsigned int thread_queue_wake(struct thread_entry **list) | ||
198 | { | ||
199 | unsigned int result = THREAD_NONE; | ||
200 | |||
201 | for (;;) | ||
202 | { | ||
203 | unsigned int rc = wakeup_thread(list); | ||
204 | |||
205 | if (rc == THREAD_NONE) | ||
206 | break; | ||
207 | |||
208 | result |= rc; | ||
209 | } | ||
210 | |||
211 | return result; | ||
212 | } | ||
213 | |||
214 | /* for block_thread(), _w_tmp() and wakeup_thread() t->lock must point | ||
215 | * to a corelock instance, and this corelock must be held by the caller */ | ||
216 | void block_thread_switch(struct thread_entry *t, struct corelock *cl) | ||
217 | { | ||
218 | t->runnable = false; | ||
219 | add_to_list_l(t->bqp, t); | ||
220 | while(!t->runnable) | ||
221 | pthread_cond_wait(&t->cond, &cl->mutex); | ||
222 | } | ||
223 | |||
224 | void block_thread_switch_w_tmo(struct thread_entry *t, int timeout, struct corelock *cl) | ||
225 | { | ||
226 | int err = 0; | ||
227 | struct timespec ts; | ||
228 | |||
229 | clock_gettime(CLOCK_REALTIME, &ts); | ||
230 | timespec_add_ns(&ts, timeout * (NSEC_PER_SEC/HZ)); | ||
231 | |||
232 | t->runnable = false; | ||
233 | add_to_list_l(t->bqp, t); | ||
234 | while(!t->runnable && !err) | ||
235 | err = pthread_cond_timedwait(&t->cond, &cl->mutex, &ts); | ||
236 | |||
237 | if (err == ETIMEDOUT) | ||
238 | { /* the thread timed out and was not explicitely woken up. | ||
239 | * we need to do this now to mark it runnable again */ | ||
240 | remove_from_list_l(t->bqp, t); | ||
241 | t->runnable = true; | ||
242 | if (t->wakeup_ext_cb) | ||
243 | t->wakeup_ext_cb(t); | ||
244 | } | ||
245 | } | ||
246 | |||
247 | unsigned int wakeup_thread(struct thread_entry **list) | ||
248 | { | ||
249 | struct thread_entry *t = *list; | ||
250 | if (t) | ||
251 | { | ||
252 | remove_from_list_l(list, t); | ||
253 | t->runnable = true; | ||
254 | pthread_cond_signal(&t->cond); | ||
255 | } | ||
256 | return THREAD_NONE; | ||
257 | } | ||
258 | |||
259 | |||
260 | void yield(void) {} | ||
261 | |||
262 | unsigned sleep(unsigned ticks) | ||
263 | { | ||
264 | struct timespec ts; | ||
265 | |||
266 | ts.tv_sec = ticks/HZ; | ||
267 | ts.tv_nsec = (ticks % HZ) * (NSEC_PER_SEC/HZ); | ||
268 | |||
269 | nanosleep(&ts, NULL); | ||
270 | |||
271 | return 0; | ||
272 | } | ||