sched.c 8.7 KB

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