/*====================================================================*/ /* Chaine : tests Semaphores */ /* Programme : essem.c */ /* But : tests semaphores and multi-tasking */ /* Creation : 25/06/00 */ /* Auteur : Henri HENAULT (C) 2005 H.H. & S */ /* http://www.hhns.fr */ /*--------------------------------------------------------------------*/ /* Arguments : neant */ /*--------------------------------------------------------------------*/ /* Compile W32 : cl /MT -o semhh.exe semhh.c */ /* Compile UNIX : cl -o semhh semhh.c -lpthread */ /*--------------------------------------------------------------------*/ /* Historique */ /*--------------------------------------------------------------------*/ /* But : */ /* date : */ /* Auteur : */ /*--------------------------------------------------------------------*/ /* But : */ /* date : */ /* Auteur : */ /*====================================================================*/ #include #include #include #include "semhh.h" #define hhallc(_n) malloc(_n) #define hhfree(_a) free(_a) #define getstamp() time(NULL) #define getmstamp() clock() /*-----------------------------------------------*/ /*- A little hack for making printf re-entrant -*/ /*-----------------------------------------------*/ #if defined (_WIN32) # define mprintf(a) \ semp(mtx_stdout); \ printf##a ; \ fflush(stdout); \ semv(mtx_stdout) #else # define mprintf(a) \ semp(mtx_stdout); \ printf a ; \ fflush(stdout); \ semv(mtx_stdout) #endif /*-------------------------------------------------------------------*/ /*- global declares : variables and functions -*/ /*-------------------------------------------------------------------*/ static void fpc(void *), /* producer/consumer */ fst(void *), /* simple test */ fem(void *), /* mutex */ ftst(void); /* start/kill */ /*-------------------------------------------------------------------*/ /*- a pseudo-random function -*/ /*- returns a 'random' integer in a range g..d -*/ /*-------------------------------------------------------------------*/ static unsigned hhrand(int g, int d, unsigned r) { /* g < d */ r = r * 3141592621 + 663896637; return g + r % (d - g + 1); } /*-------------------------------------------------------------------*/ /*- static global variables for this program -*/ /*- returns a 'random' integer in a range g..d -*/ /*-------------------------------------------------------------------*/ static HHSEM s1, s2, s3; static int ctr; static char z[3*250]; static char *z1 = z, *z2 = z+250, *z3 = z+2*250; static HHSEM sz; static int prz = -1; /* common buffer index */ static HHSEM mtx_stdout; #define full s2 #define free s3 /*-------------------------------------------------------------------*/ /*- the main task -*/ /*-------------------------------------------------------------------*/ main(int argc, char ** argv) { char s[20]; char * parg; TSKID_t cid, cid1, cid2, cid3; int i, rc = getmstamp(); seminit(mtx_stdout, 1); /* init mutex=1 */ for (;;) { puts("---------------------------------"); puts(" Routines to be tested"); puts(" 1 - simple test ******"); puts(" 2 - multiple test ******"); puts(" 3 - exclusion mutuelle ******"); puts(" 4 - 1 prod + 1 cons ******"); puts(" 5 - n prod + 1 cons ******"); printf("\nSelection : "); if (! gets(s)) break; if (*s == 0x00) break; switch(atoi(s)) { case 1 : /* simple test */ /*------ A) starts the substask fst with arg = 3 ----------*/ mprintf(("%09ld : main : ********* simple test **********\n", getmstamp())); cid = strtsk(fst, "3"); /* cid, function, args, NT_priority */ mprintf(("%09ld : main : fst(3) started, cid = x%08lx\n", getmstamp(), cid)); mprintf(("%09ld : main : sleep 1 ...\n", getmstamp())); SLEEP(1); /*------ B) wait for then end of the subtask --------------*/ mprintf(("%09ld : main : wait end task x%08lx ...\n", getmstamp(), cid )); waitsk(cid, rc); mprintf(("%09ld : main : task x%08lx done, rc=%d (should be 3)\n", getmstamp(), cid, rc )); /*------ C) starts the substask fst with arg = 2 ----------*/ cid = strtsk(fst, "2"); /* cid, function, args, NT_priority */ mprintf(("%09ld : main : fst(2) started, cid = x%08lx\n", getmstamp(), cid)); mprintf(("%09ld : main : sleep 5 ...\n", getmstamp())); SLEEP(5); /*------ D) wait for then end of the subtask --------------*/ mprintf(("%09ld : main : wait end task x%08lx ...\n", getmstamp(), cid )); waitsk(cid, rc); mprintf(("%09ld : main : task x%08lx done, rc=%d (should be 2)\n", getmstamp(), cid, rc )); break; case 2 : /* multiple test */ puts(" 2 - multiple test ******"); #define NTASKS 15 /*------ A) starts NTASKS occurrences of subtask fst ------*/ rc = getstamp(); for (i = 0; i < NTASKS; ++i) { parg = hhallc(20); sprintf(parg, "%d", rc = hhrand(5, 15, rc) ); cid = strtsk(fst, parg); /* cid, function, args, NT_priority */ mprintf(("%09ld : main, strtsk #%2d, fst(%s) started, cid = x%08lx\n", getmstamp(), i, parg, cid)); } SLEEP(0); /* just for let other tasks having control of CPU */ /*------ B) wait all subtasks endeing -----*/ mprintf(("%09ld : main : waitall ...\n", getmstamp())); rc = waitall(); mprintf(("%09ld : main, waitall done, rc=%d (shoud be %d)\n", getmstamp(), rc, NTASKS )); break; case 3 : /* exclusion mutuelle */ /*--------------------------------------------------------------------------*/ /*- main child -*/ /*- init sem. s1 : 1 -*/ /*- init ctr = 10 -*/ /*- start child and sleep 10 -*/ /*- do 10 times : do 10 times -*/ /*- nap -*/ /*- semp semp -*/ /*- ++ctr --ctr -*/ /*- nap nap -*/ /*- semv semv -*/ /*- at end, ctr should be 10 -*/ /*--------------------------------------------------------------------------*/ mprintf(("%09ld : main : ********* mutual exclusion **********\n", getmstamp())); ctr = 1515; mprintf(("%09ld : main : sem s1 init to 0 and start fem ...\n", getmstamp())); /*------ A) init sem s1 and start task fem ------*/ seminit(s1,0); /* init mutex=1, starts child */ cid = strtsk(fem, NULL); mprintf(("%09ld : main : fem started, cid = x%08lx\n", getmstamp(), cid)); /*------ B) sleep 10 sec. and signal ctr free ------*/ mprintf(("%09ld : main : sleep 5 sec. ..\n", getmstamp())); SLEEP(5); mprintf(("%09ld : main : release ctr (op V on sem 'S1').\n", getmstamp())); semv(s1); /*------ C) { hold ctr, update ctr, signal ctr free } x 10 times ------*/ for (i = 0; i < 9; ++ i) { /* 10 times ----------*/ mprintf(("%09ld : main : sleep 500ms...\n", getmstamp())); NAP(500); mprintf(("%09ld : main : wait ctr free (op P on sem.'S1') ...\n", getmstamp())); semp(s1); /*---- wait for s1 */ mprintf(("%09ld : main : got it, ctr %d\n", getmstamp(), ctr)); ++ctr; /*---- update ctr */ mprintf(("%09ld : main : ++ctr -> ctr %d\n", getmstamp(), ctr)); mprintf(("%09ld : main : sleep 500ms...\n", getmstamp())); NAP(500); /*---- wait 0.5 sec */ mprintf(("%09ld : main : release ctr (op V on sem.'S1').\n", getmstamp())); semv(s1); /*---- release s1 */ } /*--------------------- 10 times ----------*/ /*------ D) waits end of task fem ------*/ mprintf(("%09ld : main : waiting end of cid x%08lx ...\n", getmstamp(), cid)); waitsk(cid, rc); mprintf(("%09ld : main : end of test, ctr %d (should be 1515)\n", getmstamp(), ctr)); break; case 4 : /* 1 prod, 1 cons */ /*--------------------------------------------------------------------------*/ /*- main child -*/ /*- init sems : full=0 free=1 sz=1 -*/ /*- init ctr = 10 -*/ /*- start child -*/ /*- do 10 times : -*/ /*- semp(full) semp(free) -*/ /*- print bf. semp(sz); fillbf; semv(sz) */ /*- nap nap -*/ /*- semv(free) semv(full) -*/ /*--------------------------------------------------------------------------*/ mprintf(("%09ld : main : ********* 1 prod - 1 cons *********\n", getmstamp())); ctr = 10; /*------ A) init sem's full, free, sz and start task fpc (the producer) ------*/ mprintf(("%09ld : main : seminit free = 1, full = 0, sz = 1\n", getmstamp())); seminit(full,0); seminit(free,1); seminit(sz, 1); cid = strtsk(fpc, NULL); /* cid, function, args, NT_priority */ mprintf(("%09ld : main : producer task started, start cid = x%08lx\n", getmstamp(), cid)); /*------ B) { wait a buffer full, print it, and signal buffer free } x 10 times -----*/ for (i = 0; i < 9; ++ i) { int nz = (i % 3); sprintf(z, "main : %d", i); mprintf(("%09ld : main : wait buffer #%d full (op P on sem.'full') ...\n", getmstamp(), nz)); semp(full); mprintf(("%09ld : main : got it : [%s]. \n", getmstamp(), z + nz*250 )); mprintf(("%09ld : main : nap 300 ms ...\n", getmstamp())); NAP(300); mprintf(("%09ld : main : signal buffer free (op V on sem. 'free').\n", getmstamp())); semv(free); } /*------ C) waits end of task fpc ------*/ mprintf(("%09ld : main : waiting end of cid x%08lx ...\n", getmstamp(), cid)); waitsk(cid, rc); mprintf(("%09ld : main : end of test\n", getmstamp())); break; case 5 : /* n prod, 1 cons */ mprintf(("%09ld : main : ********* 3 prod - 1 cons *********\n", getmstamp())); /*------ A) init sem's full, free, sz and start 3 x tasks fpc (the producers) ------*/ mprintf(("%09ld : main : seminit free = 3, full = 0, sz = 1\n", getmstamp())); seminit(full,0); seminit(free,3); seminit(sz,1); cid1 = strtsk(fpc, "10"); mprintf(("%09ld : main : subtask fpc started cid = x%08lx\n", getmstamp(), cid1)); cid2 = strtsk(fpc, "20"); mprintf(("%09ld : main : subtask fpc started cid = x%08lx\n", getmstamp(), cid2)); cid3 = strtsk(fpc, "30"); mprintf(("%09ld : main : subtask fpc started cid = x%08lx\n", getmstamp(), cid3)); /*------ B) { wait a buffer full, print it, and signal buffer free } x 27 times -----*/ for (i = 0; i < 27; ++ i) { int coz = i % 3; mprintf(("%09ld : main : wait buffer #%d full (op P on sem 'full')...\n", getmstamp(), coz )); semp(full); mprintf(("%09ld : main : got it, z=[%s].\n", getmstamp(), z+coz*250)); mprintf(("%09ld : main : signals buffer free (op V on sem.'free').\n", getmstamp())); semv(free); } /*------ C) waits end of 3 * tasks fpc ------*/ mprintf(("%09ld : main : waiting end of each cid's ...\n", getmstamp() )); for (i=0; i < 3; ++i) { TSKID_t wcid; mprintf(("%09ld : main : waitany #%d ...\n", getmstamp(), i )); wcid = waitany(rc); mprintf(("%09ld : main : waitany #%d -> cid x%08lx, rc %d\n", getmstamp(), i, wcid, rc )); } mprintf(("%09ld : main : end of test\n", getmstamp() )); break; } /* switch */ } /* for ever */ } /* main */ /*------------------------------------------------------------------*/ /*- fst : sipmle test -*/ /*- arg : any string -*/ /*- process : sleep 3 and return -*/ /*------------------------------------------------------------------*/ static void fst(void * a) { int rc = atoi(a); TSKID_t cid = tskid(); mprintf(("%09ld child cid x%08lx: starts, delai %s...\n", getmstamp(), cid, a)); mprintf(("%09ld child cid x%08lx: sleep %d ...\n", getmstamp(), cid, rc)); SLEEP(rc); mprintf(("%09ld child cid x%08lx: exitTask rc=%d ...\n", getmstamp(), cid, rc)); exitsk(rc); } /*------------------------------------------------------------------*/ /*- fem : mutual exclusion -*/ /*- arg : dummy pointer (unused) -*/ /*- process : { get excl.ctrl, update ctr, release ctrl} x 10 times-*/ /*------------------------------------------------------------------*/ static void fem(void * a) { static int rc = 0; int i; mprintf(("%09ld : child : starting, Sleep 5 sec....\n", getmstamp() )); SLEEP(5); for (i = 0; i < 9; ++ i) { mprintf(("%09ld : child : wait ctr free (op P on sem 'S1') ...\n", getmstamp())); semp(s1); /* P operation : get ctr exclusive with s1 */ mprintf(("%09ld : child : got it, ctr %d\n", getmstamp(), ctr)); --ctr; /* update ctr */ mprintf(("%09ld : child : --ctr ->ctr %d, sleep 600 ms ...\n", getmstamp(), ctr)); NAP(600); /* wait 0.6 sec. */ mprintf(("%09ld : child : release ctr (op V on sem.'S1').\n", getmstamp())); semv(s1); /* V operation : release ctr with s1 */ } exitsk(rc); } /*------------------------------------------------------------------*/ /*- fpc : producer - consumer / producer part -*/ /*- arg : # of elements to be processed -*/ /*- process : { get excl.ctrl, update ctr, release ctrl} x 10 times-*/ /*------------------------------------------------------------------*/ static void fpc(void * a) { int n = a == NULL ? 10 : atoi(a); int rc = n; int i; int nz; mprintf(("%09ld : child %d: starting.\n", getmstamp(), n)); for (i = n; i < n+9; ++ i) { mprintf(("%09ld : child %d: wait buffer free (op P on sem 'free') ...\n", getmstamp(), n)); semp(free); /* wait for a buffer: z[prz+1] will be empty */ mprintf(("%09ld : child %d: got it\n", getmstamp(), n, z)); mprintf(("%09ld : child %d: wait buf.index free (op P on sem.'sz') ...\n", getmstamp(), n)); semp(sz); /* wait prz free */ mprintf(("%09ld : child %d: got it\n", getmstamp(), n)); nz = ++prz; /* bump next buffer index */ mprintf(("%09ld : child %d: release buf.index (op V on sem.'sz')\n", getmstamp(), n)); semv(sz); /* release prz, fill the buffer */ nz %= 3; /* nz = 0, 1, 2 */ sprintf(z + 250*nz, "child %d : buf %d, msg %d", n, nz, i); mprintf(("%09ld : child %d: fill the buffer #%d, and nap %d ms.\n", getmstamp(), n, nz, 100+5*n)); NAP(100+5*n); mprintf(("%09ld : child %d: signal buffer full (op V on sem.'full')\n", getmstamp(), n)); semv(full); /* says that a buffer is ready */ } mprintf(("%09ld : child %d: ending, rc %d\n", getmstamp(), n, rc)); exitsk(rc); } static void ftst() { while (1) { mprintf(("%09ld : child ftst : alive, sleep 1/2 sec.\n", getmstamp() )); NAP(500); } }