xref: /rk3399_rockchip-uboot/examples/standalone/sched.c (revision 326ea986ac150acdc7656d57fca647db80b50158)
11bc15386SPeter Tyser /*
2*1a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
31bc15386SPeter Tyser  */
41bc15386SPeter Tyser 
51bc15386SPeter Tyser #include <common.h>
61bc15386SPeter Tyser #include <exports.h>
71bc15386SPeter Tyser 
81bc15386SPeter Tyser /*
91bc15386SPeter Tyser  * Author: Arun Dharankar <ADharankar@ATTBI.Com>
101bc15386SPeter Tyser  *
111bc15386SPeter Tyser  * A very simple thread/schedular model:
121bc15386SPeter Tyser  *   - only one master thread, and no parent child relation maintained
131bc15386SPeter Tyser  *   - parent thread cannot be stopped or deleted
141bc15386SPeter Tyser  *   - no permissions or credentials
151bc15386SPeter Tyser  *   - no elaborate safety checks
161bc15386SPeter Tyser  *   - cooperative multi threading
171bc15386SPeter Tyser  *   - Simple round-robin scheduleing with no priorities
181bc15386SPeter Tyser  *   - no metering/statistics collection
191bc15386SPeter Tyser  *
201bc15386SPeter Tyser  * Basic idea of implementing this is to allow more than one tests to
211bc15386SPeter Tyser  * execute "simultaneously".
221bc15386SPeter Tyser  *
231bc15386SPeter Tyser  * This may be modified such thread_yield may be called in syscalls, and
241bc15386SPeter Tyser  * timer interrupts.
251bc15386SPeter Tyser  */
261bc15386SPeter Tyser 
271bc15386SPeter Tyser 
281bc15386SPeter Tyser #define MAX_THREADS 8
291bc15386SPeter Tyser 
301bc15386SPeter Tyser #define CTX_SIZE 512
311bc15386SPeter Tyser #define STK_SIZE 8*1024
321bc15386SPeter Tyser 
331bc15386SPeter Tyser #define STATE_EMPTY 0
341bc15386SPeter Tyser #define STATE_RUNNABLE 1
351bc15386SPeter Tyser #define STATE_STOPPED 2
361bc15386SPeter Tyser #define STATE_TERMINATED 2
371bc15386SPeter Tyser 
381bc15386SPeter Tyser #define MASTER_THREAD 0
391bc15386SPeter Tyser 
401bc15386SPeter Tyser #define RC_FAILURE	(-1)
411bc15386SPeter Tyser #define	RC_SUCCESS	(0)
421bc15386SPeter Tyser 
431bc15386SPeter Tyser typedef	vu_char *jmp_ctx;
441bc15386SPeter Tyser unsigned long setctxsp (vu_char *sp);
451bc15386SPeter Tyser int ppc_setjmp(jmp_ctx env);
461bc15386SPeter Tyser void ppc_longjmp(jmp_ctx env, int val);
471bc15386SPeter Tyser #define setjmp	ppc_setjmp
481bc15386SPeter Tyser #define longjmp	ppc_longjmp
491bc15386SPeter Tyser 
501bc15386SPeter Tyser struct lthread {
511bc15386SPeter Tyser 	int state;
521bc15386SPeter Tyser 	int retval;
531bc15386SPeter Tyser 	char stack[STK_SIZE];
541bc15386SPeter Tyser 	uchar context[CTX_SIZE];
551bc15386SPeter Tyser 	int (*func) (void *);
561bc15386SPeter Tyser 	void *arg;
571bc15386SPeter Tyser };
581bc15386SPeter Tyser static volatile struct lthread lthreads[MAX_THREADS];
591bc15386SPeter Tyser static volatile int current_tid = MASTER_THREAD;
601bc15386SPeter Tyser 
611bc15386SPeter Tyser 
621bc15386SPeter Tyser static uchar dbg = 0;
631bc15386SPeter Tyser 
641bc15386SPeter Tyser #define PDEBUG(fmt, args...)	 {					\
651bc15386SPeter Tyser 	if(dbg != 0) {							\
661bc15386SPeter Tyser 		printf("[%s %d %s]: ",__FILE__,__LINE__,__FUNCTION__);\
671bc15386SPeter Tyser 		printf(fmt, ##args);				\
681bc15386SPeter Tyser 		printf("\n");					\
691bc15386SPeter Tyser 	}								\
701bc15386SPeter Tyser }
711bc15386SPeter Tyser 
721bc15386SPeter Tyser static int testthread (void *);
731bc15386SPeter Tyser static void sched_init (void);
741bc15386SPeter Tyser static int thread_create (int (*func) (void *), void *arg);
751bc15386SPeter Tyser static int thread_start (int id);
761bc15386SPeter Tyser static void thread_yield (void);
771bc15386SPeter Tyser static int thread_delete (int id);
781bc15386SPeter Tyser static int thread_join (int *ret);
791bc15386SPeter Tyser 
801bc15386SPeter Tyser #if 0							/* not used yet */
811bc15386SPeter Tyser static int thread_stop (int id);
821bc15386SPeter Tyser #endif							/* not used yet */
831bc15386SPeter Tyser 
841bc15386SPeter Tyser /* An example of schedular test */
851bc15386SPeter Tyser 
861bc15386SPeter Tyser #define NUMTHREADS 7
sched(int ac,char * av[])871bc15386SPeter Tyser int sched (int ac, char *av[])
881bc15386SPeter Tyser {
891bc15386SPeter Tyser 	int i, j;
901bc15386SPeter Tyser 	int tid[NUMTHREADS];
911bc15386SPeter Tyser 	int names[NUMTHREADS];
921bc15386SPeter Tyser 
931bc15386SPeter Tyser 	app_startup(av);
941bc15386SPeter Tyser 
951bc15386SPeter Tyser 	sched_init ();
961bc15386SPeter Tyser 
971bc15386SPeter Tyser 	for (i = 0; i < NUMTHREADS; i++) {
981bc15386SPeter Tyser 		names[i] = i;
991bc15386SPeter Tyser 		j = thread_create (testthread, (void *) &names[i]);
1001bc15386SPeter Tyser 		if (j == RC_FAILURE)
1011bc15386SPeter Tyser 			printf ("schedtest: Failed to create thread %d\n", i);
1021bc15386SPeter Tyser 		if (j > 0) {
1031bc15386SPeter Tyser 			printf ("schedtest: Created thread with id %d, name %d\n",
1041bc15386SPeter Tyser 						j, i);
1051bc15386SPeter Tyser 			tid[i] = j;
1061bc15386SPeter Tyser 		}
1071bc15386SPeter Tyser 	}
1081bc15386SPeter Tyser 	printf ("schedtest: Threads created\n");
1091bc15386SPeter Tyser 
1101bc15386SPeter Tyser 	printf ("sched_test: function=0x%08x\n", (unsigned)testthread);
1111bc15386SPeter Tyser 	for (i = 0; i < NUMTHREADS; i++) {
1121bc15386SPeter Tyser 		printf ("schedtest: Setting thread %d runnable\n", tid[i]);
1131bc15386SPeter Tyser 		thread_start (tid[i]);
1141bc15386SPeter Tyser 		thread_yield ();
1151bc15386SPeter Tyser 	}
1161bc15386SPeter Tyser 	printf ("schedtest: Started %d threads\n", NUMTHREADS);
1171bc15386SPeter Tyser 
1181bc15386SPeter Tyser 	while (1) {
1191bc15386SPeter Tyser 		printf ("schedtest: Waiting for threads to complete\n");
1201bc15386SPeter Tyser 		if (tstc () && getc () == 0x3) {
1211bc15386SPeter Tyser 			printf ("schedtest: Aborting threads...\n");
1221bc15386SPeter Tyser 			for (i = 0; i < NUMTHREADS; i++) {
1231bc15386SPeter Tyser 				printf ("schedtest: Deleting thread %d\n", tid[i]);
1241bc15386SPeter Tyser 				thread_delete (tid[i]);
1251bc15386SPeter Tyser 			}
1261bc15386SPeter Tyser 			return RC_SUCCESS;
1271bc15386SPeter Tyser 		}
1281bc15386SPeter Tyser 		j = -1;
1291bc15386SPeter Tyser 		i = thread_join (&j);
1301bc15386SPeter Tyser 		if (i == RC_FAILURE) {
1311bc15386SPeter Tyser 			printf ("schedtest: No threads pending, "
1321bc15386SPeter Tyser 						"exiting schedular test\n");
1331bc15386SPeter Tyser 			return RC_SUCCESS;
1341bc15386SPeter Tyser 		}
1351bc15386SPeter Tyser 		printf ("schedtest: thread is %d returned %d\n", i, j);
1361bc15386SPeter Tyser 		thread_yield ();
1371bc15386SPeter Tyser 	}
1381bc15386SPeter Tyser 
1391bc15386SPeter Tyser 	return RC_SUCCESS;
1401bc15386SPeter Tyser }
1411bc15386SPeter Tyser 
testthread(void * name)1421bc15386SPeter Tyser static int testthread (void *name)
1431bc15386SPeter Tyser {
1441bc15386SPeter Tyser 	int i;
1451bc15386SPeter Tyser 
1461bc15386SPeter Tyser 	printf ("testthread: Begin executing thread, myname %d, &i=0x%08x\n",
1471bc15386SPeter Tyser 		*(int *) name, (unsigned)&i);
1481bc15386SPeter Tyser 
1491bc15386SPeter Tyser 	printf ("Thread %02d, i=%d\n", *(int *) name, i);
1501bc15386SPeter Tyser 
1511bc15386SPeter Tyser 	for (i = 0; i < 0xffff * (*(int *) name + 1); i++) {
1521bc15386SPeter Tyser 		if (tstc () && getc () == 0x3) {
1531bc15386SPeter Tyser 			printf ("testthread: myname %d terminating.\n",
1541bc15386SPeter Tyser 						*(int *) name);
1551bc15386SPeter Tyser 			return *(int *) name + 1;
1561bc15386SPeter Tyser 		}
1571bc15386SPeter Tyser 
1581bc15386SPeter Tyser 		if (i % 100 == 0)
1591bc15386SPeter Tyser 			thread_yield ();
1601bc15386SPeter Tyser 	}
1611bc15386SPeter Tyser 
1621bc15386SPeter Tyser 	printf ("testthread: returning %d, i=0x%x\n",
1631bc15386SPeter Tyser 				*(int *) name + 1, i);
1641bc15386SPeter Tyser 
1651bc15386SPeter Tyser 	return *(int *) name + 1;
1661bc15386SPeter Tyser }
1671bc15386SPeter Tyser 
1681bc15386SPeter Tyser 
sched_init(void)1691bc15386SPeter Tyser static void sched_init (void)
1701bc15386SPeter Tyser {
1711bc15386SPeter Tyser 	int i;
1721bc15386SPeter Tyser 
1731bc15386SPeter Tyser 	for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++)
1741bc15386SPeter Tyser 		lthreads[i].state = STATE_EMPTY;
1751bc15386SPeter Tyser 
1761bc15386SPeter Tyser 	current_tid = MASTER_THREAD;
1771bc15386SPeter Tyser 	lthreads[current_tid].state = STATE_RUNNABLE;
1781bc15386SPeter Tyser 	PDEBUG ("sched_init: master context = 0x%08x",
1791bc15386SPeter Tyser 		(unsigned)lthreads[current_tid].context);
1801bc15386SPeter Tyser 	return;
1811bc15386SPeter Tyser }
1821bc15386SPeter Tyser 
thread_yield(void)1831bc15386SPeter Tyser static void thread_yield (void)
1841bc15386SPeter Tyser {
1851bc15386SPeter Tyser 	static int i;
1861bc15386SPeter Tyser 
1871bc15386SPeter Tyser 	PDEBUG ("thread_yield: current tid=%d", current_tid);
1881bc15386SPeter Tyser 
1891bc15386SPeter Tyser #define SWITCH(new)							\
1901bc15386SPeter Tyser 	if(lthreads[new].state == STATE_RUNNABLE) {			\
1911bc15386SPeter Tyser 		PDEBUG("thread_yield: %d match, ctx=0x%08x",		\
1921bc15386SPeter Tyser 			new,						\
1931bc15386SPeter Tyser 			(unsigned)lthreads[current_tid].context);	\
1941bc15386SPeter Tyser 		if(setjmp(lthreads[current_tid].context) == 0) {	\
1951bc15386SPeter Tyser 			current_tid = new;				\
1961bc15386SPeter Tyser 			PDEBUG("thread_yield: tid %d returns 0",	\
1971bc15386SPeter Tyser 				new);					\
1981bc15386SPeter Tyser 			longjmp(lthreads[new].context, 1);		\
1991bc15386SPeter Tyser 		} else {						\
2001bc15386SPeter Tyser 			PDEBUG("thread_yield: tid %d returns 1",	\
2011bc15386SPeter Tyser 				new);					\
2021bc15386SPeter Tyser 			return;						\
2031bc15386SPeter Tyser 		}							\
2041bc15386SPeter Tyser 	}
2051bc15386SPeter Tyser 
2061bc15386SPeter Tyser 	for (i = current_tid + 1; i < MAX_THREADS; i++) {
2071bc15386SPeter Tyser 		SWITCH (i);
2081bc15386SPeter Tyser 	}
2091bc15386SPeter Tyser 
2101bc15386SPeter Tyser 	if (current_tid != 0) {
2111bc15386SPeter Tyser 		for (i = 0; i <= current_tid; i++) {
2121bc15386SPeter Tyser 			SWITCH (i);
2131bc15386SPeter Tyser 		}
2141bc15386SPeter Tyser 	}
2151bc15386SPeter Tyser 
2161bc15386SPeter Tyser 	PDEBUG ("thread_yield: returning from thread_yield");
2171bc15386SPeter Tyser 	return;
2181bc15386SPeter Tyser }
2191bc15386SPeter Tyser 
thread_create(int (* func)(void *),void * arg)2201bc15386SPeter Tyser static int thread_create (int (*func) (void *), void *arg)
2211bc15386SPeter Tyser {
2221bc15386SPeter Tyser 	int i;
2231bc15386SPeter Tyser 
2241bc15386SPeter Tyser 	for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++) {
2251bc15386SPeter Tyser 		if (lthreads[i].state == STATE_EMPTY) {
2261bc15386SPeter Tyser 			lthreads[i].state = STATE_STOPPED;
2271bc15386SPeter Tyser 			lthreads[i].func = func;
2281bc15386SPeter Tyser 			lthreads[i].arg = arg;
2291bc15386SPeter Tyser 			PDEBUG ("thread_create: returns new tid %d", i);
2301bc15386SPeter Tyser 			return i;
2311bc15386SPeter Tyser 		}
2321bc15386SPeter Tyser 	}
2331bc15386SPeter Tyser 
2341bc15386SPeter Tyser 	PDEBUG ("thread_create: returns failure");
2351bc15386SPeter Tyser 	return RC_FAILURE;
2361bc15386SPeter Tyser }
2371bc15386SPeter Tyser 
thread_delete(int id)2381bc15386SPeter Tyser static int thread_delete (int id)
2391bc15386SPeter Tyser {
2401bc15386SPeter Tyser 	if (id <= MASTER_THREAD || id > MAX_THREADS)
2411bc15386SPeter Tyser 		return RC_FAILURE;
2421bc15386SPeter Tyser 
2431bc15386SPeter Tyser 	if (current_tid == id)
2441bc15386SPeter Tyser 		return RC_FAILURE;
2451bc15386SPeter Tyser 
2461bc15386SPeter Tyser 	lthreads[id].state = STATE_EMPTY;
2471bc15386SPeter Tyser 	return RC_SUCCESS;
2481bc15386SPeter Tyser }
2491bc15386SPeter Tyser 
thread_launcher(void)2501bc15386SPeter Tyser static void thread_launcher (void)
2511bc15386SPeter Tyser {
2521bc15386SPeter Tyser 	PDEBUG ("thread_launcher: invoking func=0x%08x",
2531bc15386SPeter Tyser 		   (unsigned)lthreads[current_tid].func);
2541bc15386SPeter Tyser 
2551bc15386SPeter Tyser 	lthreads[current_tid].retval =
2561bc15386SPeter Tyser 			lthreads[current_tid].func (lthreads[current_tid].arg);
2571bc15386SPeter Tyser 
2581bc15386SPeter Tyser 	PDEBUG ("thread_launcher: tid %d terminated", current_tid);
2591bc15386SPeter Tyser 
2601bc15386SPeter Tyser 	lthreads[current_tid].state = STATE_TERMINATED;
2611bc15386SPeter Tyser 	thread_yield ();
2621bc15386SPeter Tyser 	printf ("thread_launcher: should NEVER get here!\n");
2631bc15386SPeter Tyser 
2641bc15386SPeter Tyser 	return;
2651bc15386SPeter Tyser }
2661bc15386SPeter Tyser 
thread_start(int id)2671bc15386SPeter Tyser static int thread_start (int id)
2681bc15386SPeter Tyser {
2691bc15386SPeter Tyser 	PDEBUG ("thread_start: id=%d", id);
2701bc15386SPeter Tyser 	if (id <= MASTER_THREAD || id > MAX_THREADS) {
2711bc15386SPeter Tyser 		return RC_FAILURE;
2721bc15386SPeter Tyser 	}
2731bc15386SPeter Tyser 
2741bc15386SPeter Tyser 	if (lthreads[id].state != STATE_STOPPED)
2751bc15386SPeter Tyser 		return RC_FAILURE;
2761bc15386SPeter Tyser 
2771bc15386SPeter Tyser 	if (setjmp (lthreads[current_tid].context) == 0) {
2781bc15386SPeter Tyser 		lthreads[id].state = STATE_RUNNABLE;
2791bc15386SPeter Tyser 		current_tid = id;
2801bc15386SPeter Tyser 		PDEBUG ("thread_start: to be stack=0%08x",
2811bc15386SPeter Tyser 			(unsigned)lthreads[id].stack);
2821bc15386SPeter Tyser 		setctxsp ((vu_char *)&lthreads[id].stack[STK_SIZE]);
2831bc15386SPeter Tyser 		thread_launcher ();
2841bc15386SPeter Tyser 	}
2851bc15386SPeter Tyser 
2861bc15386SPeter Tyser 	PDEBUG ("thread_start: Thread id=%d started, parent returns", id);
2871bc15386SPeter Tyser 
2881bc15386SPeter Tyser 	return RC_SUCCESS;
2891bc15386SPeter Tyser }
2901bc15386SPeter Tyser 
2911bc15386SPeter Tyser #if 0	/* not used so far */
2921bc15386SPeter Tyser static int thread_stop (int id)
2931bc15386SPeter Tyser {
2941bc15386SPeter Tyser 	if (id <= MASTER_THREAD || id >= MAX_THREADS)
2951bc15386SPeter Tyser 		return RC_FAILURE;
2961bc15386SPeter Tyser 
2971bc15386SPeter Tyser 	if (current_tid == id)
2981bc15386SPeter Tyser 		return RC_FAILURE;
2991bc15386SPeter Tyser 
3001bc15386SPeter Tyser 	lthreads[id].state = STATE_STOPPED;
3011bc15386SPeter Tyser 	return RC_SUCCESS;
3021bc15386SPeter Tyser }
3031bc15386SPeter Tyser #endif	/* not used so far */
3041bc15386SPeter Tyser 
thread_join(int * ret)3051bc15386SPeter Tyser static int thread_join (int *ret)
3061bc15386SPeter Tyser {
3071bc15386SPeter Tyser 	int i, j = 0;
3081bc15386SPeter Tyser 
3091bc15386SPeter Tyser 	PDEBUG ("thread_join: *ret = %d", *ret);
3101bc15386SPeter Tyser 
3111bc15386SPeter Tyser 	if (!(*ret == -1 || *ret > MASTER_THREAD || *ret < MAX_THREADS)) {
3121bc15386SPeter Tyser 		PDEBUG ("thread_join: invalid tid %d", *ret);
3131bc15386SPeter Tyser 		return RC_FAILURE;
3141bc15386SPeter Tyser 	}
3151bc15386SPeter Tyser 
3161bc15386SPeter Tyser 	if (*ret == -1) {
3171bc15386SPeter Tyser 		PDEBUG ("Checking for tid = -1");
3181bc15386SPeter Tyser 		while (1) {
3191bc15386SPeter Tyser 			/* PDEBUG("thread_join: start while-loopn"); */
3201bc15386SPeter Tyser 			j = 0;
3211bc15386SPeter Tyser 			for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++) {
3221bc15386SPeter Tyser 				if (lthreads[i].state == STATE_TERMINATED) {
3231bc15386SPeter Tyser 					*ret = lthreads[i].retval;
3241bc15386SPeter Tyser 					lthreads[i].state = STATE_EMPTY;
3251bc15386SPeter Tyser 					/* PDEBUG("thread_join: returning retval %d of tid %d",
3261bc15386SPeter Tyser 					   ret, i); */
3271bc15386SPeter Tyser 					return RC_SUCCESS;
3281bc15386SPeter Tyser 				}
3291bc15386SPeter Tyser 
3301bc15386SPeter Tyser 				if (lthreads[i].state != STATE_EMPTY) {
3311bc15386SPeter Tyser 					PDEBUG ("thread_join: %d used slots tid %d state=%d",
3321bc15386SPeter Tyser 						   j, i, lthreads[i].state);
3331bc15386SPeter Tyser 					j++;
3341bc15386SPeter Tyser 				}
3351bc15386SPeter Tyser 			}
3361bc15386SPeter Tyser 			if (j == 0) {
3371bc15386SPeter Tyser 				PDEBUG ("thread_join: all slots empty!");
3381bc15386SPeter Tyser 				return RC_FAILURE;
3391bc15386SPeter Tyser 			}
3401bc15386SPeter Tyser 			/*  PDEBUG("thread_join: yielding"); */
3411bc15386SPeter Tyser 			thread_yield ();
3421bc15386SPeter Tyser 			/*  PDEBUG("thread_join: back from yield"); */
3431bc15386SPeter Tyser 		}
3441bc15386SPeter Tyser 	}
3451bc15386SPeter Tyser 
3461bc15386SPeter Tyser 	if (lthreads[*ret].state == STATE_TERMINATED) {
3471bc15386SPeter Tyser 		i = *ret;
3481bc15386SPeter Tyser 		*ret = lthreads[*ret].retval;
3491bc15386SPeter Tyser 		lthreads[*ret].state = STATE_EMPTY;
3501bc15386SPeter Tyser 		PDEBUG ("thread_join: returing %d for tid %d", *ret, i);
3511bc15386SPeter Tyser 		return RC_SUCCESS;
3521bc15386SPeter Tyser 	}
3531bc15386SPeter Tyser 
3541bc15386SPeter Tyser 	PDEBUG ("thread_join: thread %d is not terminated!", *ret);
3551bc15386SPeter Tyser 	return RC_FAILURE;
3561bc15386SPeter Tyser }
357