mpthreadport.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /*
  2. * This file is part of the MicroPython project, http://micropython.org/
  3. *
  4. * The MIT License (MIT)
  5. *
  6. * Copyright (c) 2018 Armink (armink.ztl@gmail.com)
  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 "stdio.h"
  27. #include "py/mpconfig.h"
  28. #include "py/mpstate.h"
  29. #include "py/gc.h"
  30. #include "py/mpthread.h"
  31. #include "mpthreadport.h"
  32. #include <rthw.h>
  33. #if MICROPY_PY_THREAD
  34. #define MP_THREAD_MIN_STACK_SIZE (4 * 1024)
  35. #define MP_THREAD_DEFAULT_STACK_SIZE (MP_THREAD_MIN_STACK_SIZE + 1024)
  36. #define MP_THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX / 2)
  37. typedef struct {
  38. rt_thread_t thread;
  39. rt_list_t list;
  40. } mp_thread, *mp_thread_t;
  41. typedef struct {
  42. rt_mutex_t mutex;
  43. rt_list_t list;
  44. } mp_mutex, *mp_mutex_t;
  45. // the mutex controls access to the linked list
  46. STATIC mp_thread_mutex_t thread_mutex;
  47. STATIC rt_list_t thread_list, mutex_list;
  48. void mp_thread_init(void) {
  49. mp_thread_set_state(&mp_state_ctx.thread);
  50. rt_list_init(&thread_list);
  51. rt_list_init(&mutex_list);
  52. mp_thread_mutex_init(&thread_mutex);
  53. }
  54. mp_state_thread_t *mp_thread_get_state(void) {
  55. return (mp_state_thread_t *)(rt_thread_self()->user_data);
  56. }
  57. void mp_thread_set_state(void *state) {
  58. rt_thread_self()->user_data = (rt_uint32_t)state;
  59. }
  60. void mp_thread_start(void) {
  61. }
  62. STATIC void *(*ext_thread_entry)(void*) = NULL;
  63. STATIC void rtthread_entry(void *arg) {
  64. if (ext_thread_entry) {
  65. ext_thread_entry(arg);
  66. }
  67. /* remove node on list */
  68. {
  69. struct rt_list_node *list = &thread_list, *node = NULL;
  70. mp_thread_t cur_thread_node = NULL;
  71. mp_thread_mutex_lock(&thread_mutex, 1);
  72. for (node = list->next; node != list; node = node->next) {
  73. cur_thread_node = rt_list_entry(node, mp_thread, list);
  74. if (cur_thread_node->thread == rt_thread_self()) {
  75. rt_list_remove(node);
  76. break;
  77. }
  78. }
  79. mp_thread_mutex_unlock(&thread_mutex);
  80. }
  81. }
  82. void mp_thread_create_ex(void *(*entry)(void*), void *arg, size_t *stack_size, int priority, char *name) {
  83. // store thread entry function into a global variable so we can access it
  84. ext_thread_entry = entry;//(void (*)(void *parameter))
  85. if (*stack_size == 0) {
  86. *stack_size = MP_THREAD_DEFAULT_STACK_SIZE; // default stack size
  87. } else if (*stack_size < MP_THREAD_MIN_STACK_SIZE) {
  88. *stack_size = MP_THREAD_MIN_STACK_SIZE; // minimum stack size
  89. }
  90. // allocate linked-list node (must be outside thread_mutex lock)
  91. mp_thread *node = rt_malloc(sizeof(mp_thread));
  92. if (node == NULL) {
  93. nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread list node"));
  94. }
  95. mp_thread_mutex_lock(&thread_mutex, 1);
  96. // create thread
  97. rt_thread_t th = rt_thread_create(name, rtthread_entry, arg, *stack_size, priority, 0);
  98. if (th == NULL) {
  99. mp_thread_mutex_unlock(&thread_mutex);
  100. nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread"));
  101. }
  102. // add thread to linked list of all threads
  103. {
  104. rt_base_t level;
  105. level = rt_hw_interrupt_disable();
  106. node->thread = th;
  107. rt_list_insert_before(&thread_list, &(node->list));
  108. rt_hw_interrupt_enable(level);
  109. }
  110. rt_thread_startup(th);
  111. mp_thread_mutex_unlock(&thread_mutex);
  112. }
  113. void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) {
  114. static uint8_t count = 0;
  115. char name[RT_NAME_MAX];
  116. /* build name */
  117. rt_snprintf(name, sizeof(name), "mp%02d", count ++);
  118. mp_thread_create_ex(entry, arg, stack_size, MP_THREAD_PRIORITY, name);
  119. }
  120. void mp_thread_finish(void) {
  121. }
  122. void mp_thread_mutex_init(mp_thread_mutex_t *mutex) {
  123. static uint8_t count = 0;
  124. char name[RT_NAME_MAX];
  125. rt_base_t level;
  126. level = rt_hw_interrupt_disable();
  127. mp_mutex *node = rt_malloc(sizeof(mp_mutex));
  128. if (node == NULL) {
  129. nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create mutex list node"));
  130. }
  131. /* build name */
  132. rt_snprintf(name, sizeof(name), "mp%02d", count ++);
  133. rt_mutex_init((rt_mutex_t) mutex, name, RT_IPC_FLAG_FIFO);
  134. // add mutex to linked list of all mutexs
  135. node->mutex = (rt_mutex_t)mutex;
  136. rt_list_insert_before(&mutex_list, &(node->list));
  137. rt_hw_interrupt_enable(level);
  138. }
  139. int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait) {
  140. return (RT_EOK == rt_mutex_take((rt_mutex_t) mutex, wait ? RT_WAITING_FOREVER : 0));
  141. }
  142. void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) {
  143. rt_mutex_release((rt_mutex_t) mutex);
  144. }
  145. void mp_thread_deinit(void) {
  146. rt_base_t level;
  147. level = rt_hw_interrupt_disable();
  148. /* remove all thread node on list */
  149. {
  150. struct rt_list_node *list = &thread_list, *node = NULL;
  151. mp_thread_t cur_thread_node = NULL;
  152. for (node = list->next; node != list; node = node->next) {
  153. cur_thread_node = rt_list_entry(node, mp_thread, list);
  154. rt_thread_delete(cur_thread_node->thread);
  155. rt_free(cur_thread_node);
  156. }
  157. }
  158. /* remove all mutex node on list */
  159. {
  160. struct rt_list_node *list = &mutex_list, *node = NULL;
  161. mp_mutex_t cur_mutex_node = NULL;
  162. for (node = list->next; node != list; node = node->next) {
  163. cur_mutex_node = rt_list_entry(node, mp_mutex, list);
  164. rt_mutex_detach(cur_mutex_node->mutex);
  165. rt_free(cur_mutex_node);
  166. }
  167. }
  168. rt_hw_interrupt_enable(level);
  169. // allow RT-Thread to clean-up the threads
  170. rt_thread_delay(200);
  171. }
  172. #endif /* MICROPY_PY_THREAD */