#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 char *testdir = "/tmp/test3a"; static int reader (int i); static int deleter (int i); static int creator (int i); typedef int (*callfunc_t)(int); #define NR_PROCS 5 pid_t pids[NR_PROCS]; callfunc_t dofunc[NR_PROCS] = { deleter, creator, reader, reader, reader }; int priorities[NR_PROCS] = { 9, 10, 11, 12, 13, }; key_t semkey; key_t shmkey; int semid = -1; int shmid = -1; int safe = 0; int *flags; static void remove_testdir(void); 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); remove_testdir(); #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; struct sembuf sops; int semid; memset(&sops,0,sizeof(sops)); if ((semid = semget(semkey,1,0)) < 0) { perror("semget"); return; } 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; struct timespec ts = {0,250000000UL}; time_t t; char timebuf[30]; unsigned long long starttsc, nowtsc; memset(&sops,0,sizeof(sops)); if ((semid = semget(semkey,1,0)) < 0) { perror("semget"); return -1; } 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); printf("reader %d grabbing waiting on sem\n",i); printf("(id=%d) start time is %ld.%06ld\n",i,starttv.tv_sec,starttv.tv_usec); if (semop(semid, &sops, 1) < 0) { perror("semop"); return -1; } logdev_print(logfd,"reader %d past semaphore\n",i); 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("/tmp"); 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)) { nanosleep(&ts,NULL); read_dirs("/tmp"); if (list_empty(&dirs)) /* ?? */ break; } p = dirs.next; list_del(p); item = list_entry(p,struct dir_item, list); printf("%d: reading dir %s\n",i,item->dir); 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(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); printf(" (id=%d) end time is %ld.%06ld\n",i,tv.tv_sec,tv.tv_usec); printf(" (id=%d) end time should be %ld.%06ld\n",i,endtv.tv_sec,endtv.tv_usec); /* * When the readers are done, stop the others that don't * have any other test to stop with. No locks needed, we * all just set it to one. */ *flags = 1; return 0; } void delete_all(char *dirname) { DIR *dir; struct dirent *dent; int len = strlen(dirname); char *name; struct sembuf sops; int semid; memset(&sops,0,sizeof(sops)); if ((semid = semget(semkey,1,0)) < 0) { perror("semget"); return; } 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); unlink(name); free(name); } out: closedir(dir); } static int deleter(int i) { struct sembuf sops; int semid; memset(&sops,0,sizeof(sops)); if ((semid = semget(semkey,1,0)) < 0) { perror("semget"); return -1; } printf("deleter %d grabbing waiting on sem\n",i); if (semop(semid, &sops, 1) < 0) { perror("semop"); return -1; } logdev_print(logfd,"deleter %d past semaphore\n",i); while (!*flags) { delete_all(testdir); } return 0; } static int creator(int i) { struct sembuf sops; int semid; int x; char name[100]; memset(&sops,0,sizeof(sops)); if ((semid = semget(semkey,1,0)) < 0) { perror("semget"); return -1; } mkdir(testdir,0777); printf("creator %d grabbing waiting on sem\n",i); if (semop(semid, &sops, 1) < 0) { perror("semop"); return -1; } logdev_print(logfd,"creator %d past semaphore\n",i); while (!*flags) { int fd; char *garbage = "garbage\n"; snprintf(name,100,"%s/dummy%d",testdir,x++); if ((fd = open(name,O_CREAT|O_WRONLY,0777)) < 0) { perror(name); continue; } write(fd,garbage,strlen(garbage)); close(fd); } return 0; } static void remove_testdir(void) { delete_all(testdir); rmdir(testdir); } void usage(char **argv) { char *arg = argv[0]; char *p = arg+strlen(arg); while (p >= arg && *p != '/') p--; p++; printf("\nusage: %s [-sn]\n" " -s : safe mode. Have the readers use the tsc to stop\n" " -n : run without RT\n" "\n",p); exit(-1); } int main (int argc, char **argv) { int ret=0; int i; int nr_procs=0; int noprio = 0; struct sembuf sops; int c; opterr = 0; while ((c=getopt(argc,argv,"hsn")) >= 0) { switch (c) { case 's': safe = 1; break; case 'n': noprio = 1; break; case 'h': default: printf("\n"); if (c != ':' && tolower(optopt) != 'h' && optopt != '?') printf("unknown option: %c\n",optopt); usage(argv); } } semkey = ftok(argv[0],123); shmkey = ftok(argv[0],456); if ((semid = semget(semkey,1,IPC_CREAT|IPC_EXCL|0600)) < 0) { perror("semget"); exit (-1); } if ((shmid = shmget(shmkey,30,IPC_CREAT|IPC_EXCL|0600)) < 0) { perror("shmget"); goto out; } if ((flags = shmat(shmid, NULL, 0)) == (void*)-1) { perror("shmat"); goto out; } *flags = 0; #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++; if (!noprio && priorities[i]) { 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); }