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
 | 
						|
 |