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