summaryrefslogtreecommitdiffstats
path: root/stopwatch.c
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2021-03-25 13:20:15 +0100
committerMattias Andrée <maandree@kth.se>2021-03-25 13:20:15 +0100
commit71461330a7d343a5bbdd6c2c96d4652f44852030 (patch)
tree0fc86c32b17edde3599f0a86411e2da3474728a5 /stopwatch.c
downloadpdatools-71461330a7d343a5bbdd6c2c96d4652f44852030.tar.gz
pdatools-71461330a7d343a5bbdd6c2c96d4652f44852030.tar.bz2
pdatools-71461330a7d343a5bbdd6c2c96d4652f44852030.tar.xz
First commit
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to 'stopwatch.c')
-rw-r--r--stopwatch.c230
1 files changed, 230 insertions, 0 deletions
diff --git a/stopwatch.c b/stopwatch.c
new file mode 100644
index 0000000..19aba4f
--- /dev/null
+++ b/stopwatch.c
@@ -0,0 +1,230 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-2]");
+
+static volatile sig_atomic_t caught_sigterm = 0;
+static volatile sig_atomic_t caught_sigio = 0;
+static struct itimerspec orig_time;
+static int quadsize = 0;
+
+static void
+sigterm(int signo)
+{
+ caught_sigterm = 1;
+ (void) signo;
+}
+
+static void
+sigio(int signo)
+{
+ caught_sigio = 1;
+ (void) signo;
+}
+
+static int
+display_stopwatch(int timerfd)
+{
+ uint64_t overrun = 0;
+ uintmax_t total_overrun = 0, h, m, s, d, first_overrun = 0;
+ int paused = 0, have_first = 0;
+ struct itimerspec old_time, zero_time;
+ ssize_t r;
+ char c;
+
+ memset(&zero_time, 0, sizeof(zero_time));
+
+ while (!caught_sigterm) {
+ if (caught_sigio) {
+ caught_sigio = 0;
+ for (;;) {
+ r = read(STDIN_FILENO, &c, 1);
+ if (r <= 0) {
+ if (!r)
+ goto out;
+ if (errno == EAGAIN)
+ break;
+ if (errno == EINTR)
+ continue;
+ goto fail;
+ }
+ if (c == 'q') {
+ goto out;
+ } else if (c == ' ') {
+ paused ^= 1;
+ if (paused) {
+ if (timerfd_settime(timerfd, 0, &zero_time, &old_time))
+ goto fail;
+ } else {
+ if (timerfd_settime(timerfd, 0, &old_time, NULL))
+ goto fail;
+ }
+ } else if (c == '\n') {
+ if (timerfd_settime(timerfd, 0, &orig_time, NULL))
+ goto fail;
+ d = total_overrun % 10;
+ s = total_overrun / 10 % 60;
+ m = total_overrun / 10 / 60 % 60;
+ h = total_overrun / 10 / 60 / 60;
+ if (quadsize)
+ printf("\033#5");
+ printf("%ju:%02ju:%02ju.%ju", h, m, s, d);
+ if (!have_first) {
+ have_first = 1;
+ first_overrun = total_overrun;
+ } else if (total_overrun > first_overrun) {
+ total_overrun = total_overrun - first_overrun;
+ d = total_overrun % 10;
+ s = total_overrun / 10 % 60;
+ m = total_overrun / 10 / 60 % 60;
+ h = total_overrun / 10 / 60 / 60;
+ printf(" \033[31m(+%ju:%02ju:%02ju.%ju)\033[m", h, m, s, d);
+ } else if (total_overrun < first_overrun) {
+ total_overrun = first_overrun - total_overrun;
+ d = total_overrun % 10;
+ s = total_overrun / 10 % 60;
+ m = total_overrun / 10 / 60 % 60;
+ h = total_overrun / 10 / 60 / 60;
+ printf(" \033[34m(-%ju:%02ju:%02ju.%ju)\033[m", h, m, s, d);
+ }
+ printf("\033[K\n");
+ total_overrun = 0;
+ }
+ }
+ }
+
+ d = total_overrun % 10;
+ s = total_overrun / 10 % 60;
+ m = total_overrun / 10 / 60 % 60;
+ h = total_overrun / 10 / 60 / 60;
+
+ if (!paused) {
+ if (quadsize) {
+ printf("\033""7\033#3%ju:%02ju:%02ju.%ju\033[K\n", h, m, s, d);
+ printf("\033#4%ju:%02ju:%02ju.%ju\033[K\033""8", h, m, s, d);
+ } else {
+ printf("\033""7%ju:%02ju:%02ju.%ju\033[K\033""8", h, m, s, d);
+ }
+ fflush(stdout);
+ } else {
+ if (quadsize) {
+ printf("\033""7\033#3\033[33m%ju:%02ju:%02ju.%ju (paused)\033[m\033[K\n", h, m, s, d);
+ printf("\033#4\033[33m%ju:%02ju:%02ju.%ju (paused)\033[m\033[K\033""8", h, m, s, d);
+ } else {
+ printf("\033""7\033[33m%ju:%02ju:%02ju.%ju (paused)\033[m\033[K\033""8", h, m, s, d);
+ }
+ fflush(stdout);
+ pause();
+ continue;
+ }
+
+ if (read(timerfd, &overrun, sizeof(overrun)) < 0) {
+ if (errno != EINTR)
+ goto fail;
+ } else {
+ total_overrun += (uintmax_t)overrun;
+ }
+ }
+
+out:
+ return 0;
+
+fail:
+ return -1;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int timerfd = -1, old_flags = -1, tcset = 0, old_sig = 0;
+ struct sigaction sigact;
+ int64_t owner_set = 0;
+ struct f_owner_ex old_owner, new_owner;
+ struct termios stty, saved_stty;
+
+ ARGBEGIN {
+ case '2':
+ quadsize = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (argc)
+ usage();
+
+ printf("\033[?25l\033[m");
+
+ orig_time.it_interval.tv_sec = 0;
+ orig_time.it_interval.tv_nsec = 100000000L;
+ orig_time.it_value.tv_sec = 0;
+ orig_time.it_value.tv_nsec = 100000000L;
+ timerfd = timerfd_create(CLOCK_BOOTTIME, 0);
+ if (timerfd < 0)
+ goto fail;
+ if (timerfd_settime(timerfd, 0, &orig_time, NULL))
+ goto fail;
+
+ memset(&sigact, 0, sizeof(sigact));
+
+ sigact.sa_handler = sigterm;
+ sigaction(SIGTERM, &sigact, NULL);
+ sigaction(SIGQUIT, &sigact, NULL);
+ sigaction(SIGINT, &sigact, NULL);
+
+ sigact.sa_handler = sigio;
+ sigaction(SIGIO, &sigact, NULL);
+ sigaction(SIGURG, &sigact, NULL);
+
+ if (fcntl(STDIN_FILENO, F_GETOWN_EX, &old_owner))
+ goto fail;
+ memset(&new_owner, 0, sizeof(new_owner));
+ new_owner.type = F_OWNER_PID;
+ new_owner.pid = getpid();
+ if (fcntl(STDIN_FILENO, F_SETOWN_EX, &new_owner))
+ goto fail;
+ owner_set = 1;
+ old_flags = fcntl(STDIN_FILENO, F_GETFL);
+ fcntl(STDIN_FILENO, F_SETFL, old_flags | FASYNC | O_NONBLOCK);
+ fcntl(STDIN_FILENO, F_GETSIG, &old_sig);
+ if (old_sig)
+ fcntl(STDIN_FILENO, F_SETSIG, 0);
+
+ if (!tcgetattr(STDIN_FILENO, &stty)) {
+ saved_stty = stty;
+ stty.c_lflag &= (tcflag_t)~(ECHO | ICANON);
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &stty);
+ tcset = 1;
+ }
+
+ if (display_stopwatch(timerfd))
+ goto fail;
+
+ if (quadsize)
+ printf("\n\n\033#5\033[?25h");
+ else
+ printf("\033[?25h\n");
+ fflush(stdout);
+ fcntl(STDIN_FILENO, F_SETOWN_EX, &old_owner);
+ fcntl(STDIN_FILENO, F_SETFL, old_flags);
+ fcntl(STDIN_FILENO, F_SETSIG, old_sig);
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_stty);
+ close(timerfd);
+ return 0;
+
+fail:
+ printf("\033[?25h\n");
+ perror(argv0 ? argv0 : "stopwatch");
+ fflush(stdout);
+ if (owner_set)
+ fcntl(STDIN_FILENO, F_SETOWN_EX, &old_owner);
+ if (old_flags != -1)
+ fcntl(STDIN_FILENO, F_SETFL, old_flags);
+ if (old_sig)
+ fcntl(STDIN_FILENO, F_SETSIG, old_sig);
+ if (tcset)
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_stty);
+ if (timerfd >= 0)
+ close(timerfd);
+ return 1;
+}