sched.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /*
  2. * This program is free software; you can redistribute it and/or
  3. * modify it under the terms of the GNU General Public License as
  4. * published by the Free Software Foundation; either version 2 of
  5. * the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program; if not, write to the Free Software
  14. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  15. * MA 02111-1307 USA
  16. */
  17. #include <common.h>
  18. #include <syscall.h>
  19. #include <setjmp.h>
  20. /*
  21. * Author: Arun Dharankar <ADharankar@ATTBI.Com>
  22. *
  23. * A very simple thread/schedular model:
  24. * - only one master thread, and no parent child relation maintained
  25. * - parent thread cannot be stopped or deleted
  26. * - no permissions or credentials
  27. * - no elaborate safety checks
  28. * - cooperative multi threading
  29. * - Simple round-robin scheduleing with no priorities
  30. * - no metering/statistics collection
  31. *
  32. * Basic idea of implementing this is to allow more than one tests to
  33. * execute "simultaneously".
  34. *
  35. * This may be modified such thread_yield may be called in syscalls, and
  36. * timer interrupts.
  37. */
  38. #define MAX_THREADS 8
  39. #define CTX_SIZE 512
  40. #define STK_SIZE 8*1024
  41. #define STATE_EMPTY 0
  42. #define STATE_RUNNABLE 1
  43. #define STATE_STOPPED 2
  44. #define STATE_TERMINATED 2
  45. #define MASTER_THREAD 0
  46. #define RC_FAILURE (-1)
  47. #define RC_SUCCESS (0)
  48. struct lthread {
  49. int state;
  50. int retval;
  51. char stack[STK_SIZE];
  52. uchar context[CTX_SIZE];
  53. int (*func) (void *);
  54. void *arg;
  55. };
  56. static volatile struct lthread lthreads[MAX_THREADS];
  57. static volatile int current_tid = MASTER_THREAD;
  58. static uchar dbg = 0;
  59. #define DEBUG(fmt, args...) { \
  60. if(dbg != 0) { \
  61. mon_printf("[%s %d %s]: ", __FILE__, __LINE__, __FUNCTION__); \
  62. mon_printf(fmt, ##args); \
  63. mon_printf("\n"); \
  64. } \
  65. }
  66. static int testthread (void *);
  67. static void sched_init (void);
  68. static int thread_create (int (*func) (void *), void *arg);
  69. static int thread_start (int id);
  70. static void thread_yield (void);
  71. static int thread_delete (int id);
  72. static int thread_join (int *ret);
  73. #if 0 /* not used yet */
  74. static int thread_stop (int id);
  75. #endif /* not used yet */
  76. /* An example of schedular test */
  77. #define NUMTHREADS 7
  78. int sched (bd_t *bd, int ac, char *av[])
  79. {
  80. int i, j;
  81. int tid[NUMTHREADS];
  82. int names[NUMTHREADS];
  83. sched_init ();
  84. for (i = 0; i < NUMTHREADS; i++) {
  85. names[i] = i;
  86. j = thread_create (testthread, (void *) &names[i]);
  87. if (j == RC_FAILURE)
  88. mon_printf ("schedtest: Failed to create thread %d\n",
  89. i);
  90. if (j > 0) {
  91. mon_printf ("schedtest: Created thread with id %d, name %d\n",
  92. j, i);
  93. tid[i] = j;
  94. }
  95. }
  96. mon_printf ("schedtest: Threads created\n");
  97. mon_printf ("sched_test: function=0x%08x\n", testthread);
  98. for (i = 0; i < NUMTHREADS; i++) {
  99. mon_printf ("schedtest: Setting thread %d runnable\n", tid[i]);
  100. thread_start (tid[i]);
  101. thread_yield ();
  102. }
  103. mon_printf ("schedtest: Started %d threads\n", NUMTHREADS);
  104. while (1) {
  105. mon_printf ("schedtest: Waiting for threads to complete\n");
  106. if (mon_tstc () && mon_getc () == 0x3) {
  107. mon_printf ("schedtest: Aborting threads...\n");
  108. for (i = 0; i < NUMTHREADS; i++) {
  109. mon_printf ("schedtest: Deleting thread %d\n",
  110. tid[i]);
  111. thread_delete (tid[i]);
  112. }
  113. return RC_SUCCESS;
  114. }
  115. j = -1;
  116. i = thread_join (&j);
  117. if (i == RC_FAILURE) {
  118. mon_printf ("schedtest: No threads pending, "
  119. "exiting schedular test\n");
  120. return RC_SUCCESS;
  121. }
  122. mon_printf ("schedtest: thread is %d returned %d\n", i,
  123. j);
  124. thread_yield ();
  125. }
  126. return RC_SUCCESS;
  127. }
  128. static int testthread (void *name)
  129. {
  130. int i;
  131. mon_printf ("testthread: Begin executing thread, myname %d, &i=0x%08x\n",
  132. *(int *) name, &i);
  133. mon_printf ("Thread %02d, i=%d\n", *(int *) name);
  134. for (i = 0; i < 0xffff * (*(int *) name + 1); i++) {
  135. if (mon_tstc () && mon_getc () == 0x3) {
  136. mon_printf ("testthread: myname %d terminating.\n",
  137. *(int *) name);
  138. return *(int *) name + 1;
  139. }
  140. if (i % 100 == 0)
  141. thread_yield ();
  142. }
  143. mon_printf ("testthread: returning %d, i=0x%x\n",
  144. *(int *) name + 1, i);
  145. return *(int *) name + 1;
  146. }
  147. static void sched_init (void)
  148. {
  149. int i;
  150. for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++)
  151. lthreads[i].state = STATE_EMPTY;
  152. current_tid = MASTER_THREAD;
  153. lthreads[current_tid].state = STATE_RUNNABLE;
  154. DEBUG ("sched_init: master context = 0x%08x",
  155. lthreads[current_tid].context);
  156. return;
  157. }
  158. static void thread_yield (void)
  159. {
  160. static int i;
  161. DEBUG ("thread_yield: current tid=%d", current_tid);
  162. #define SWITCH(new) \
  163. if(lthreads[new].state == STATE_RUNNABLE) { \
  164. DEBUG("thread_yield: %d match, ctx=0x%08x", \
  165. new, lthreads[current_tid].context); \
  166. if(setjmp(lthreads[current_tid].context) == 0) { \
  167. current_tid = new; \
  168. DEBUG("thread_yield: tid %d returns 0", \
  169. new); \
  170. longjmp(lthreads[new].context, 1); \
  171. } else { \
  172. DEBUG("thread_yield: tid %d returns 1", \
  173. new); \
  174. return; \
  175. } \
  176. }
  177. for (i = current_tid + 1; i < MAX_THREADS; i++) {
  178. SWITCH (i);
  179. }
  180. if (current_tid != 0) {
  181. for (i = 0; i <= current_tid; i++) {
  182. SWITCH (i);
  183. }
  184. }
  185. DEBUG ("thread_yield: returning from thread_yield");
  186. return;
  187. }
  188. static int thread_create (int (*func) (void *), void *arg)
  189. {
  190. int i;
  191. for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++) {
  192. if (lthreads[i].state == STATE_EMPTY) {
  193. lthreads[i].state = STATE_STOPPED;
  194. lthreads[i].func = func;
  195. lthreads[i].arg = arg;
  196. DEBUG ("thread_create: returns new tid %d", i);
  197. return i;
  198. }
  199. }
  200. DEBUG ("thread_create: returns failure");
  201. return RC_FAILURE;
  202. }
  203. static int thread_delete (int id)
  204. {
  205. if (id <= MASTER_THREAD || id > MAX_THREADS)
  206. return RC_FAILURE;
  207. if (current_tid == id)
  208. return RC_FAILURE;
  209. lthreads[id].state = STATE_EMPTY;
  210. return RC_SUCCESS;
  211. }
  212. static void thread_launcher (void)
  213. {
  214. DEBUG ("thread_launcher: invoking func=0x%08x",
  215. lthreads[current_tid].func);
  216. lthreads[current_tid].retval =
  217. lthreads[current_tid].func(lthreads[current_tid].arg);
  218. DEBUG ("thread_launcher: tid %d terminated", current_tid);
  219. lthreads[current_tid].state = STATE_TERMINATED;
  220. thread_yield ();
  221. mon_printf ("thread_launcher: should NEVER get here!\n");
  222. return;
  223. }
  224. static int thread_start (int id)
  225. {
  226. DEBUG ("thread_start: id=%d", id);
  227. if (id <= MASTER_THREAD || id > MAX_THREADS) {
  228. return RC_FAILURE;
  229. }
  230. if (lthreads[id].state != STATE_STOPPED)
  231. return RC_FAILURE;
  232. if (setjmp (lthreads[current_tid].context) == 0) {
  233. lthreads[id].state = STATE_RUNNABLE;
  234. current_tid = id;
  235. DEBUG ("thread_start: to be stack=0%08x", lthreads[id].stack);
  236. setctxsp (&lthreads[id].stack[STK_SIZE]);
  237. thread_launcher ();
  238. }
  239. DEBUG ("thread_start: Thread id=%d started, parent returns", id);
  240. return RC_SUCCESS;
  241. }
  242. #if 0 /* not used so far */
  243. static int thread_stop (int id)
  244. {
  245. if (id <= MASTER_THREAD || id >= MAX_THREADS)
  246. return RC_FAILURE;
  247. if (current_tid == id)
  248. return RC_FAILURE;
  249. lthreads[id].state = STATE_STOPPED;
  250. return RC_SUCCESS;
  251. }
  252. #endif /* not used so far */
  253. static int thread_join (int *ret)
  254. {
  255. int i, j = 0;
  256. DEBUG ("thread_join: *ret = %d", *ret);
  257. if (!(*ret == -1 || *ret > MASTER_THREAD || *ret < MAX_THREADS)) {
  258. DEBUG ("thread_join: invalid tid %d", *ret);
  259. return RC_FAILURE;
  260. }
  261. if (*ret == -1) {
  262. DEBUG ("Checking for tid = -1");
  263. while (1) {
  264. /* DEBUG("thread_join: start while-loopn"); */
  265. j = 0;
  266. for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++) {
  267. if (lthreads[i].state == STATE_TERMINATED) {
  268. *ret = lthreads[i].retval;
  269. lthreads[i].state = STATE_EMPTY;
  270. /* DEBUG("thread_join: returning retval %d of tid %d",
  271. ret, i); */
  272. return RC_SUCCESS;
  273. }
  274. if (lthreads[i].state != STATE_EMPTY) {
  275. DEBUG ("thread_join: %d used slots tid %d state=%d",
  276. j, i, lthreads[i].state);
  277. j++;
  278. }
  279. }
  280. if (j == 0) {
  281. DEBUG ("thread_join: all slots empty!");
  282. return RC_FAILURE;
  283. }
  284. /* DEBUG("thread_join: yielding"); */
  285. thread_yield ();
  286. /* DEBUG("thread_join: back from yield"); */
  287. }
  288. }
  289. if (lthreads[*ret].state == STATE_TERMINATED) {
  290. i = *ret;
  291. *ret = lthreads[*ret].retval;
  292. lthreads[*ret].state = STATE_EMPTY;
  293. DEBUG ("thread_join: returing %d for tid %d", *ret, i);
  294. return RC_SUCCESS;
  295. }
  296. DEBUG ("thread_join: thread %d is not terminated!", *ret);
  297. return RC_FAILURE;
  298. }