sched.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  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 <exports.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. printf("[%s %d %s]: ",__FILE__,__LINE__,__FUNCTION__);\
  67. printf(fmt, ##args); \
  68. 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 (int ac, char *av[])
  84. {
  85. int i, j;
  86. int tid[NUMTHREADS];
  87. int names[NUMTHREADS];
  88. app_startup(av);
  89. sched_init ();
  90. for (i = 0; i < NUMTHREADS; i++) {
  91. names[i] = i;
  92. j = thread_create (testthread, (void *) &names[i]);
  93. if (j == RC_FAILURE)
  94. printf ("schedtest: Failed to create thread %d\n", i);
  95. if (j > 0) {
  96. printf ("schedtest: Created thread with id %d, name %d\n",
  97. j, i);
  98. tid[i] = j;
  99. }
  100. }
  101. printf ("schedtest: Threads created\n");
  102. printf ("sched_test: function=0x%08x\n", (unsigned)testthread);
  103. for (i = 0; i < NUMTHREADS; i++) {
  104. printf ("schedtest: Setting thread %d runnable\n", tid[i]);
  105. thread_start (tid[i]);
  106. thread_yield ();
  107. }
  108. printf ("schedtest: Started %d threads\n", NUMTHREADS);
  109. while (1) {
  110. printf ("schedtest: Waiting for threads to complete\n");
  111. if (tstc () && getc () == 0x3) {
  112. printf ("schedtest: Aborting threads...\n");
  113. for (i = 0; i < NUMTHREADS; i++) {
  114. printf ("schedtest: Deleting thread %d\n", tid[i]);
  115. thread_delete (tid[i]);
  116. }
  117. return RC_SUCCESS;
  118. }
  119. j = -1;
  120. i = thread_join (&j);
  121. if (i == RC_FAILURE) {
  122. printf ("schedtest: No threads pending, "
  123. "exiting schedular test\n");
  124. return RC_SUCCESS;
  125. }
  126. printf ("schedtest: thread is %d returned %d\n", i, j);
  127. thread_yield ();
  128. }
  129. return RC_SUCCESS;
  130. }
  131. static int testthread (void *name)
  132. {
  133. int i;
  134. printf ("testthread: Begin executing thread, myname %d, &i=0x%08x\n",
  135. *(int *) name, (unsigned)&i);
  136. printf ("Thread %02d, i=%d\n", *(int *) name, i);
  137. for (i = 0; i < 0xffff * (*(int *) name + 1); i++) {
  138. if (tstc () && getc () == 0x3) {
  139. printf ("testthread: myname %d terminating.\n",
  140. *(int *) name);
  141. return *(int *) name + 1;
  142. }
  143. if (i % 100 == 0)
  144. thread_yield ();
  145. }
  146. printf ("testthread: returning %d, i=0x%x\n",
  147. *(int *) name + 1, i);
  148. return *(int *) name + 1;
  149. }
  150. static void sched_init (void)
  151. {
  152. int i;
  153. for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++)
  154. lthreads[i].state = STATE_EMPTY;
  155. current_tid = MASTER_THREAD;
  156. lthreads[current_tid].state = STATE_RUNNABLE;
  157. PDEBUG ("sched_init: master context = 0x%08x",
  158. (unsigned)lthreads[current_tid].context);
  159. return;
  160. }
  161. static void thread_yield (void)
  162. {
  163. static int i;
  164. PDEBUG ("thread_yield: current tid=%d", current_tid);
  165. #define SWITCH(new) \
  166. if(lthreads[new].state == STATE_RUNNABLE) { \
  167. PDEBUG("thread_yield: %d match, ctx=0x%08x", \
  168. new, \
  169. (unsigned)lthreads[current_tid].context); \
  170. if(setjmp(lthreads[current_tid].context) == 0) { \
  171. current_tid = new; \
  172. PDEBUG("thread_yield: tid %d returns 0", \
  173. new); \
  174. longjmp(lthreads[new].context, 1); \
  175. } else { \
  176. PDEBUG("thread_yield: tid %d returns 1", \
  177. new); \
  178. return; \
  179. } \
  180. }
  181. for (i = current_tid + 1; i < MAX_THREADS; i++) {
  182. SWITCH (i);
  183. }
  184. if (current_tid != 0) {
  185. for (i = 0; i <= current_tid; i++) {
  186. SWITCH (i);
  187. }
  188. }
  189. PDEBUG ("thread_yield: returning from thread_yield");
  190. return;
  191. }
  192. static int thread_create (int (*func) (void *), void *arg)
  193. {
  194. int i;
  195. for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++) {
  196. if (lthreads[i].state == STATE_EMPTY) {
  197. lthreads[i].state = STATE_STOPPED;
  198. lthreads[i].func = func;
  199. lthreads[i].arg = arg;
  200. PDEBUG ("thread_create: returns new tid %d", i);
  201. return i;
  202. }
  203. }
  204. PDEBUG ("thread_create: returns failure");
  205. return RC_FAILURE;
  206. }
  207. static int thread_delete (int id)
  208. {
  209. if (id <= MASTER_THREAD || id > MAX_THREADS)
  210. return RC_FAILURE;
  211. if (current_tid == id)
  212. return RC_FAILURE;
  213. lthreads[id].state = STATE_EMPTY;
  214. return RC_SUCCESS;
  215. }
  216. static void thread_launcher (void)
  217. {
  218. PDEBUG ("thread_launcher: invoking func=0x%08x",
  219. (unsigned)lthreads[current_tid].func);
  220. lthreads[current_tid].retval =
  221. lthreads[current_tid].func (lthreads[current_tid].arg);
  222. PDEBUG ("thread_launcher: tid %d terminated", current_tid);
  223. lthreads[current_tid].state = STATE_TERMINATED;
  224. thread_yield ();
  225. printf ("thread_launcher: should NEVER get here!\n");
  226. return;
  227. }
  228. static int thread_start (int id)
  229. {
  230. PDEBUG ("thread_start: id=%d", id);
  231. if (id <= MASTER_THREAD || id > MAX_THREADS) {
  232. return RC_FAILURE;
  233. }
  234. if (lthreads[id].state != STATE_STOPPED)
  235. return RC_FAILURE;
  236. if (setjmp (lthreads[current_tid].context) == 0) {
  237. lthreads[id].state = STATE_RUNNABLE;
  238. current_tid = id;
  239. PDEBUG ("thread_start: to be stack=0%08x",
  240. (unsigned)lthreads[id].stack);
  241. setctxsp (&lthreads[id].stack[STK_SIZE]);
  242. thread_launcher ();
  243. }
  244. PDEBUG ("thread_start: Thread id=%d started, parent returns", id);
  245. return RC_SUCCESS;
  246. }
  247. #if 0 /* not used so far */
  248. static int thread_stop (int id)
  249. {
  250. if (id <= MASTER_THREAD || id >= MAX_THREADS)
  251. return RC_FAILURE;
  252. if (current_tid == id)
  253. return RC_FAILURE;
  254. lthreads[id].state = STATE_STOPPED;
  255. return RC_SUCCESS;
  256. }
  257. #endif /* not used so far */
  258. static int thread_join (int *ret)
  259. {
  260. int i, j = 0;
  261. PDEBUG ("thread_join: *ret = %d", *ret);
  262. if (!(*ret == -1 || *ret > MASTER_THREAD || *ret < MAX_THREADS)) {
  263. PDEBUG ("thread_join: invalid tid %d", *ret);
  264. return RC_FAILURE;
  265. }
  266. if (*ret == -1) {
  267. PDEBUG ("Checking for tid = -1");
  268. while (1) {
  269. /* PDEBUG("thread_join: start while-loopn"); */
  270. j = 0;
  271. for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++) {
  272. if (lthreads[i].state == STATE_TERMINATED) {
  273. *ret = lthreads[i].retval;
  274. lthreads[i].state = STATE_EMPTY;
  275. /* PDEBUG("thread_join: returning retval %d of tid %d",
  276. ret, i); */
  277. return RC_SUCCESS;
  278. }
  279. if (lthreads[i].state != STATE_EMPTY) {
  280. PDEBUG ("thread_join: %d used slots tid %d state=%d",
  281. j, i, lthreads[i].state);
  282. j++;
  283. }
  284. }
  285. if (j == 0) {
  286. PDEBUG ("thread_join: all slots empty!");
  287. return RC_FAILURE;
  288. }
  289. /* PDEBUG("thread_join: yielding"); */
  290. thread_yield ();
  291. /* PDEBUG("thread_join: back from yield"); */
  292. }
  293. }
  294. if (lthreads[*ret].state == STATE_TERMINATED) {
  295. i = *ret;
  296. *ret = lthreads[*ret].retval;
  297. lthreads[*ret].state = STATE_EMPTY;
  298. PDEBUG ("thread_join: returing %d for tid %d", *ret, i);
  299. return RC_SUCCESS;
  300. }
  301. PDEBUG ("thread_join: thread %d is not terminated!", *ret);
  302. return RC_FAILURE;
  303. }