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