/* threadHelper.c * * 7/23/2000 Sarah Anderson, LCSE * * OS independent implementation of useful multithreading routines * including C and Fortran bindings. * * Fortran binding: * * T_INIT( int *node, int *stacksize, int *status ) * Initialize structures * T_CREATE( int *ithread, void *f_routine, int *istatus ) * Spawn thread at f_routine. *ithread counts 1.. and is the number passed * to f_routine(ithread) * T_LOCK() * Obtain simple lock * T_UNLOCK() * Release simple lock * T_WAIT() * Simple OS semaphore * T_RELEASE() * Release thread(s) waiting on T_WAIT * T_ID( int *ithread, int *istatus ) * Partial implementation! * FBARRIER( int *num_threads, int *status ) * Spinning barrier * IFETCHADD( long *v, int *lock_number ) * Atomic increment of v (lock_number ignored) * ABARRIER( unsigned *num ) * Semaphore based barrier routine * LOOOPEND( volatile int *ivar ) * spins while *ivar != 0 * IWAITER( volatile int *ivar ) * wpins while *ivar == 0 */ #include #include #include // assert turned off by defining NDEBUG #include #include #define MXTHREADS 33 /* Maximum no. compute threads */ #define MXFADDLOCKS 65 #define debug 0 #include "threadhelper.h" #ifdef _WIN32 /* For Digital/Compaq fortran: add __stdcall */ #define T_INIT T_INIT #define T_CREATE T_CREATE #define T_ID T_ID #define SEM_DELETE SEM_DELETE #define FBARRIER FBARRIER #define ABARRIER ABARRIER #define IFETCHADD IFETCHADD #define IWAITER IWAITER #define LOOPEND LOOPEND #define T_RELEASE T_RELEASE #define T_WAIT T_WAIT #endif /***************************************************************** * global data, all mutexes created with default attributes are fast * ones, i.e. can be locked only once before being unlocked *****************************************************************/ #define NSEM 9 /* one semaphore for ABARRIER, remainder for WAIT/RELEASE */ #define NCRIT 8 /* critical sections LOCK/UNLOCK */ static unsigned long threads [ MXTHREADS ]; /* array of thread handles */ static HANDLE Semid[NSEM]; static CRITICAL_SECTION Critid[NCRIT]; static int Nthreads=0; /* Number of spawned threads */ static unsigned int Stacksize= 0; //static CRITICAL_SECTION Csection; /***************************************************************** * global data, all mutexes created with default attributes are fast * ones, i.e. can be locked only once before being unlocked *****************************************************************/ long t_init( int node, unsigned int stacksize ) { int i; char name[80]; Stacksize = stacksize; /* fprintf(stdout,"init set stacksize to %d\n", Stacksize ); */ /* It seems NT is requiring me to name these */ for(i=0; i=0 && *n=0 && n=0 && *n=0 && n 0 && *n < NSEM ); WaitForSingleObject( Semid[*n], (DWORD)INFINITE ); } void t_wait( int n ) { assert( n>0 && n < NSEM ); WaitForSingleObject( Semid[n], (DWORD)INFINITE ); } /* **************************************************************** * Release threads * ***************************************************************/ void T_RELEASE( int *n ) { assert( *n > 0 && *n < NSEM ); ReleaseSemaphore( Semid[*n], 1, NULL ); } void t_release( int n ) { assert( n>0 && n < NSEM ); ReleaseSemaphore( Semid[n], 1, NULL ); } /***************************************************************** *Twiddle (spin) until ivar changes. volatile insures ivar fetched *from memory for every while check *****************************************************************/ void LOOPEND( volatile int *ivar ) { while(*ivar!=0); /* spin */ } void IWAITER( volatile int *ivar ) { while(*ivar==0); /* spin */ }