/* * ttynvt stress tool */ #include #include #include #include #include #include #include #include #include #include #include "lib/nvt_log.h" /**INDENT-OFF**/ static const char help_text[] = "Usage: nvttest OPTIONS...\n" "OPTIONS:\n" " -D name : Specify device name (/dev/name, default /dev/ttyNVT0)\n" " -d : Enable debug\n" " -n loops : Test loops per thread\n" " -q : Quiet\n" " -r : Insert random delay in loops\n" " -t threads : N. threads\n" ; /**INDENT-ON**/ static char dev[64] = "/dev/ttyNVT0"; typedef struct { int nthread; int ithread; int nloop; bool opt_rand_delay; } topts_t; typedef struct { pthread_t thr; topts_t opts; } thr_t; static void _usage(int rc) { printf(help_text); exit(rc); } static void *_worker(void *arg) { thr_t *thr = arg; int iloop; int fd, err, nw; struct termios ios; for (iloop = 0; iloop < thr->opts.nloop; iloop++) { nvt_log(LOG_INFO, "Thread %d/%d run %d/%d\n", thr->opts.ithread, thr->opts.nthread, iloop + 1, thr->opts.nloop); { fd = open(dev, O_RDWR); if (fd < 0) { nvt_log(LOG_ERR, "Open '%s' failed: %m\n", dev); break; } memset(&ios, 0, sizeof(ios)); err = ioctl(fd, TCGETS, &ios); if (err != 0) { nvt_log(LOG_ERR, "ioctl(TCGETS) failed: %m\n"); break; } err = ioctl(fd, TCSETS, &ios); if (err != 0) { nvt_log(LOG_ERR, "ioctl(TCSETS) failed: %m\n"); break; } close(fd); } { int i, len; char buf[1024]; for (i = 0; i < (int)sizeof(buf); i++) buf[i] = '0' + i % 10; fd = open(dev, O_RDWR); if (fd < 0) { nvt_log(LOG_ERR, "Open '%s' failed: %m\n", dev); break; } for (i = 0; i < 10; i++) { len = rand() & 0xff; nw = write(fd, buf, len); if (nw < 0) { nvt_log(LOG_ERR, "write failed: %m\n"); break; } if (nw < len) { nvt_log(LOG_ERR, "write short: %u/%u\n", nw, len); break; } } close(fd); } if (thr->opts.opt_rand_delay) usleep(rand() & 0xfff); } return NULL; } int main(int argc, char **argv) { int err; int opt; int ithr, nthr; thr_t *threads, *thr; topts_t topts = { }; int debug, quiet; struct stat st; debug = quiet = 0; nthr = 1; topts.nloop = 1; while ((opt = getopt(argc, argv, "D:dn:qrt:")) != -1) { switch (opt) { default: /* '?' */ _usage(1); break; case 'D': snprintf(dev, sizeof(dev), "/dev/%s", optarg); break; case 'd': debug += 1; break; case 'n': topts.nloop = atoi(optarg); break; case 'q': quiet = 1; break; case 'r': topts.opt_rand_delay = true; break; case 't': nthr = atoi(optarg); break; } } if (stat(dev, &st) || !S_ISCHR(st.st_mode)) { fprintf(stderr, "Invalid device file: '%s'\n", dev); exit(EXIT_FAILURE); } nvt_log_level(quiet, debug); nvt_log_dest(NVT_LOG_STDOUT); topts.nthread = nthr; threads = malloc(nthr * sizeof(thr_t)); for (ithr = 0; ithr < nthr; ithr++) { nvt_log(LOG_INFO, "Create worker thread %d/%d\n", ithr + 1, nthr); thr = &threads[ithr]; thr->opts = topts; thr->opts.ithread = ithr + 1; err = pthread_create(&thr->thr, NULL, _worker, thr); if (err) { nvt_log(LOG_ERR, "Failed to create thread %d/%d\n", ithr, nthr); break; } } for (ithr = 0; ithr < nthr; ithr++) { thr = &threads[ithr]; if (thr->thr == 0) break; pthread_join(thr->thr, NULL); nvt_log(LOG_INFO, "Joined worker thread %d/%d\n", ithr + 1, nthr); } return 0; }