|  | @@ -0,0 +1,96 @@
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + * thread.c
 | 
	
		
			
				|  |  | + * 
 | 
	
		
			
				|  |  | + * Cooperative multitasking.
 | 
	
		
			
				|  |  | + * 
 | 
	
		
			
				|  |  | + * Written & released by Keir Fraser <keir.xen@gmail.com> and Eric Anderson
 | 
	
		
			
				|  |  | + * <ejona86@gmail.com>
 | 
	
		
			
				|  |  | + * 
 | 
	
		
			
				|  |  | + * This is free and unencumbered software released into the public domain.
 | 
	
		
			
				|  |  | + * See the file COPYING for more details, or visit <http://unlicense.org>.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* Holds stack pointer. */
 | 
	
		
			
				|  |  | +static uint32_t *waiting_thread;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +__attribute__((naked))
 | 
	
		
			
				|  |  | +static void _thread_yield(uint32_t *new_stack, uint32_t **save_stack_pointer)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    asm (
 | 
	
		
			
				|  |  | +        "    stmdb sp!,{r4-r11,lr}\n"
 | 
	
		
			
				|  |  | +        "    str   sp,[r1]\n"
 | 
	
		
			
				|  |  | +        "    b     resume\n"
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void thread_yield(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    if (!waiting_thread)
 | 
	
		
			
				|  |  | +        return;
 | 
	
		
			
				|  |  | +    _thread_yield(waiting_thread, &waiting_thread);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +__attribute__((naked))
 | 
	
		
			
				|  |  | +static void resume(uint32_t *stack)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    asm (
 | 
	
		
			
				|  |  | +        "    mov   sp,r0\n"
 | 
	
		
			
				|  |  | +        "    ldmia sp!,{r4-r11,lr}\n"
 | 
	
		
			
				|  |  | +        "    bx    lr\n"
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void _thread_main(struct thread *thread, void (*func)(void*), void *arg)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    uint32_t *other_thread;
 | 
	
		
			
				|  |  | +    func(arg);
 | 
	
		
			
				|  |  | +    thread->exited = TRUE;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    other_thread = waiting_thread;
 | 
	
		
			
				|  |  | +    waiting_thread = 0;
 | 
	
		
			
				|  |  | +    resume(other_thread);
 | 
	
		
			
				|  |  | +    ASSERT(0); /* unreachable */
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +__attribute__((naked))
 | 
	
		
			
				|  |  | +static void _main(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    asm (
 | 
	
		
			
				|  |  | +        "    mov r0,r9\n"
 | 
	
		
			
				|  |  | +        "    mov r1,r10\n"
 | 
	
		
			
				|  |  | +        "    mov r2,r11\n"
 | 
	
		
			
				|  |  | +        "    b   _thread_main\n"
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void thread_start(struct thread *thread, uint32_t *stack,
 | 
	
		
			
				|  |  | +                  void (*func)(void *), void* arg)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    memset(thread, 0, sizeof(*thread));
 | 
	
		
			
				|  |  | +    ASSERT(!waiting_thread);
 | 
	
		
			
				|  |  | +    /* Fake thread_yield storage */
 | 
	
		
			
				|  |  | +    *(--stack) = (uint32_t)_main; /* rl */
 | 
	
		
			
				|  |  | +    *(--stack) = (uint32_t)arg; /* r11 */
 | 
	
		
			
				|  |  | +    *(--stack) = (uint32_t)func; /* r10 */
 | 
	
		
			
				|  |  | +    *(--stack) = (uint32_t)thread; /* r9 */
 | 
	
		
			
				|  |  | +    stack -= 5; /* r4-r8 */
 | 
	
		
			
				|  |  | +    waiting_thread = stack;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +bool_t thread_tryjoin(struct thread *thread)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    bool_t exited = thread->exited;
 | 
	
		
			
				|  |  | +    thread->exited = FALSE;
 | 
	
		
			
				|  |  | +    return exited;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void thread_join(struct thread *thread)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    while (!thread->exited)
 | 
	
		
			
				|  |  | +        thread_yield();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void thread_reset(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    waiting_thread = NULL;
 | 
	
		
			
				|  |  | +}
 |