NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
lib/44707: libedit does not allow for non-blobking operation
>Number: 44707
>Category: lib
>Synopsis: libedit does not allow for non-blobking operation
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: lib-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Fri Mar 11 01:00:00 +0000 2011
>Originator: Preston A. Elder
>Release:
>Organization:
>Environment:
>Description:
Libedit right now as implemented requires (to use it in unbuffered mode)
requires that a thread sit blocked on an el_gets call. It allows you to
specify your own read function, which you can make non-blocking, but that
doesn't really help much.
I submitted a patch a while ago to allow for a single app to handle multiple
libedit sessions at once (for, say, writing a custom telnet server) - however
it's still not really useful if I have to spawn a thread for each active
session. The change to make libedit allow for non-blocking operation is
actually pretty simple.
>How-To-Repeat:
Here is a sample program that demonstrates libedit operating where it is driven
by select (and so theoretically, N number of libedit sessions could be handled
by a single thread - note that without the patch, this will keep repeating the
prompt every time there is a keystroke!
#include <histedit.h>
#include <sys/ioctl.h>
#include <errno.h>
int my_read(EditLine *el, char *cp)
{
int rv;
FILE *fd = NULL;
el_get(el, EL_GETFP, 0, &fd);
rv = fgetc(fd);
if (rv > 0)
{
*cp = rv;
return 1;
}
return rv;
}
int main()
{
const char *s;
int nread;
fd_set fds;
EditLine *el = el_init("test", stdin, stdout, stderr);
int arg = 1;
ioctl(fileno(stdin), FIONBIO, &arg);
el_set(el, EL_GETCFN, &my_read);
FD_ZERO(&fds);
FD_SET(fileno(stdin), &fds);
s = el_gets(el, &nread);
if (errno != EAGAIN)
printf("Read %d/%d: %s", nread, errno, s);
while (1)
{
select(fileno(stdin)+1, &fds, NULL, NULL, NULL);
if (FD_ISSET(fileno(stdin), &fds))
{
errno = 0;
s = el_gets(el, &nread);
if (errno != EAGAIN)
{
if (!s)
break;
printf("Read %d/%d: %s", nread, errno, s);
}
}
}
el_end(el);
}
>Fix:
PATCH:
diff -ur libedit-20110227-3.0.orig/src/read.c libedit-20110227-3.0/src/read.c
--- libedit-20110227-3.0.orig/src/read.c 2011-02-26 17:42:59.000000000
-0500
+++ libedit-20110227-3.0/src/read.c 2011-03-10 19:13:17.533684002 -0500
@@ -523,8 +523,10 @@
}
#endif /* FIONREAD */
- if ((el->el_flags & UNBUFFERED) == 0)
+ // If the previous thing was an EAGAIN, don't prepare.
+ if (el->el_errno != EAGAIN && (el->el_flags & UNBUFFERED) == 0)
read_prepare(el);
+ el->el_errno = 0;
if (el->el_flags & EDIT_DISABLED) {
size_t idx;
@@ -580,6 +582,9 @@
el->el_line.cursor = el->el_line.buffer;
break;
}
+ if (el->el_errno == EAGAIN) {
+ break;
+ }
if ((unsigned int)cmdnum >= (unsigned int)el->el_map.nfunc) {
/* BUG CHECK command */
#ifdef DEBUG_EDIT
(void) fprintf(el->el_errfile,
Home |
Main Index |
Thread Index |
Old Index