arm.c 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. #define LIBCO_C
  2. #include "libco.h"
  3. #include "settings.h"
  4. #ifdef LIBCO_MPROTECT
  5. #include <unistd.h>
  6. #include <sys/mman.h>
  7. #endif
  8. #ifdef __cplusplus
  9. extern "C" {
  10. #endif
  11. static thread_local unsigned long co_active_buffer[64];
  12. static thread_local cothread_t co_active_handle = 0;
  13. static void (*co_swap)(cothread_t, cothread_t) = 0;
  14. #ifdef LIBCO_MPROTECT
  15. alignas(4096)
  16. #else
  17. section(text)
  18. #endif
  19. static const unsigned long co_swap_function[1024] = {
  20. 0xe8a16ff0, /* stmia r1!, {r4-r11,sp,lr} */
  21. 0xe8b0aff0, /* ldmia r0!, {r4-r11,sp,pc} */
  22. 0xe12fff1e, /* bx lr */
  23. };
  24. static void co_init() {
  25. #ifdef LIBCO_MPROTECT
  26. unsigned long addr = (unsigned long)co_swap_function;
  27. unsigned long base = addr - (addr % sysconf(_SC_PAGESIZE));
  28. unsigned long size = (addr - base) + sizeof co_swap_function;
  29. mprotect((void*)base, size, PROT_READ | PROT_EXEC);
  30. #endif
  31. }
  32. cothread_t co_active() {
  33. if(!co_active_handle) co_active_handle = &co_active_buffer;
  34. return co_active_handle;
  35. }
  36. cothread_t co_derive(void* memory, unsigned int size, void (*entrypoint)(void)) {
  37. unsigned long* handle;
  38. if(!co_swap) {
  39. co_init();
  40. co_swap = (void (*)(cothread_t, cothread_t))co_swap_function;
  41. }
  42. if(!co_active_handle) co_active_handle = &co_active_buffer;
  43. if(handle = (unsigned long*)memory) {
  44. unsigned int offset = (size & ~15);
  45. unsigned long* p = (unsigned long*)((unsigned char*)handle + offset);
  46. handle[8] = (unsigned long)p;
  47. handle[9] = (unsigned long)entrypoint;
  48. }
  49. return handle;
  50. }
  51. cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
  52. void* memory = LIBCO_MALLOC(size);
  53. if(!memory) return (cothread_t)0;
  54. return co_derive(memory, size, entrypoint);
  55. }
  56. void co_delete(cothread_t handle) {
  57. LIBCO_FREE(handle);
  58. }
  59. void co_switch(cothread_t handle) {
  60. cothread_t co_previous_handle = co_active_handle;
  61. co_swap(co_active_handle = handle, co_previous_handle);
  62. }
  63. int co_serializable() {
  64. return 1;
  65. }
  66. #ifdef __cplusplus
  67. }
  68. #endif