NetBSD Problem Report #44707
From www@NetBSD.org Fri Mar 11 00:56:35 2011
Return-Path: <www@NetBSD.org>
Received: from mail.netbsd.org (mail.netbsd.org [204.152.190.11])
by www.NetBSD.org (Postfix) with ESMTP id 22FDD63B8DB
for <gnats-bugs@gnats.NetBSD.org>; Fri, 11 Mar 2011 00:56:35 +0000 (UTC)
Message-Id: <20110311005633.D114363B874@www.NetBSD.org>
Date: Fri, 11 Mar 2011 00:56:33 +0000 (UTC)
From: prez@goth.net
Reply-To: prez@goth.net
To: gnats-bugs@NetBSD.org
Subject: libedit does not allow for non-blobking operation
X-Send-Pr-Version: www-1.0
>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,
(Contact us)
$NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.