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