From 3e0ce64b76f34a1e9cc0799ce31aa2420671b06c Mon Sep 17 00:00:00 2001 From: nick black Date: Thu, 21 Oct 2021 14:50:05 -0400 Subject: [PATCH] [input] try to use CLOCK_MONOTONIC for condvar By default, Pthread condition variables use the wretched CLOCK_REALTIME for pthread_cond_timedwait(). We reaaaaaaly want it to use CLOCK_MONOTONIC instead. Where supported, use pthread_condvar_setclock() to initialize the input condvar with CLOCK_MONOTONIC, since every other operation we perform is clocked against it. Closes #2291. --- src/lib/in.c | 96 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 37 deletions(-) diff --git a/src/lib/in.c b/src/lib/in.c index c0b2696f5..7dc13eda9 100644 --- a/src/lib/in.c +++ b/src/lib/in.c @@ -1385,6 +1385,24 @@ getpipes(ipipe pipes[static 2]){ return 0; } +// attempt to set up a pthread_condattr_t such that pthread_cond_timedwait() +// uses CLOCK_MONOTONIC rather than CLOCK_REALTIME. unfortunately, this isn't +// available on all operating systems. return success so long as we can +// initialize the condattr_t; it does not imply successful clock selection =\. +static int +prep_condattr(pthread_condattr_t* cattr){ + int e; + if( (e = pthread_condattr_init(cattr)) ){ + logerror("couldn't initialize condattr (%s)\n", strerror(e)); + return -1; + } + // remember, return success even if this doesn't fly + if( (e = pthread_condattr_setclock(cattr, CLOCK_MONOTONIC)) ){ + logwarn("warning: couldn't set CLOCK_MONOTONIC for condvar (%s)\n", strerror(e)); + } + return 0; +} + static inline inputctx* create_inputctx(tinfo* ti, FILE* infp, int lmargin, int tmargin, int rmargin, int bmargin, ncsharedstats* stats, unsigned drain, @@ -1396,52 +1414,56 @@ create_inputctx(tinfo* ti, FILE* infp, int lmargin, int tmargin, int rmargin, i->isize = BUFSIZ; if( (i->inputs = malloc(sizeof(*i->inputs) * i->isize)) ){ if(pthread_mutex_init(&i->ilock, NULL) == 0){ - if(pthread_cond_init(&i->icond, NULL) == 0){ - if(pthread_mutex_init(&i->clock, NULL) == 0){ - if(pthread_cond_init(&i->ccond, NULL) == 0){ - if((i->stdinfd = fileno(infp)) >= 0){ - if( (i->initdata = malloc(sizeof(*i->initdata))) ){ - if(getpipes(i->readypipes) == 0){ - memset(&i->amata, 0, sizeof(i->amata)); - if(prep_special_keys(i) == 0){ - if(set_fd_nonblocking(i->stdinfd, 1, &ti->stdio_blocking_save) == 0){ - i->termfd = tty_check(i->stdinfd) ? -1 : get_tty_fd(infp); - memset(i->initdata, 0, sizeof(*i->initdata)); - i->initdata->qterm = ti->qterm; - i->iread = i->iwrite = i->ivalid = 0; - i->cread = i->cwrite = i->cvalid = 0; - i->initdata_complete = NULL; - i->stats = stats; - i->ti = ti; - i->stdineof = 0; + pthread_condattr_t condattr; + if(prep_condattr(&condattr) == 0){ + if(pthread_cond_init(&i->icond, &condattr) == 0){ + if(pthread_mutex_init(&i->clock, NULL) == 0){ + if(pthread_cond_init(&i->ccond, &condattr) == 0){ + if((i->stdinfd = fileno(infp)) >= 0){ + if( (i->initdata = malloc(sizeof(*i->initdata))) ){ + if(getpipes(i->readypipes) == 0){ + memset(&i->amata, 0, sizeof(i->amata)); + if(prep_special_keys(i) == 0){ + if(set_fd_nonblocking(i->stdinfd, 1, &ti->stdio_blocking_save) == 0){ + i->termfd = tty_check(i->stdinfd) ? -1 : get_tty_fd(infp); + memset(i->initdata, 0, sizeof(*i->initdata)); + i->initdata->qterm = ti->qterm; + i->iread = i->iwrite = i->ivalid = 0; + i->cread = i->cwrite = i->cvalid = 0; + i->initdata_complete = NULL; + i->stats = stats; + i->ti = ti; + i->stdineof = 0; #ifdef __MINGW64__ - i->stdinhandle = ti->inhandle; + i->stdinhandle = ti->inhandle; #endif - i->ibufvalid = 0; - i->linesigs = linesigs_enabled; - i->tbufvalid = 0; - i->midescape = 0; - i->lmargin = lmargin; - i->tmargin = tmargin; - i->rmargin = rmargin; - i->bmargin = bmargin; - i->drain = drain; - i->failed = false; - logdebug("input descriptors: %d/%d\n", i->stdinfd, i->termfd); - return i; + i->ibufvalid = 0; + i->linesigs = linesigs_enabled; + i->tbufvalid = 0; + i->midescape = 0; + i->lmargin = lmargin; + i->tmargin = tmargin; + i->rmargin = rmargin; + i->bmargin = bmargin; + i->drain = drain; + i->failed = false; + logdebug("input descriptors: %d/%d\n", i->stdinfd, i->termfd); + return i; + } } + input_free_esctrie(&i->amata); } - input_free_esctrie(&i->amata); + endpipes(i->readypipes); } - endpipes(i->readypipes); + free(i->initdata); } - free(i->initdata); + pthread_cond_destroy(&i->ccond); } - pthread_cond_destroy(&i->ccond); + pthread_mutex_destroy(&i->clock); } - pthread_mutex_destroy(&i->clock); + pthread_cond_destroy(&i->icond); } - pthread_cond_destroy(&i->icond); + pthread_condattr_destroy(&condattr); } pthread_mutex_destroy(&i->ilock); }