#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define __USE_GNU #include #ifdef SDR_TOOLS #include #include #include #include #include "dump_trace.h" int logfd = -1; #else #define logdev_print(x...) do {} while(0) #define logdev_switch_set(x) (0) #endif #include static int reader (int i); typedef int (*callfunc_t)(int); #define NR_PROCS 5 pid_t pids[NR_PROCS]; callfunc_t dofunc[NR_PROCS] = { reader, reader, reader, reader, reader }; int priorities[NR_PROCS] = { 10, 11, 12, 13, 14, }; key_t key; int semid = -1; int shmid = -1; int safe = 0; int tod = 0; int *flags; void cleanup(void) { int i; for (i=0; i < NR_PROCS; i++) { if (pids[i]) kill(pids[i],SIGKILL); } if (semid >= 0) semctl(semid, 0, IPC_RMID); if (shmid >= 0) shmctl(shmid, IPC_RMID, NULL); #ifdef SDR_TOOLS if (logfd >= 0) close_logdev(logfd); #endif } void catchall(int sig) { cleanup(); psignal(sig,"Caught: "); exit(-1); } static int compare_timeval(const struct timeval *a, const struct timeval *b) { return (a->tv_sec > b->tv_sec) ? 1 : (a->tv_sec < b->tv_sec) ? -1: (a->tv_usec > b->tv_usec) ? 1: (a->tv_usec < b->tv_usec) ? -1: 0; } static void add_timeval(const struct timeval *a, const struct timeval *b, struct timeval *c) { c->tv_usec = a->tv_usec + b->tv_usec; c->tv_sec = a->tv_sec + b->tv_sec; while (c->tv_usec > 1000000) { c->tv_usec -= 1000000; c->tv_sec++; } } static void sub_timeval(const struct timeval *a, const struct timeval *b, struct timeval *c) { c->tv_usec = a->tv_usec - b->tv_usec; c->tv_sec = a->tv_sec - b->tv_sec; while (c->tv_usec < 0) { c->tv_usec += 1000000; c->tv_sec--; } } struct dir_item { struct list_head list; char *dir; }; LIST_HEAD_DECLARE(dirs); static void read_dirs(char *dirname) { DIR *dir; struct dirent *dent; struct stat st; struct dir_item *item; int len = strlen(dirname); char *name; if ((dir = opendir(dirname)) == NULL) return; while ((dent = readdir(dir))) { if (strcmp(dent->d_name,".") == 0 || strcmp(dent->d_name,"..") == 0) continue; name = malloc(strlen(dent->d_name)+len+2); if (!name) { goto out; } strcpy(name,dirname); name[len] = '/'; strcpy(name+len+1,dent->d_name); if (stat(name,&st) < 0) { perror(name); free(name); continue; } if ((S_ISDIR(st.st_mode))) { item = malloc(sizeof(*item)); if (!item) { free(name); goto out; } item->dir = name; list_add_tail(&item->list,&dirs); } else { free(name); } } out: closedir(dir); } static int reader(int i) { struct sembuf sops; int semid; struct timeval starttv; struct timeval endtv; struct timeval tv; struct timeval lasttv; struct timeval deltatv; time_t t; char timebuf[30]; unsigned long long starttsc, nowtsc; memset(&sops,0,sizeof(sops)); if ((semid = semget(key,1,0)) < 0) { perror("semget"); return -1; } printf("reader %d grabbing waiting on sem\n",i); if (semop(semid, &sops, 1) < 0) { perror("semop"); return -1; } logdev_print(logfd,"reader %d past semaphore\n",i); if (gettimeofday(&starttv,NULL) < 0) { perror("gettimeofday"); return -1; } memset (&deltatv,0,sizeof(deltatv)); endtv.tv_sec = 10; endtv.tv_usec = 0; add_timeval(&starttv,&endtv,&endtv); t = time(NULL); ctime_r(&t,timebuf); timebuf[strlen(timebuf)-1] = 0; printf("reader %d starting loop (%s)\n",i,timebuf); logdev_print(logfd,"reader %d (pid %d) starting loop (%s)\n",i,getpid(),timebuf); lasttv = starttv; asm ("rdtsc" : "=A"(starttsc)); chdir("/"); read_dirs("/"); do { struct list_head *p; struct dir_item *item; asm ("rdtsc" : "=A"(nowtsc)); if (safe && (nowtsc - starttsc > 8000000000ULL)) { printf("now - start > 8000000000\n"); break; } if (list_empty(&dirs)) break; p = dirs.next; list_del(p); item = list_entry(p,struct dir_item, list); read_dirs(item->dir); free(item->dir); free(item); if (gettimeofday(&tv,NULL) < 0) { perror("gettimeofday (in loop)"); return -1; } sub_timeval(&tv,&lasttv,&lasttv); if (compare_timeval(&deltatv,&lasttv) < 0) deltatv = lasttv; lasttv = tv; } while(!tod || compare_timeval(&endtv,&tv) > 0); t = time(NULL); ctime_r(&t,timebuf); timebuf[strlen(timebuf)-1] = 0; logdev_print(logfd,"spinner %d (pid %d) done (%s)\n",i,getpid(),timebuf); printf("spinner %d ended loop (%s) (%d.%06d secs delta)\n", i,timebuf,(int)deltatv.tv_sec,(int)deltatv.tv_usec); return 0; } void usage(char **argv) { char *arg = argv[0]; char *p = arg+strlen(arg); while (p >= arg && *p != '/') p--; p++; printf("\nusage: %s [-st]\n" " -s : safe mode. Have the readers use the tsc to stop\n" " -t : use timeofday to stop loop\n" "\n",p); exit(-1); } int main (int argc, char **argv) { int ret=0; int i; int nr_procs=0; struct sembuf sops; int c; opterr = 0; while ((c=getopt(argc,argv,"hnsf:")) >= 0) { switch (c) { case 's': safe = 1; break; case 't': tod = 1; break; case 'h': default: printf("\n"); if (c != ':' && tolower(optopt) != 'h' && optopt != '?') printf("unknown option: %c\n",optopt); usage(argv); } } key = ftok(argv[0],123); if ((semid = semget(key,1,IPC_CREAT|IPC_EXCL|0600)) < 0) { perror("semget"); exit (-1); } if ((shmid = shmget(key,30,IPC_CREAT|IPC_EXCL|0600)) < 0) { perror("shmget"); goto out; } if ((flags = shmat(shmid, NULL, 0)) == (void*)-1) { perror("shmat"); goto out; } #ifdef SDR_TOOLS if ((logfd = open_logdev(NULL,O_RDWR)) < 0) { perror("open_logdev"); goto out; } if (logdev_switch_set(1)) { perror("logdev_switch_on"); } #endif /* Grab the semaphore before anyone else can take it. */ memset(&sops,0,sizeof(sops)); // sops.sem_flg = SEM_UNDO; sops.sem_op = 1; if (semop(semid, &sops, 1) < 0) { perror("semop"); ret = -1; goto out; } for (i=0; i < NR_PROCS; i++) { struct sched_param p; if ((pids[i] = fork()) < 0) { perror("fork"); ret = -1; goto out; } else if (pids[i] == 0) { /* child */ ret = dofunc[i](i); exit(ret); } nr_procs++; p.sched_priority = priorities[i]; if (sched_setscheduler(pids[i],SCHED_FIFO,&p)) { perror("sched_setscheduler"); goto out; } /* parent */ } signal(SIGINT,catchall); signal(SIGILL,catchall); signal(SIGFPE,catchall); signal(SIGSEGV,catchall); signal(SIGBUS,catchall); sleep(1); printf("parent zeroing semaphore\n"); sops.sem_op = -1; if (semop(semid,&sops,1) < 0) { perror("semop"); ret = -1; goto out; } while (nr_procs) { int status; pid_t pid; if ((pid = wait(&status)) < 0) { perror("wait"); break; } for (i=0; i < NR_PROCS; i++) { if (pids[i] == pid) { pids[i] = 0; nr_procs--; } } } if (logdev_switch_set(0)) { perror("logdev_switch_off"); } out: cleanup(); exit(ret); }