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
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.
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_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)
                                printf("Read %d/%d: %s", nread, errno, s);



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 
+++ 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)
+       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;
+               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