summaryrefslogtreecommitdiff
path: root/uisimulator/sdl/kernel.c
diff options
context:
space:
mode:
Diffstat (limited to 'uisimulator/sdl/kernel.c')
-rw-r--r--uisimulator/sdl/kernel.c147
1 files changed, 126 insertions, 21 deletions
diff --git a/uisimulator/sdl/kernel.c b/uisimulator/sdl/kernel.c
index 6a8c9e4538..4e0a508f74 100644
--- a/uisimulator/sdl/kernel.c
+++ b/uisimulator/sdl/kernel.c
@@ -18,13 +18,93 @@
18 ****************************************************************************/ 18 ****************************************************************************/
19 19
20#include <stdlib.h> 20#include <stdlib.h>
21#include <SDL.h>
22#include <SDL_thread.h>
21#include "memory.h" 23#include "memory.h"
24#include "system-sdl.h"
22#include "uisdl.h" 25#include "uisdl.h"
23#include "kernel.h" 26#include "kernel.h"
24#include "thread-sdl.h" 27#include "thread-sdl.h"
25#include "thread.h" 28#include "thread.h"
26#include "debug.h" 29#include "debug.h"
27 30
31/* Prevent "irq handler" from thread concurrent access as well as current
32 * access on multiple handlers */
33static SDL_cond *sim_thread_cond;
34/* Protect sim irq object when it is being changed */
35static SDL_mutex *sim_irq_mtx;
36static int interrupt_level = HIGHEST_IRQ_LEVEL;
37static int status_reg = 0;
38
39extern struct core_entry cores[NUM_CORES];
40
41/* Nescessary logic:
42 * 1) All threads must pass unblocked
43 * 2) Current handler must always pass unblocked
44 * 3) Threads must be excluded when irq routine is running
45 * 4) No more than one handler routine should execute at a time
46 */
47int set_irq_level(int level)
48{
49 SDL_LockMutex(sim_irq_mtx);
50
51 int oldlevel = interrupt_level;
52
53 if (status_reg == 0 && level == 0 && oldlevel != 0)
54 {
55 /* Not in a handler and "interrupts" are being reenabled */
56 SDL_CondSignal(sim_thread_cond);
57 }
58
59 interrupt_level = level; /* save new level */
60
61 SDL_UnlockMutex(sim_irq_mtx);
62 return oldlevel;
63}
64
65void sim_enter_irq_handler(void)
66{
67 SDL_LockMutex(sim_irq_mtx);
68 if(interrupt_level != 0)
69 {
70 /* "Interrupts" are disabled. Wait for reenable */
71 SDL_CondWait(sim_thread_cond, sim_irq_mtx);
72 }
73 status_reg = 1;
74}
75
76void sim_exit_irq_handler(void)
77{
78 status_reg = 0;
79 SDL_UnlockMutex(sim_irq_mtx);
80}
81
82bool sim_kernel_init(void)
83{
84 sim_irq_mtx = SDL_CreateMutex();
85 if (sim_irq_mtx == NULL)
86 {
87 fprintf(stderr, "Cannot create sim_handler_mtx\n");
88 return false;
89 }
90
91 /* Create with a count of 0 to have interrupts disabled by default */
92 sim_thread_cond = SDL_CreateCond();
93 if (sim_thread_cond == NULL)
94 {
95 fprintf(stderr, "Cannot create sim_thread_cond\n");
96 return false;
97 }
98
99 return true;
100}
101
102void sim_kernel_shutdown(void)
103{
104 SDL_DestroyMutex(sim_irq_mtx);
105 SDL_DestroyCond(sim_thread_cond);
106}
107
28volatile long current_tick = 0; 108volatile long current_tick = 0;
29static void (*tick_funcs[MAX_NUM_TICK_TASKS])(void); 109static void (*tick_funcs[MAX_NUM_TICK_TASKS])(void);
30 110
@@ -85,17 +165,21 @@ static void queue_release_all_senders(struct event_queue *q)
85void queue_enable_queue_send(struct event_queue *q, 165void queue_enable_queue_send(struct event_queue *q,
86 struct queue_sender_list *send) 166 struct queue_sender_list *send)
87{ 167{
168 int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
88 q->send = NULL; 169 q->send = NULL;
89 if(send) 170 if(send)
90 { 171 {
91 q->send = send; 172 q->send = send;
92 memset(send, 0, sizeof(*send)); 173 memset(send, 0, sizeof(*send));
93 } 174 }
175 set_irq_level(oldlevel);
94} 176}
95#endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */ 177#endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */
96 178
97void queue_init(struct event_queue *q, bool register_queue) 179void queue_init(struct event_queue *q, bool register_queue)
98{ 180{
181 int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
182
99 q->read = 0; 183 q->read = 0;
100 q->write = 0; 184 q->write = 0;
101 thread_queue_init(&q->queue); 185 thread_queue_init(&q->queue);
@@ -113,6 +197,8 @@ void queue_init(struct event_queue *q, bool register_queue)
113 /* Add it to the all_queues array */ 197 /* Add it to the all_queues array */
114 all_queues[num_queues++] = q; 198 all_queues[num_queues++] = q;
115 } 199 }
200
201 set_irq_level(oldlevel);
116} 202}
117 203
118void queue_delete(struct event_queue *q) 204void queue_delete(struct event_queue *q)
@@ -120,6 +206,8 @@ void queue_delete(struct event_queue *q)
120 int i; 206 int i;
121 bool found = false; 207 bool found = false;
122 208
209 int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
210
123 /* Find the queue to be deleted */ 211 /* Find the queue to be deleted */
124 for(i = 0;i < num_queues;i++) 212 for(i = 0;i < num_queues;i++)
125 { 213 {
@@ -153,11 +241,14 @@ void queue_delete(struct event_queue *q)
153 241
154 q->read = 0; 242 q->read = 0;
155 q->write = 0; 243 q->write = 0;
244
245 set_irq_level(oldlevel);
156} 246}
157 247
158void queue_wait(struct event_queue *q, struct queue_event *ev) 248void queue_wait(struct event_queue *q, struct queue_event *ev)
159{ 249{
160 unsigned int rd; 250 unsigned int rd;
251 int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
161 252
162#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME 253#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
163 if (q->send && q->send->curr_sender) 254 if (q->send && q->send->curr_sender)
@@ -171,7 +262,9 @@ void queue_wait(struct event_queue *q, struct queue_event *ev)
171 { 262 {
172 do 263 do
173 { 264 {
265 cores[CURRENT_CORE].irq_level = oldlevel;
174 block_thread(&q->queue); 266 block_thread(&q->queue);
267 oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
175 } 268 }
176 while (q->read == q->write); 269 while (q->read == q->write);
177 } 270 }
@@ -186,10 +279,14 @@ void queue_wait(struct event_queue *q, struct queue_event *ev)
186 queue_fetch_sender(q->send, rd); 279 queue_fetch_sender(q->send, rd);
187 } 280 }
188#endif 281#endif
282
283 set_irq_level(oldlevel);
189} 284}
190 285
191void queue_wait_w_tmo(struct event_queue *q, struct queue_event *ev, int ticks) 286void queue_wait_w_tmo(struct event_queue *q, struct queue_event *ev, int ticks)
192{ 287{
288 int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
289
193#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME 290#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
194 if (q->send && q->send->curr_sender) 291 if (q->send && q->send->curr_sender)
195 { 292 {
@@ -200,7 +297,9 @@ void queue_wait_w_tmo(struct event_queue *q, struct queue_event *ev, int ticks)
200 297
201 if (q->read == q->write && ticks > 0) 298 if (q->read == q->write && ticks > 0)
202 { 299 {
300 cores[CURRENT_CORE].irq_level = oldlevel;
203 block_thread_w_tmo(&q->queue, ticks); 301 block_thread_w_tmo(&q->queue, ticks);
302 oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
204 } 303 }
205 304
206 if(q->read != q->write) 305 if(q->read != q->write)
@@ -220,10 +319,14 @@ void queue_wait_w_tmo(struct event_queue *q, struct queue_event *ev, int ticks)
220 { 319 {
221 ev->id = SYS_TIMEOUT; 320 ev->id = SYS_TIMEOUT;
222 } 321 }
322
323 set_irq_level(oldlevel);
223} 324}
224 325
225void queue_post(struct event_queue *q, long id, intptr_t data) 326void queue_post(struct event_queue *q, long id, intptr_t data)
226{ 327{
328 int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
329
227 unsigned int wr = q->write++ & QUEUE_LENGTH_MASK; 330 unsigned int wr = q->write++ & QUEUE_LENGTH_MASK;
228 331
229 q->events[wr].id = id; 332 q->events[wr].id = id;
@@ -243,20 +346,15 @@ void queue_post(struct event_queue *q, long id, intptr_t data)
243#endif 346#endif
244 347
245 wakeup_thread(&q->queue); 348 wakeup_thread(&q->queue);
246}
247 349
248/* Special thread-synced queue_post for button driver or any other preemptive sim thread */ 350 set_irq_level(oldlevel);
249void queue_syncpost(struct event_queue *q, long id, intptr_t data)
250{
251 thread_sdl_lock();
252 /* No rockbox threads can be running here */
253 queue_post(q, id, data);
254 thread_sdl_unlock();
255} 351}
256 352
257#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME 353#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
258intptr_t queue_send(struct event_queue *q, long id, intptr_t data) 354intptr_t queue_send(struct event_queue *q, long id, intptr_t data)
259{ 355{
356 int oldlevel = set_irq_level(oldlevel);
357
260 unsigned int wr = q->write++ & QUEUE_LENGTH_MASK; 358 unsigned int wr = q->write++ & QUEUE_LENGTH_MASK;
261 359
262 q->events[wr].id = id; 360 q->events[wr].id = id;
@@ -274,11 +372,14 @@ intptr_t queue_send(struct event_queue *q, long id, intptr_t data)
274 372
275 wakeup_thread(&q->queue); 373 wakeup_thread(&q->queue);
276 374
375 cores[CURRENT_CORE].irq_level = oldlevel;
277 block_thread_no_listlock(spp); 376 block_thread_no_listlock(spp);
278 return thread_get_current()->retval; 377 return thread_get_current()->retval;
279 } 378 }
280 379
281 /* Function as queue_post if sending is not enabled */ 380 /* Function as queue_post if sending is not enabled */
381 wakeup_thread(&q->queue);
382 set_irq_level(oldlevel);
282 return 0; 383 return 0;
283} 384}
284 385
@@ -307,6 +408,8 @@ bool queue_empty(const struct event_queue* q)
307 408
308void queue_clear(struct event_queue* q) 409void queue_clear(struct event_queue* q)
309{ 410{
411 int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
412
310 /* fixme: This is potentially unsafe in case we do interrupt-like processing */ 413 /* fixme: This is potentially unsafe in case we do interrupt-like processing */
311#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME 414#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
312 /* Release all thread waiting in the queue for a reply - 415 /* Release all thread waiting in the queue for a reply -
@@ -315,10 +418,14 @@ void queue_clear(struct event_queue* q)
315#endif 418#endif
316 q->read = 0; 419 q->read = 0;
317 q->write = 0; 420 q->write = 0;
421
422 set_irq_level(oldlevel);
318} 423}
319 424
320void queue_remove_from_head(struct event_queue *q, long id) 425void queue_remove_from_head(struct event_queue *q, long id)
321{ 426{
427 int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
428
322 while(q->read != q->write) 429 while(q->read != q->write)
323 { 430 {
324 unsigned int rd = q->read & QUEUE_LENGTH_MASK; 431 unsigned int rd = q->read & QUEUE_LENGTH_MASK;
@@ -342,6 +449,8 @@ void queue_remove_from_head(struct event_queue *q, long id)
342#endif 449#endif
343 q->read++; 450 q->read++;
344 } 451 }
452
453 set_irq_level(oldlevel);
345} 454}
346 455
347int queue_count(const struct event_queue *q) 456int queue_count(const struct event_queue *q)
@@ -351,25 +460,16 @@ int queue_count(const struct event_queue *q)
351 460
352int queue_broadcast(long id, intptr_t data) 461int queue_broadcast(long id, intptr_t data)
353{ 462{
463 int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
354 int i; 464 int i;
355 465
356 for(i = 0;i < num_queues;i++) 466 for(i = 0;i < num_queues;i++)
357 { 467 {
358 queue_post(all_queues[i], id, data); 468 queue_post(all_queues[i], id, data);
359 } 469 }
360
361 return num_queues;
362}
363 470
364/* Special thread-synced queue_broadcast for button driver or any other preemptive sim thread */ 471 set_irq_level(oldlevel);
365int queue_syncbroadcast(long id, intptr_t data) 472 return num_queues;
366{
367 int i;
368 thread_sdl_lock();
369 /* No rockbox threads can be running here */
370 i = queue_broadcast(id, data);
371 thread_sdl_unlock();
372 return i;
373} 473}
374 474
375void yield(void) 475void yield(void)
@@ -398,6 +498,7 @@ void sim_tick_tasks(void)
398 498
399int tick_add_task(void (*f)(void)) 499int tick_add_task(void (*f)(void))
400{ 500{
501 int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
401 int i; 502 int i;
402 503
403 /* Add a task if there is room */ 504 /* Add a task if there is room */
@@ -406,6 +507,7 @@ int tick_add_task(void (*f)(void))
406 if(tick_funcs[i] == NULL) 507 if(tick_funcs[i] == NULL)
407 { 508 {
408 tick_funcs[i] = f; 509 tick_funcs[i] = f;
510 set_irq_level(oldlevel);
409 return 0; 511 return 0;
410 } 512 }
411 } 513 }
@@ -416,6 +518,7 @@ int tick_add_task(void (*f)(void))
416 518
417int tick_remove_task(void (*f)(void)) 519int tick_remove_task(void (*f)(void))
418{ 520{
521 int oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
419 int i; 522 int i;
420 523
421 /* Remove a task if it is there */ 524 /* Remove a task if it is there */
@@ -424,10 +527,12 @@ int tick_remove_task(void (*f)(void))
424 if(tick_funcs[i] == f) 527 if(tick_funcs[i] == f)
425 { 528 {
426 tick_funcs[i] = NULL; 529 tick_funcs[i] = NULL;
530 set_irq_level(oldlevel);
427 return 0; 531 return 0;
428 } 532 }
429 } 533 }
430 534
535 set_irq_level(oldlevel);
431 return -1; 536 return -1;
432} 537}
433 538