diff options
| author | Peter Tyser <ptyser@xes-inc.com> | 2009-07-10 11:03:19 -0500 | 
|---|---|---|
| committer | Wolfgang Denk <wd@denx.de> | 2009-07-21 00:13:21 +0200 | 
| commit | 1bc1538613d66cef3cbce680fc8d7c3561a0fbd0 (patch) | |
| tree | f832202519d4077e8ca735948198691f054fe968 /examples/standalone/sched.c | |
| parent | b220c64d86f7c705a183302c3b50076d7e5d876c (diff) | |
| download | olio-uboot-2014.01-1bc1538613d66cef3cbce680fc8d7c3561a0fbd0.tar.xz olio-uboot-2014.01-1bc1538613d66cef3cbce680fc8d7c3561a0fbd0.zip  | |
Move examples/ to examples/standalone
The current files in examples are all standalone application examples,
so put them in their own subdirectory for organizational purposes
Signed-off-by: Peter Tyser <ptyser@xes-inc.com>
Diffstat (limited to 'examples/standalone/sched.c')
| -rw-r--r-- | examples/standalone/sched.c | 369 | 
1 files changed, 369 insertions, 0 deletions
diff --git a/examples/standalone/sched.c b/examples/standalone/sched.c new file mode 100644 index 000000000..b32766fed --- /dev/null +++ b/examples/standalone/sched.c @@ -0,0 +1,369 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <exports.h> + +/* + * Author: Arun Dharankar <ADharankar@ATTBI.Com> + * + * A very simple thread/schedular model: + *   - only one master thread, and no parent child relation maintained + *   - parent thread cannot be stopped or deleted + *   - no permissions or credentials + *   - no elaborate safety checks + *   - cooperative multi threading + *   - Simple round-robin scheduleing with no priorities + *   - no metering/statistics collection + * + * Basic idea of implementing this is to allow more than one tests to + * execute "simultaneously". + * + * This may be modified such thread_yield may be called in syscalls, and + * timer interrupts. + */ + + +#define MAX_THREADS 8 + +#define CTX_SIZE 512 +#define STK_SIZE 8*1024 + +#define STATE_EMPTY 0 +#define STATE_RUNNABLE 1 +#define STATE_STOPPED 2 +#define STATE_TERMINATED 2 + +#define MASTER_THREAD 0 + +#define RC_FAILURE	(-1) +#define	RC_SUCCESS	(0) + +typedef	vu_char *jmp_ctx; +unsigned long setctxsp (vu_char *sp); +int ppc_setjmp(jmp_ctx env); +void ppc_longjmp(jmp_ctx env, int val); +#define setjmp	ppc_setjmp +#define longjmp	ppc_longjmp + +struct lthread { +	int state; +	int retval; +	char stack[STK_SIZE]; +	uchar context[CTX_SIZE]; +	int (*func) (void *); +	void *arg; +}; +static volatile struct lthread lthreads[MAX_THREADS]; +static volatile int current_tid = MASTER_THREAD; + + +static uchar dbg = 0; + +#define PDEBUG(fmt, args...)	 {					\ +	if(dbg != 0) {							\ +		printf("[%s %d %s]: ",__FILE__,__LINE__,__FUNCTION__);\ +		printf(fmt, ##args);				\ +		printf("\n");					\ +	}								\ +} + +static int testthread (void *); +static void sched_init (void); +static int thread_create (int (*func) (void *), void *arg); +static int thread_start (int id); +static void thread_yield (void); +static int thread_delete (int id); +static int thread_join (int *ret); + +#if 0							/* not used yet */ +static int thread_stop (int id); +#endif							/* not used yet */ + +/* An example of schedular test */ + +#define NUMTHREADS 7 +int sched (int ac, char *av[]) +{ +	int i, j; +	int tid[NUMTHREADS]; +	int names[NUMTHREADS]; + +	app_startup(av); + +	sched_init (); + +	for (i = 0; i < NUMTHREADS; i++) { +		names[i] = i; +		j = thread_create (testthread, (void *) &names[i]); +		if (j == RC_FAILURE) +			printf ("schedtest: Failed to create thread %d\n", i); +		if (j > 0) { +			printf ("schedtest: Created thread with id %d, name %d\n", +						j, i); +			tid[i] = j; +		} +	} +	printf ("schedtest: Threads created\n"); + +	printf ("sched_test: function=0x%08x\n", (unsigned)testthread); +	for (i = 0; i < NUMTHREADS; i++) { +		printf ("schedtest: Setting thread %d runnable\n", tid[i]); +		thread_start (tid[i]); +		thread_yield (); +	} +	printf ("schedtest: Started %d threads\n", NUMTHREADS); + +	while (1) { +		printf ("schedtest: Waiting for threads to complete\n"); +		if (tstc () && getc () == 0x3) { +			printf ("schedtest: Aborting threads...\n"); +			for (i = 0; i < NUMTHREADS; i++) { +				printf ("schedtest: Deleting thread %d\n", tid[i]); +				thread_delete (tid[i]); +			} +			return RC_SUCCESS; +		} +		j = -1; +		i = thread_join (&j); +		if (i == RC_FAILURE) { +			printf ("schedtest: No threads pending, " +						"exiting schedular test\n"); +			return RC_SUCCESS; +		} +		printf ("schedtest: thread is %d returned %d\n", i, j); +		thread_yield (); +	} + +	return RC_SUCCESS; +} + +static int testthread (void *name) +{ +	int i; + +	printf ("testthread: Begin executing thread, myname %d, &i=0x%08x\n", +		*(int *) name, (unsigned)&i); + +	printf ("Thread %02d, i=%d\n", *(int *) name, i); + +	for (i = 0; i < 0xffff * (*(int *) name + 1); i++) { +		if (tstc () && getc () == 0x3) { +			printf ("testthread: myname %d terminating.\n", +						*(int *) name); +			return *(int *) name + 1; +		} + +		if (i % 100 == 0) +			thread_yield (); +	} + +	printf ("testthread: returning %d, i=0x%x\n", +				*(int *) name + 1, i); + +	return *(int *) name + 1; +} + + +static void sched_init (void) +{ +	int i; + +	for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++) +		lthreads[i].state = STATE_EMPTY; + +	current_tid = MASTER_THREAD; +	lthreads[current_tid].state = STATE_RUNNABLE; +	PDEBUG ("sched_init: master context = 0x%08x", +		(unsigned)lthreads[current_tid].context); +	return; +} + +static void thread_yield (void) +{ +	static int i; + +	PDEBUG ("thread_yield: current tid=%d", current_tid); + +#define SWITCH(new)							\ +	if(lthreads[new].state == STATE_RUNNABLE) {			\ +		PDEBUG("thread_yield: %d match, ctx=0x%08x",		\ +			new,						\ +			(unsigned)lthreads[current_tid].context);	\ +		if(setjmp(lthreads[current_tid].context) == 0) {	\ +			current_tid = new;				\ +			PDEBUG("thread_yield: tid %d returns 0",	\ +				new);					\ +			longjmp(lthreads[new].context, 1);		\ +		} else {						\ +			PDEBUG("thread_yield: tid %d returns 1",	\ +				new);					\ +			return;						\ +		}							\ +	} + +	for (i = current_tid + 1; i < MAX_THREADS; i++) { +		SWITCH (i); +	} + +	if (current_tid != 0) { +		for (i = 0; i <= current_tid; i++) { +			SWITCH (i); +		} +	} + +	PDEBUG ("thread_yield: returning from thread_yield"); +	return; +} + +static int thread_create (int (*func) (void *), void *arg) +{ +	int i; + +	for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++) { +		if (lthreads[i].state == STATE_EMPTY) { +			lthreads[i].state = STATE_STOPPED; +			lthreads[i].func = func; +			lthreads[i].arg = arg; +			PDEBUG ("thread_create: returns new tid %d", i); +			return i; +		} +	} + +	PDEBUG ("thread_create: returns failure"); +	return RC_FAILURE; +} + +static int thread_delete (int id) +{ +	if (id <= MASTER_THREAD || id > MAX_THREADS) +		return RC_FAILURE; + +	if (current_tid == id) +		return RC_FAILURE; + +	lthreads[id].state = STATE_EMPTY; +	return RC_SUCCESS; +} + +static void thread_launcher (void) +{ +	PDEBUG ("thread_launcher: invoking func=0x%08x", +		   (unsigned)lthreads[current_tid].func); + +	lthreads[current_tid].retval = +			lthreads[current_tid].func (lthreads[current_tid].arg); + +	PDEBUG ("thread_launcher: tid %d terminated", current_tid); + +	lthreads[current_tid].state = STATE_TERMINATED; +	thread_yield (); +	printf ("thread_launcher: should NEVER get here!\n"); + +	return; +} + +static int thread_start (int id) +{ +	PDEBUG ("thread_start: id=%d", id); +	if (id <= MASTER_THREAD || id > MAX_THREADS) { +		return RC_FAILURE; +	} + +	if (lthreads[id].state != STATE_STOPPED) +		return RC_FAILURE; + +	if (setjmp (lthreads[current_tid].context) == 0) { +		lthreads[id].state = STATE_RUNNABLE; +		current_tid = id; +		PDEBUG ("thread_start: to be stack=0%08x", +			(unsigned)lthreads[id].stack); +		setctxsp ((vu_char *)<hreads[id].stack[STK_SIZE]); +		thread_launcher (); +	} + +	PDEBUG ("thread_start: Thread id=%d started, parent returns", id); + +	return RC_SUCCESS; +} + +#if 0	/* not used so far */ +static int thread_stop (int id) +{ +	if (id <= MASTER_THREAD || id >= MAX_THREADS) +		return RC_FAILURE; + +	if (current_tid == id) +		return RC_FAILURE; + +	lthreads[id].state = STATE_STOPPED; +	return RC_SUCCESS; +} +#endif	/* not used so far */ + +static int thread_join (int *ret) +{ +	int i, j = 0; + +	PDEBUG ("thread_join: *ret = %d", *ret); + +	if (!(*ret == -1 || *ret > MASTER_THREAD || *ret < MAX_THREADS)) { +		PDEBUG ("thread_join: invalid tid %d", *ret); +		return RC_FAILURE; +	} + +	if (*ret == -1) { +		PDEBUG ("Checking for tid = -1"); +		while (1) { +			/* PDEBUG("thread_join: start while-loopn"); */ +			j = 0; +			for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++) { +				if (lthreads[i].state == STATE_TERMINATED) { +					*ret = lthreads[i].retval; +					lthreads[i].state = STATE_EMPTY; +					/* PDEBUG("thread_join: returning retval %d of tid %d", +					   ret, i); */ +					return RC_SUCCESS; +				} + +				if (lthreads[i].state != STATE_EMPTY) { +					PDEBUG ("thread_join: %d used slots tid %d state=%d", +						   j, i, lthreads[i].state); +					j++; +				} +			} +			if (j == 0) { +				PDEBUG ("thread_join: all slots empty!"); +				return RC_FAILURE; +			} +			/*  PDEBUG("thread_join: yielding"); */ +			thread_yield (); +			/*  PDEBUG("thread_join: back from yield"); */ +		} +	} + +	if (lthreads[*ret].state == STATE_TERMINATED) { +		i = *ret; +		*ret = lthreads[*ret].retval; +		lthreads[*ret].state = STATE_EMPTY; +		PDEBUG ("thread_join: returing %d for tid %d", *ret, i); +		return RC_SUCCESS; +	} + +	PDEBUG ("thread_join: thread %d is not terminated!", *ret); +	return RC_FAILURE; +}  |