xref: /OK3568_Linux_fs/u-boot/examples/standalone/sched.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 *)&lthreads[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