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