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,

NetBSD Home
NetBSD PR Database Search

(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.