95 lines
		
	
	
	
		
			1.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			95 lines
		
	
	
	
		
			1.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|   libco.armeabi (2013-04-05)
 | |
|   author: Themaister
 | |
|   license: public domain
 | |
| */
 | |
| 
 | |
| #define LIBCO_C
 | |
| #include <libco.h>
 | |
| #include <assert.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <stdint.h>
 | |
| 
 | |
| #ifndef IOS
 | |
| #include <malloc.h>
 | |
| #endif
 | |
| 
 | |
| #ifdef __cplusplus
 | |
| extern "C" {
 | |
| #endif
 | |
| 
 | |
| static thread_local uint32_t co_active_buffer[64];
 | |
| static thread_local cothread_t co_active_handle;
 | |
| 
 | |
| asm (
 | |
|       ".arm\n"
 | |
|       ".align 4\n"
 | |
|       ".globl co_switch_arm\n"
 | |
|       ".globl _co_switch_arm\n"
 | |
|       "co_switch_arm:\n"
 | |
|       "_co_switch_arm:\n"      
 | |
|       "  stmia r1!, {r4, r5, r6, r7, r8, r9, r10, r11, sp, lr}\n"
 | |
|       "  ldmia r0!, {r4, r5, r6, r7, r8, r9, r10, r11, sp, pc}\n"
 | |
|     );
 | |
| 
 | |
| /* ASM */
 | |
| void co_switch_arm(cothread_t handle, cothread_t current);
 | |
| 
 | |
| static void crash(void)
 | |
| {
 | |
|    /* Called only if cothread_t entrypoint returns. */
 | |
|    assert(0);
 | |
| }
 | |
| 
 | |
| cothread_t co_create(unsigned int size, void (*entrypoint)(void))
 | |
| {
 | |
|    size = (size + 1023) & ~1023;
 | |
|    cothread_t handle = 0;
 | |
| #if HAVE_POSIX_MEMALIGN >= 1
 | |
|    if (posix_memalign(&handle, 1024, size + 256) < 0)
 | |
|       return 0;
 | |
| #else
 | |
|    handle = memalign(1024, size + 256);
 | |
| #endif
 | |
| 
 | |
|    if (!handle)
 | |
|       return handle;
 | |
| 
 | |
|    uint32_t *ptr = (uint32_t*)handle;
 | |
|    /* Non-volatiles.  */
 | |
|    ptr[0] = 0; /* r4  */
 | |
|    ptr[1] = 0; /* r5  */
 | |
|    ptr[2] = 0; /* r6  */
 | |
|    ptr[3] = 0; /* r7  */
 | |
|    ptr[4] = 0; /* r8  */
 | |
|    ptr[5] = 0; /* r9  */
 | |
|    ptr[6] = 0; /* r10 */
 | |
|    ptr[7] = 0; /* r11 */
 | |
|    ptr[8] = (uintptr_t)ptr + size + 256 - 4; /* r13, stack pointer */
 | |
|    ptr[9] = (uintptr_t)entrypoint; /* r15, PC (link register r14 gets saved here). */
 | |
|    return handle;
 | |
| }
 | |
| 
 | |
| cothread_t co_active(void)
 | |
| {
 | |
|    if (!co_active_handle)
 | |
|       co_active_handle = co_active_buffer;
 | |
|    return co_active_handle;
 | |
| }
 | |
| 
 | |
| void co_delete(cothread_t handle)
 | |
| {
 | |
|    free(handle);
 | |
| }
 | |
| 
 | |
| void co_switch(cothread_t handle)
 | |
| {
 | |
|    cothread_t co_previous_handle = co_active();
 | |
|    co_switch_arm(co_active_handle = handle, co_previous_handle);
 | |
| }
 | |
| 
 | |
| #ifdef __cplusplus
 | |
| }
 | |
| #endif
 | |
| 
 |