thread.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /*
  2. * Copyright (C) 2000-2004 by ETH Zurich
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the copyright holders nor the names of
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY ETH ZURICH AND CONTRIBUTORS
  18. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ETH ZURICH
  21. * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  24. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  25. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  26. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  27. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. *
  30. * For additional information see http://www.ethernut.de/
  31. *
  32. */
  33. /*
  34. * unix_thread.c - unix emulation of cooperative threads using pthreads
  35. *
  36. * 2004.04.01 Matthias Ringwald <matthias.ringwald@inf.ethz.ch>
  37. *
  38. */
  39. #include <cfg/os.h>
  40. #include <pthread.h>
  41. #include <stdio.h>
  42. // #include <cfg/memory.h>
  43. #include <string.h>
  44. #include <sys/types.h>
  45. #include <sys/heap.h>
  46. #include <sys/atom.h>
  47. // #include <sys/timer.h>
  48. #include <sys/thread.h>
  49. #ifdef NUTDEBUG
  50. #include <sys/osdebug.h>
  51. #endif
  52. /*!
  53. * \addtogroup xgNutArchUnixOsContext Context Switching for Linux Emulation
  54. * \ingroup xgNutArchUnixOs
  55. * \brief Context Switching for the UNIX emulator.
  56. */
  57. /*@{*/
  58. /* reused parameters for other calls */
  59. pthread_attr_t attr;
  60. /* protect thread signaling */
  61. pthread_mutex_t thread_mutex;
  62. /* to get a new thread start acked'd */
  63. pthread_cond_t main_cv;
  64. /* level of critical sections entered but not left outside a thread */
  65. uint16_t main_cs_level;
  66. void NutThreadInit(void)
  67. {
  68. /* Initialize mutex and condition variable objects */
  69. pthread_mutex_init(&thread_mutex, NULL);
  70. pthread_attr_init(&attr);
  71. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  72. // main_cv init
  73. pthread_cond_init(&main_cv, NULL);
  74. }
  75. /*
  76. * This code is executed when entering a thread.
  77. *
  78. *
  79. */
  80. static void *NutThreadEntry(void *arg);
  81. static void *NutThreadEntry(void *arg)
  82. {
  83. // get THREADINFO back
  84. NUTTHREADINFO *td = (NUTTHREADINFO *) arg;
  85. // confirm start
  86. pthread_mutex_lock(&thread_mutex);
  87. pthread_cond_signal(&main_cv);
  88. // wait for start signaled
  89. pthread_cond_wait(&td->td_cv, &thread_mutex);
  90. pthread_mutex_unlock(&thread_mutex);
  91. // set critical section value
  92. td->td_cs_level = 0;
  93. // enable interrupts
  94. pthread_sigmask(SIG_UNBLOCK, &irq_signal, 0);
  95. // call real function
  96. td->td_fn(td->td_arg);
  97. // NutExitCritical();
  98. // tell nut/os about it
  99. NutThreadExit();
  100. // thread exit routine
  101. pthread_exit(NULL);
  102. // make some compilers happy
  103. return NULL;
  104. }
  105. void NutThreadSwitch(void);
  106. void NutThreadSwitch(void)
  107. {
  108. NUTTHREADINFO *myself;
  109. NutEnterCritical();
  110. // lock thread switching mutex
  111. pthread_mutex_lock(&thread_mutex);
  112. // next thread is the first one in the run queue
  113. myself = runningThread;
  114. if (runningThread != runQueue) {
  115. // switching call
  116. runningThread = runQueue;
  117. runningThread->td_state = TDS_RUNNING;
  118. pthread_cond_signal(&runQueue->td_cv);
  119. pthread_cond_wait(&myself->td_cv, &thread_mutex);
  120. }
  121. pthread_mutex_unlock(&thread_mutex);
  122. NutExitCritical();
  123. }
  124. HANDLE NutThreadCreate(char * name, void (*fn) (void *), void *arg, size_t stackSize)
  125. {
  126. NUTTHREADINFO *td;
  127. const uintptr_t *paddr;
  128. paddr = (const uintptr_t *) fn;
  129. NutEnterCritical();
  130. /*
  131. * Allocate stack and thread info structure in one block.
  132. */
  133. if ((td = NutHeapAlloc(sizeof(NUTTHREADINFO))) == 0) {
  134. NutExitCritical();
  135. return 0;
  136. }
  137. /* store thread name */
  138. memcpy(td->td_name, name, sizeof(td->td_name) - 1);
  139. td->td_name[sizeof(td->td_name) - 1] = 0;
  140. // set initial critical section value
  141. td->td_cs_level = 1;
  142. /*
  143. * Insert into the thread list and the run queue.
  144. */
  145. td->td_priority = 64;
  146. td->td_next = nutThreadList;
  147. nutThreadList = td;
  148. td->td_state = TDS_READY;
  149. td->td_timer = 0;
  150. td->td_queue = 0;
  151. #ifdef NUTDEBUG
  152. if (__os_trf) {
  153. fprintf(__os_trs, "Cre<%08lx>\n", (uintptr_t) td);
  154. }
  155. #endif
  156. NutThreadAddPriQueue(td, (NUTTHREADINFO **) & runQueue);
  157. #ifdef NUTDEBUG
  158. if (__os_trf)
  159. NutDumpThreadList(__os_trs);
  160. #endif
  161. // init thread structure
  162. pthread_cond_init(&td->td_cv, NULL);
  163. td->td_fn = fn;
  164. td->td_arg = arg;
  165. /*
  166. * If no thread is active, switch to new thread.
  167. * this also means, we're called from nutinit
  168. * (if not, there would be a runningThread..)
  169. *
  170. */
  171. if (runningThread == 0) {
  172. // correct cs level counter
  173. // main_cs_level--;
  174. NutExitCritical();
  175. // switching
  176. runningThread = runQueue;
  177. runningThread->td_state = TDS_RUNNING;
  178. // set initial critical section value and enable interrupts
  179. runningThread->td_cs_level = 0;
  180. pthread_sigmask(SIG_UNBLOCK, &irq_signal, 0);
  181. // go!
  182. fn(arg);
  183. printf("Nut/OS Application terminated.\n\r");
  184. exit(0);
  185. };
  186. // lock mutex and start thread
  187. pthread_mutex_lock(&thread_mutex);
  188. pthread_create(&td->td_pthread, &attr, NutThreadEntry, (void *) td);
  189. // wait for ack
  190. pthread_cond_wait(&main_cv, &thread_mutex);
  191. pthread_mutex_unlock(&thread_mutex);
  192. /*
  193. * If current context is not in front of
  194. * the run queue (highest priority), then
  195. * switch to the thread in front.
  196. */
  197. if (runningThread != runQueue) {
  198. runningThread->td_state = TDS_READY;
  199. #ifdef NUTDEBUG
  200. if (__os_trf)
  201. fprintf(__os_trs, "New<%08lx %08lx>\n", (uintptr_t) runningThread, (uintptr_t) runQueue);
  202. #endif
  203. NutThreadSwitch();
  204. }
  205. NutExitCritical();
  206. return td;
  207. }
  208. /*@}*/