#include #include #include #include #include #include #include #include #include #include #include #include void *runner(void *); void *status(void *); void error_set(int, int); int error_check(void); void state_set(int, int); time_t tv_sub(struct timeval *, struct timeval *); static pthread_mutex_t mutex_errored = PTHREAD_MUTEX_INITIALIZER; static int errored = 0; static pthread_mutex_t mutex_status = PTHREAD_MUTEX_INITIALIZER; static struct timeval *laststatechange; static int *state; typedef enum { ATTR_NONE = 0x00, ATTR_BOLD = 0x01, ATTR_INVERSE = 0x02, ATTR_RED = 0x10, ATTR_GREEN = 0x20, ATTR_BLUE = 0x40, ATTR_COLORS = ATTR_RED|ATTR_GREEN|ATTR_BLUE, ATTR_DEFAULT = ATTR_NONE|ATTR_RED|ATTR_GREEN|ATTR_BLUE } textattr_t; int nthreads = 2; int main(int argc, char *argv[]) { pthread_t *threads = NULL, statthread; pthread_attr_t attr; int x, res, opt; struct timeval now; while ((opt = getopt(argc, argv, "n:h")) != -1) { switch (opt) { case 'n': nthreads = atoi(optarg); break; case 'h': default: printf("usage: %s [-n #|-h]\n", argv[0]); printf("\t-n: number of threads (default: 2)\n"); printf("\t-h: help\n"); return (opt != 'h'); } } if ((threads = calloc(nthreads, sizeof(pthread_t))) == NULL) { printf("Unable to allocate thread structures\n"); return 1; } if ((laststatechange = malloc(nthreads * sizeof(struct timeval))) == NULL) { printf("Unable to allocate thread time info\n"); free(threads); return 1; } if ((state = malloc(nthreads * sizeof(int))) == NULL) { printf("Unable to allocate thread status\n"); free(laststatechange); free(threads); return 1; } pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + 8192 + 16384); printf("\e[2J\e[1;1H\e[0mCreating threads...\n"); if (pthread_create(&statthread, &attr, status, NULL) < 0) { perror("pthread_create"); free(laststatechange); free(threads); free(state); return 1; } gettimeofday(&now, NULL); for (x = 0; x < nthreads; x++) { memcpy(&laststatechange[x], &now, sizeof(&laststatechange[0])); state[x] = 'i'; } for (x = 0; x < nthreads; x++) { if (pthread_create(threads + x, &attr, runner, (void *)x) < 0) break; } printf("\e[1;1HCreated %d threads.\n", x); for (x = 0; x < nthreads; x++) { if (pthread_join(*(threads + x), (void *)&res) < 0) perror("pthread_join"); } if (pthread_join(statthread, NULL) < 0) perror("pthread_join"); free(laststatechange); free(threads); free(state); return 0; } void *runner(void *numv) { char file[1024]; #if 1 char uninit[16384]; #endif int fd, num = (int)numv; snprintf(file, sizeof(file), "stressrm.tmp.%08x", num); // fprintf(stderr, "[thread#%04d] Starting, file '%s'\n", num, file); unlink(file); for (;;) { if (error_check()) break; state_set(num, 'c'); if ((fd = open(file, O_CREAT|O_WRONLY|O_EXCL, 0666)) < 0) { error_set(num, 1); fprintf(stderr, "[thread#%04d] open(\"%s\", ...): %s\n", num, file, strerror(errno)); return (void *)1; } #if 1 if (error_check()) break; state_set(num, 'w'); if (write(fd, uninit, sizeof(uninit)) < sizeof(uninit)) { error_set(num, 4); fprintf(stderr, "[thread#%04d] write(%d (\"%s\"), ...): %s\n", num, fd, file, strerror(errno)); return (void *)4; } #endif if (error_check()) break; state_set(num, 'x'); if (close(fd) < 0) { error_set(num, 2); fprintf(stderr, "[thread#%04d] close(%d (\"%s\"), ...): %s\n", num, fd, file, strerror(errno)); return (void *)2; } if (error_check()) break; state_set(num, 'u'); if (unlink(file) < 0) { error_set(num, 3); fprintf(stderr, "[thread#%04d] unlink(\"%s\"): %s\n", num, file, strerror(errno)); return (void *)3; } state_set(num, 'l'); } return (void *)0; } int error_check(void) { int err; pthread_mutex_lock(&mutex_errored); err = errored; pthread_mutex_unlock(&mutex_errored); return err; } void error_set(int num, int err) { pthread_mutex_lock(&mutex_errored); // printf("thread %d: error set = %d\n", num, err); /* hack */ printf("\e[0m"); errored = err; pthread_mutex_unlock(&mutex_errored); state_set(num, '0' + err); } void state_set(int th, int newstate) { pthread_mutex_lock(&mutex_status); gettimeofday(laststatechange + th, NULL); *(state + th) = newstate; pthread_mutex_unlock(&mutex_status); } void *status(void *unused) { struct timeval curtime; time_t age; int x, col; textattr_t want, last = ATTR_NONE; for (;;) { pthread_mutex_lock(&mutex_status); gettimeofday(&curtime, NULL); printf("\e[2;1H"); col = 0; for (x = 0; x < nthreads; x++) { age = tv_sub(&curtime, laststatechange + x); if (age > 60000000) { pthread_mutex_unlock(&mutex_status); error_set(x, 5); } /* && ((curtime.tv_usec / 500000) & 1)*/ want = 0; if (age > 2000000) { if (age > 10000000) want = ATTR_DEFAULT|ATTR_INVERSE; else if (age > 5000000) want = ATTR_RED|ATTR_BOLD; else want = ATTR_DEFAULT|ATTR_BOLD; } else want = ATTR_DEFAULT; if ((want & ~ATTR_COLORS) != (last & ~ATTR_COLORS)) { printf("\e[0m"); last = 0; } if ((want & ATTR_INVERSE) && !(last & ATTR_INVERSE)) printf("\e[7m"); if ((want & ATTR_BOLD) && !(last & ATTR_BOLD)) printf("\e[1m"); if ((want & ATTR_COLORS) != (last & ATTR_COLORS)) printf("\e[3%dm", (want & ATTR_COLORS) >> 4); last = want; printf("%c", *(state + x)); col++; if (col >= 70) { printf("\n"); col = 0; } } pthread_mutex_unlock(&mutex_status); if (col != 0) printf("\n"); fflush(stdout); usleep(1000000L / 50); if (error_check()) break; } return NULL; } time_t tv_sub(struct timeval *after, struct timeval *before) { return ((after->tv_sec - before->tv_sec) * 1000000) + (after->tv_usec - before->tv_usec); }