pybthread.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. * This file is part of the MicroPython project, http://micropython.org/
  3. *
  4. * The MIT License (MIT)
  5. *
  6. * Copyright (c) 2017 Damien P. George
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. */
  26. #include <string.h>
  27. #include <stdio.h>
  28. #include "py/obj.h"
  29. #include "gccollect.h"
  30. #include "irq.h"
  31. #include "pybthread.h"
  32. #if MICROPY_PY_THREAD
  33. #define PYB_MUTEX_UNLOCKED ((void*)0)
  34. #define PYB_MUTEX_LOCKED ((void*)1)
  35. // These macros are used when we only need to protect against a thread
  36. // switch; other interrupts are still allowed to proceed.
  37. #define RAISE_IRQ_PRI() raise_irq_pri(IRQ_PRI_PENDSV)
  38. #define RESTORE_IRQ_PRI(state) restore_irq_pri(state)
  39. extern void __fatal_error(const char*);
  40. volatile int pyb_thread_enabled;
  41. pyb_thread_t *volatile pyb_thread_all;
  42. pyb_thread_t *volatile pyb_thread_cur;
  43. static inline void pyb_thread_add_to_runable(pyb_thread_t *thread) {
  44. thread->run_prev = pyb_thread_cur->run_prev;
  45. thread->run_next = pyb_thread_cur;
  46. pyb_thread_cur->run_prev->run_next = thread;
  47. pyb_thread_cur->run_prev = thread;
  48. }
  49. static inline void pyb_thread_remove_from_runable(pyb_thread_t *thread) {
  50. if (thread->run_next == thread) {
  51. __fatal_error("deadlock");
  52. }
  53. thread->run_prev->run_next = thread->run_next;
  54. thread->run_next->run_prev = thread->run_prev;
  55. }
  56. void pyb_thread_init(pyb_thread_t *thread) {
  57. pyb_thread_enabled = 0;
  58. pyb_thread_all = thread;
  59. pyb_thread_cur = thread;
  60. thread->sp = NULL; // will be set when this thread switches out
  61. thread->local_state = 0; // will be set by mp_thread_init
  62. thread->arg = NULL;
  63. thread->stack = &_heap_end;
  64. thread->stack_len = ((uint32_t)&_estack - (uint32_t)&_heap_end) / sizeof(uint32_t);
  65. thread->all_next = NULL;
  66. thread->run_prev = thread;
  67. thread->run_next = thread;
  68. thread->queue_next = NULL;
  69. }
  70. void pyb_thread_deinit() {
  71. uint32_t irq_state = disable_irq();
  72. pyb_thread_enabled = 0;
  73. pyb_thread_all = pyb_thread_cur;
  74. pyb_thread_cur->all_next = NULL;
  75. pyb_thread_cur->run_prev = pyb_thread_cur;
  76. pyb_thread_cur->run_next = pyb_thread_cur;
  77. enable_irq(irq_state);
  78. }
  79. STATIC void pyb_thread_terminate(void) {
  80. uint32_t irq_state = disable_irq();
  81. pyb_thread_t *thread = pyb_thread_cur;
  82. // take current thread off the run list
  83. pyb_thread_remove_from_runable(thread);
  84. // take current thread off the list of all threads
  85. for (pyb_thread_t **n = (pyb_thread_t**)&pyb_thread_all;; n = &(*n)->all_next) {
  86. if (*n == thread) {
  87. *n = thread->all_next;
  88. break;
  89. }
  90. }
  91. // clean pointers as much as possible to help GC
  92. thread->all_next = NULL;
  93. thread->queue_next = NULL;
  94. thread->stack = NULL;
  95. if (pyb_thread_all->all_next == NULL) {
  96. // only 1 thread left
  97. pyb_thread_enabled = 0;
  98. }
  99. // thread switch will occur after we enable irqs
  100. SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
  101. enable_irq(irq_state);
  102. // should not return
  103. __fatal_error("could not terminate");
  104. }
  105. uint32_t pyb_thread_new(pyb_thread_t *thread, void *stack, size_t stack_len, void *entry, void *arg) {
  106. uint32_t *stack_top = (uint32_t*)stack + stack_len; // stack is full descending
  107. *--stack_top = 0x01000000; // xPSR (thumb bit set)
  108. *--stack_top = (uint32_t)entry & 0xfffffffe; // pc (must have bit 0 cleared, even for thumb code)
  109. *--stack_top = (uint32_t)pyb_thread_terminate; // lr
  110. *--stack_top = 0; // r12
  111. *--stack_top = 0; // r3
  112. *--stack_top = 0; // r2
  113. *--stack_top = 0; // r1
  114. *--stack_top = (uint32_t)arg; // r0
  115. *--stack_top = 0xfffffff9; // lr (return to thread mode, non-FP, use MSP)
  116. stack_top -= 8; // r4-r11
  117. stack_top -= 16; // s16-s31 (we assume all threads use FP registers)
  118. thread->sp = stack_top;
  119. thread->local_state = 0;
  120. thread->arg = arg;
  121. thread->stack = stack;
  122. thread->stack_len = stack_len;
  123. thread->queue_next = NULL;
  124. uint32_t irq_state = disable_irq();
  125. pyb_thread_enabled = 1;
  126. thread->all_next = pyb_thread_all;
  127. pyb_thread_all = thread;
  128. pyb_thread_add_to_runable(thread);
  129. enable_irq(irq_state);
  130. return (uint32_t)thread; // success
  131. }
  132. void pyb_thread_dump(void) {
  133. if (!pyb_thread_enabled) {
  134. printf("THREAD: only main thread\n");
  135. } else {
  136. printf("THREAD:\n");
  137. for (pyb_thread_t *th = pyb_thread_all; th != NULL; th = th->all_next) {
  138. bool runable = false;
  139. for (pyb_thread_t *th2 = pyb_thread_cur;; th2 = th2->run_next) {
  140. if (th == th2) {
  141. runable = true;
  142. break;
  143. }
  144. if (th2->run_next == pyb_thread_cur) {
  145. break;
  146. }
  147. }
  148. printf(" id=%p sp=%p sz=%u", th, th->stack, th->stack_len);
  149. if (runable) {
  150. printf(" (runable)");
  151. }
  152. printf("\n");
  153. }
  154. }
  155. }
  156. // should only be called from pendsv_isr_handler
  157. void *pyb_thread_next(void *sp) {
  158. pyb_thread_cur->sp = sp;
  159. pyb_thread_cur = pyb_thread_cur->run_next;
  160. pyb_thread_cur->timeslice = 4; // in milliseconds
  161. return pyb_thread_cur->sp;
  162. }
  163. void pyb_mutex_init(pyb_mutex_t *m) {
  164. *m = PYB_MUTEX_UNLOCKED;
  165. }
  166. int pyb_mutex_lock(pyb_mutex_t *m, int wait) {
  167. uint32_t irq_state = RAISE_IRQ_PRI();
  168. if (*m == PYB_MUTEX_UNLOCKED) {
  169. // mutex is available
  170. *m = PYB_MUTEX_LOCKED;
  171. RESTORE_IRQ_PRI(irq_state);
  172. } else {
  173. // mutex is locked
  174. if (!wait) {
  175. RESTORE_IRQ_PRI(irq_state);
  176. return 0; // failed to lock mutex
  177. }
  178. if (*m == PYB_MUTEX_LOCKED) {
  179. *m = pyb_thread_cur;
  180. } else {
  181. for (pyb_thread_t *n = *m;; n = n->queue_next) {
  182. if (n->queue_next == NULL) {
  183. n->queue_next = pyb_thread_cur;
  184. break;
  185. }
  186. }
  187. }
  188. pyb_thread_cur->queue_next = NULL;
  189. // take current thread off the run list
  190. pyb_thread_remove_from_runable(pyb_thread_cur);
  191. // thread switch will occur after we enable irqs
  192. SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
  193. RESTORE_IRQ_PRI(irq_state);
  194. // when we come back we have the mutex
  195. }
  196. return 1; // have mutex
  197. }
  198. void pyb_mutex_unlock(pyb_mutex_t *m) {
  199. uint32_t irq_state = RAISE_IRQ_PRI();
  200. if (*m == PYB_MUTEX_LOCKED) {
  201. // no threads are blocked on the mutex
  202. *m = PYB_MUTEX_UNLOCKED;
  203. } else {
  204. // at least one thread is blocked on this mutex
  205. pyb_thread_t *th = *m;
  206. if (th->queue_next == NULL) {
  207. // no other threads are blocked
  208. *m = PYB_MUTEX_LOCKED;
  209. } else {
  210. // at least one other thread is still blocked
  211. *m = th->queue_next;
  212. }
  213. // put unblocked thread on runable list
  214. pyb_thread_add_to_runable(th);
  215. }
  216. RESTORE_IRQ_PRI(irq_state);
  217. }
  218. #endif // MICROPY_PY_THREAD