[input] implement timeouts

This commit is contained in:
nick black 2021-09-16 02:03:00 -04:00
parent edb9eff34b
commit 1d4c62d446
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC
3 changed files with 32 additions and 21 deletions

View File

@ -67,9 +67,8 @@ to fill whenever it reads.
**notcurses_get** allows a **struct timespec** to be specified as a timeout. **notcurses_get** allows a **struct timespec** to be specified as a timeout.
If **ts** is **NULL**, **notcurses_get** will block until it reads input, or If **ts** is **NULL**, **notcurses_get** will block until it reads input, or
is interrupted by a signal. If its values are zeroes, there will be no blocking. is interrupted by a signal. If its values are zeroes, there will be no blocking.
Otherwise, **ts** specifies a minimum time to wait for input before giving up. Otherwise, **ts** specifies an absolute deadline (using the same source and
On timeout, 0 is returned. Signals in **sigmask** will be masked and blocked in timezone as **gettimeofday(2)**). On timeout, 0 is returned. Event
the same manner as a call to **ppoll(2)**. **sigmask** may be **NULL**. Event
details will be reported in **ni**, unless **ni** is NULL. details will be reported in **ni**, unless **ni** is NULL.
**notcurses_inputready_fd** provides a file descriptor suitable for use with **notcurses_inputready_fd** provides a file descriptor suitable for use with
@ -181,6 +180,7 @@ are resolved.
# SEE ALSO # SEE ALSO
**gettimeofday(2)**,
**poll(2)**, **poll(2)**,
**notcurses(3)**, **notcurses(3)**,
**notcurses_refresh(3)**, **notcurses_refresh(3)**,

View File

@ -1070,7 +1070,8 @@ ncinput_equal_p(const ncinput* n1, const ncinput* n2){
// timespec to bound blocking. Returns a single Unicode code point, or // timespec to bound blocking. Returns a single Unicode code point, or
// (uint32_t)-1 on error. 'sigmask' may be NULL. Returns 0 on a timeout. If an // (uint32_t)-1 on error. 'sigmask' may be NULL. Returns 0 on a timeout. If an
// event is processed, the return value is the 'id' field from that event. // event is processed, the return value is the 'id' field from that event.
// 'ni' may be NULL. // 'ni' may be NULL. 'ts' is an *absolute* time relative to gettimeofday()
// (see pthread_cond_timedwait(3)).
API uint32_t notcurses_get(struct notcurses* n, const struct timespec* ts, API uint32_t notcurses_get(struct notcurses* n, const struct timespec* ts,
ncinput* ni) ncinput* ni)
__attribute__ ((nonnull (1))); __attribute__ ((nonnull (1)));

View File

@ -23,7 +23,6 @@
// integrate main specials trie with automaton, enable input_errors // integrate main specials trie with automaton, enable input_errors
// wake up input thread when space becomes available // wake up input thread when space becomes available
// (needs pipes/eventfds) // (needs pipes/eventfds)
// handle timeouts
static sig_atomic_t resize_seen; static sig_atomic_t resize_seen;
@ -844,6 +843,13 @@ inc_input_events(inputctx* ictx){
pthread_mutex_unlock(&ictx->stats->lock); pthread_mutex_unlock(&ictx->stats->lock);
} }
static inline void
inc_input_errors(inputctx* ictx){
pthread_mutex_lock(&ictx->stats->lock);
++ictx->stats->s.input_errors;
pthread_mutex_unlock(&ictx->stats->lock);
}
// add a decoded, valid Unicode to the bulk output buffer, or drop it if no // add a decoded, valid Unicode to the bulk output buffer, or drop it if no
// space is available. // space is available.
static void static void
@ -1472,7 +1478,7 @@ pump_control_read(inputctx* ictx, unsigned char c){
} }
break; break;
default: default:
fprintf(stderr, "Reached invalid init state %d\n", ictx->state); logerror("Reached invalid init state %d\n", ictx->state);
return -1; return -1;
} }
return 0; return 0;
@ -1732,12 +1738,10 @@ block_on_input(inputctx* ictx){
sigdelset(&smask, SIGWINCH); sigdelset(&smask, SIGWINCH);
while((events = ppoll(pfds, pfdcount, ts, &smask)) < 0){ while((events = ppoll(pfds, pfdcount, ts, &smask)) < 0){
#endif #endif
fprintf(stderr, "GOT EVENTS: %d!\n", events);
if(errno != EINTR && errno != EAGAIN && errno != EBUSY && errno != EWOULDBLOCK){ if(errno != EINTR && errno != EAGAIN && errno != EBUSY && errno != EWOULDBLOCK){
return -1; return -1;
} }
if(resize_seen){ if(resize_seen){
fprintf(stderr, "SAW A RESIZE!\n");
return 1; return 1;
} }
} }
@ -1814,7 +1818,13 @@ internal_get(inputctx* ictx, const struct timespec* ts, ncinput* ni){
} }
pthread_mutex_lock(&ictx->ilock); pthread_mutex_lock(&ictx->ilock);
while(!ictx->ivalid){ while(!ictx->ivalid){
pthread_cond_wait(&ictx->icond, &ictx->ilock); if(pthread_cond_timedwait(&ictx->icond, &ictx->ilock, ts)){
if(errno == ETIMEDOUT){
return 0;
}
inc_input_errors(ictx);
return (uint32_t)-1;
}
} }
memcpy(ni, &ictx->inputs[ictx->iread], sizeof(*ni)); memcpy(ni, &ictx->inputs[ictx->iread], sizeof(*ni));
if(++ictx->iread == ictx->isize){ if(++ictx->iread == ictx->isize){
@ -1826,18 +1836,6 @@ internal_get(inputctx* ictx, const struct timespec* ts, ncinput* ni){
return ni->id; return ni->id;
} }
struct initial_responses* inputlayer_get_responses(inputctx* ictx){
struct initial_responses* iresp;
pthread_mutex_lock(&ictx->ilock);
while(!ictx->initdata_complete){
pthread_cond_wait(&ictx->icond, &ictx->ilock);
}
iresp = ictx->initdata_complete;
ictx->initdata_complete = NULL;
pthread_mutex_unlock(&ictx->ilock);
return iresp;
}
// infp has already been set non-blocking // infp has already been set non-blocking
uint32_t notcurses_get(notcurses* nc, const struct timespec* ts, ncinput* ni){ uint32_t notcurses_get(notcurses* nc, const struct timespec* ts, ncinput* ni){
uint32_t r = internal_get(nc->tcache.ictx, ts, ni); uint32_t r = internal_get(nc->tcache.ictx, ts, ni);
@ -1984,3 +1982,15 @@ linesigs_enable(tinfo* ti){
int notcurses_linesigs_enable(notcurses* n){ int notcurses_linesigs_enable(notcurses* n){
return linesigs_enable(&n->tcache); return linesigs_enable(&n->tcache);
} }
struct initial_responses* inputlayer_get_responses(inputctx* ictx){
struct initial_responses* iresp;
pthread_mutex_lock(&ictx->ilock);
while(!ictx->initdata_complete){
pthread_cond_wait(&ictx->icond, &ictx->ilock);
}
iresp = ictx->initdata_complete;
ictx->initdata_complete = NULL;
pthread_mutex_unlock(&ictx->ilock);
return iresp;
}