space_for_read(), read_input_nblock()

This commit is contained in:
nick black 2021-09-08 18:28:24 -04:00
parent 165e61e4c0
commit 6f8afb1610
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC

View File

@ -28,8 +28,10 @@ typedef struct inputctx {
#endif
unsigned char ibuf[BUFSIZ]; // we dump raw reads into this ringbuffer, and
// process them all post-read
int ibufvalid, ibufwrite; // our bookkeeping for ibuf;
// we mustn't read() if ibufvalid == sizeof(ibuf)
int ibufvalid; // we mustn't read() if ibufvalid == sizeof(ibuf)
int ibufwrite; // we write here next
int ibufread; // first valid byte here (if any are valid)
cursorloc* csrs; // cursor reports are dumped here
ncinput* inputs; // processed input is dumped here
int csize, isize; // total number of slots in csrs/inputs
@ -51,11 +53,14 @@ create_inputctx(tinfo* ti){
i->isize = BUFSIZ;
if( (i->inputs = malloc(sizeof(*i->inputs) * i->isize)) ){
// FIXME set up infd/handle
i->termfd = -1;
i->stdinfd = -1;
i->ti = ti;
i->cvalid = i->ivalid = 0;
i->cwrite = i->iwrite = 0;
i->cread = i->iread = 0;
i->ibufvalid = i->ibufwrite = 0;
i->ibufread = 0;
return i;
}
free(i->csrs);
@ -75,14 +80,81 @@ free_inputctx(inputctx* i){
}
}
// how many bytes can a single read fill in the ibuf? this might be fewer than
// the actual number of free bytes, due to reading on the right or left side.
static inline size_t
space_for_read(inputctx* ictx){
// if we are valid everywhere, there's no space to read into.
if(ictx->ibufvalid == sizeof(ictx->ibuf)){
return 0;
}
// if we are valid nowhere, we can read into the head of the buffer
if(ictx->ibufvalid == 0){
ictx->ibufread = 0;
ictx->ibufwrite = 0;
return sizeof(ictx->ibuf);
}
// otherwise, we can read either from ibufwrite to the end of the buffer,
// or from ibufwrite to ibufread.
if(ictx->ibufwrite < ictx->ibufread){
return ictx->ibufread - ictx->ibufwrite;
}
return sizeof(ictx->ibuf) - ictx->ibufwrite;
}
// populate the ibuf with any new data from the specified file descriptor.
static void
read_input_nblock(inputctx* ictx, int fd){
if(fd >= 0){
size_t space = space_for_read(ictx);
if(space == 0){
return;
}
ssize_t r = read(fd, ictx->ibuf + ictx->ibufwrite, space);
if(r >= 0){
ictx->ibufwrite += r;
if(ictx->ibufwrite == sizeof(ictx->ibuf)){
ictx->ibufwrite = 0;
}
ictx->ibufvalid += r;
space -= r;
loginfo("read %lldB from %d (%lluB left)\n", (long long)r, fd, (unsigned long long)space);
if(space == 0){
return;
}
// might have been falsely limited by space (only reading on the right).
// this will recurse one time at most.
if(ictx->ibufwrite == 0){
read_input_nblock(ictx, fd);
}
}
}
}
// walk the matching automaton from wherever we were.
static void
process_ibuf(inputctx* ictx){
// FIXME
}
// populate the ibuf with any new data, up through its size, but do not block.
// don't loop around this call without some kind of readiness notification.
static void
read_inputs_nblock(inputctx* ictx){
// first we read from the terminal, if that's a distinct source.
read_input_nblock(ictx, ictx->termfd);
// now read bulk, possibly with term escapes intermingled within (if there
// was not a distinct terminal source).
read_input_nblock(ictx, ictx->stdinfd);
}
static void*
input_thread(void* vmarshall){
inputctx* ictx = vmarshall;
for(;;){
if(ictx->ibufvalid == sizeof(ictx->ibuf)){
// we can't read any more. need clients to clear their buffers.
// sleep on condvar FIXME
}
read_inputs_nblock(ictx);
// process anything we've read
process_ibuf(ictx);
}
return NULL;
}