#if 0 +-----------------------------------------------------------------------------+ | Program: doall Jace A Mogill | | Release: 2.0 ROTANG UnderWare | | Date: $Date: 2004/01/24 03:43:09 $ http://www.rotang.com/ | | Revision: $Revision: 1.1.1.1 $ Email: mogill@rotang.com | | Copyright 1999-2000 ROTANG -- ZOOM! NOT BOOM! | +-----------------------------------------------------------------------------+ | This program is *NOT* yours to use! This code is made publicly available | | for educational and research purposes only. It, and software derived from | | it, are not to be included in or supplied with your program if your program | | has any use other than its intended research or education. This entire | | banner must accompany any use or derivation of this code. Any non-research | | or non-educational uses of this code must be licensed by the author. | +-----------------------------------------------------------------------------+ #endif #if 0 BUILDING doall ----------------------------------------------------------------- Linux: cc doall.c -o doall -lpthread Solaris: cc doall.c -o doall -lposix4 -lpthread #endif #include #include #include #include #if !defined(TRUE) # define TRUE 1 #endif #if !defined(FALSE) # define FALSE 0 #endif #define SLEEP(_sec_, _usec_) \ { \ struct timespec sleep_time; \ \ sleep_time.tv_sec = _sec_; \ sleep_time.tv_nsec = _usec_ * 1000; \ nanosleep(&sleep_time, NULL); \ } typedef struct { pthread_t thread;/* Thread of each parallel task */ pthread_mutex_t lock; /* Barrier lock for each task */ int busy; /* Semaphore indicates busy state of task */ int iter; /* Iteration number task is now working on */ } task_ts; task_ts *tasks; /* Control structures for all the tasks */ void body( void *my_id_arg ); void driver( int niterations, /* Number of iterations to perform */ int ntasks ); /* Number of tasks to use */ /*==========================================================================*/ /* * Program entry point */ void main( int argc, char *argv[]) { int i; /* Index across iterations */ int ntasks; /* Number of tasks to use */ int niterations; /* Number of iterations of the loop to perform */ if(argc != 3) { fprintf(stderr, "Usage: %s \n", argv[0]); exit(1); } ntasks = atoi(argv[1]); if(ntasks == 0) { fprintf(stderr, "%s: Number of tasks (%s) illegal. Must 1 or more.\n", argv[0], argv[1]); exit(1); } niterations = atoi(argv[2]); if(niterations == 0) { fprintf(stderr, "%s: Number of iterations (%s) illegal. Must 1 or more.\n", argv[0], argv[2]); exit(1); } if(ntasks > niterations) { fprintf(stderr, "%s: Clamping number of tasks (%d) to number of iterations (%d).\n", argv[0], ntasks, niterations); ntasks = niterations; } /*===========================================================*/ tasks = (task_ts *) malloc(sizeof(task_ts) * ntasks); if(tasks == NULL) { fprintf(stderr, "%s: Failure allocating %d task_ts's (size=%d) for tasks.\n", argv[0], ntasks, sizeof(task_ts)); exit(1); } for(i = 0; i < ntasks; i++) { tasks[i].busy = FALSE; pthread_mutex_init( &(tasks[i].lock), NULL ); if( pthread_mutex_lock( &(tasks[i].lock) ) ) fprintf(stderr, "main: Unable to initally lock task %d", i); if( pthread_create( &(tasks[i].thread), /* Handle of thread */ NULL, /* Scheduling attributes (NULL == default) */ (void *(*)(void*)) body, /* Function to invoke as thread */ (void*) i /* Argument to thread */ ) != 0) fprintf(stderr, "main: Couldn't create thread for task (%d)\n", i); } driver( niterations, ntasks ); #if !defined(JOIN_THREADS) /* If the threads exit, we cannot run the experiment * again without restarting all the task threads. */ fprintf(stderr, "And again!\n"); driver( niterations, ntasks / 2 ); fprintf(stderr, "All done!\n"); #endif } /* * Perform the body of the loop */ void body( void *my_id_arg ) { int my_id = (int) my_id_arg; /* Thread ID number */ void *retval = (void*) 0; /* Return value of task */ while(TRUE) { if( pthread_mutex_lock( &(tasks[my_id].lock) ) ) fprintf(stderr, "body: Unable to block loop body for task %d", my_id); #if defined(JOIN_THREADS) /* If the threads are to exit when they are no longer needed, * they are signaled with an impossible iteration number (-1). */ if(tasks[my_id].iter == -1) pthread_exit(retval); #endif fprintf(stderr, "body: iteration #%d performed by task %d\n", tasks[my_id].iter, my_id); SLEEP(0, my_id * 10000); /* Simulates variable load per task */ tasks[my_id].busy = FALSE; } } void driver( int niterations, /* Number of iterations to perform */ int ntasks ) /* Number of tasks to use */ { int i; /* Index over iterations */ int taskn; /* Index into tasks */ fprintf(stderr, "driver: niter=%d ntasks=%d\n", niterations, ntasks); /* * Loop over all iterations */ for(i = 0; i < niterations; i++) { int tasks_avail; /* Flag indicates a task is available for work */ int taskn; /* Index into tasks */ tasks_avail = FALSE; do { taskn = 0; while( taskn < ntasks && tasks[taskn].busy ) taskn++; if(taskn >= ntasks) SLEEP(0, 10000) /* Magic retry interval */ else tasks_avail = TRUE; } while( !tasks_avail ); tasks[taskn].busy = TRUE; tasks[taskn].iter = i; if( pthread_mutex_unlock( &(tasks[taskn].lock) ) ) fprintf(stderr, "driver: Unable to release task %d", taskn); } #if defined(JOIN_THREADS) /* * Join all the threads as they exit. */ for( taskn = 0; taskn < ntasks; taskn++ ) { void *return_status; /* Status of task upon exit */ tasks[taskn].iter = -1; /* Iteration -1 interpreted as exit */ if( pthread_mutex_unlock( &(tasks[taskn].lock) ) ) fprintf(stderr, "driver: Unable to release task %d to join it", taskn); pthread_join( tasks[taskn].thread, &return_status ); fprintf(stderr, "Task %d finished with status %d\n", taskn, (int) return_status); } #else /* * We've started all the iterations, but we need to block at * the end untill they're all done. */ for(taskn = 0; taskn < ntasks; taskn++) while( tasks[taskn].busy ) SLEEP(0, 100000); /* Magic retry interval */ #endif }