bug-readline
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Bug-readline] select() and POSIX behavior with timeval


From: Mike Frysinger
Subject: [Bug-readline] select() and POSIX behavior with timeval
Date: Mon, 9 Feb 2009 15:01:59 -0500
User-agent: KMail/1.11.0 (Linux/2.6.28; KDE/4.2.0; x86_64; ; )

weird behavior was observed with linphone's command line interface (which uses
readline).  Li traced it back to the keyboard timeout value used in readline.
linphone sets this to more than one second which has readline setup a timeval
structure like so:
        timer.tv_sec = 0;
        timer.tv_usec = _keyboard_input_timeout;
the implementation of select() that was being used would reject this as an
invalid value (since the tv_usec member had a value larger than 1 second).
this would cause linphone to keep calling readline over and over trying to get
input which would never come because select() would always return an error.

i talked to the POSIX guys and basically both behaviors are acceptable
according to the spec.  in other words, implementations may choose to return
an error (EINVAL), or they may support it (auto converting the usec field into
seconds).

as such, ive updated readline to make sure the timeval struct is setup
properly.  when the system is known to support this syntax (i.e. glibc), then
the current behavior is preserved.  otherwise the value is transformed into a
strict "valid" value.  comments ?
-mike

diff --git a/input.c b/input.c
index da5d771..e0c2043 100644
--- a/input.c
+++ b/input.c
@@ -45,14 +45,7 @@
 #  include "ansi_stdlib.h"
 #endif /* HAVE_STDLIB_H */
 
-#if defined (HAVE_SELECT)
-#  if !defined (HAVE_SYS_SELECT_H) || !defined (M_UNIX)
-#    include <sys/time.h>
-#  endif
-#endif /* HAVE_SELECT */
-#if defined (HAVE_SYS_SELECT_H)
-#  include <sys/select.h>
-#endif
+#include "posixselect.h"
 
 #if defined (FIONREAD_IN_SYS_IOCTL)
 #  include <sys/ioctl.h>
@@ -187,8 +180,7 @@ rl_gather_tyi ()
   FD_ZERO (&exceptfds);
   FD_SET (tty, &readfds);
   FD_SET (tty, &exceptfds);
-  timeout.tv_sec = 0;
-  timeout.tv_usec = _keyboard_input_timeout;
+  _rl_usec_to_timeval (_keyboard_input_timeout, timeout);
   result = select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout);
   if (result <= 0)
     return 0;  /* Nothing to read. */
@@ -301,8 +293,7 @@ _rl_input_available ()
   FD_ZERO (&exceptfds);
   FD_SET (tty, &readfds);
   FD_SET (tty, &exceptfds);
-  timeout.tv_sec = 0;
-  timeout.tv_usec = _keyboard_input_timeout;
+  _rl_usec_to_timeval (_keyboard_input_timeout, timeout);
   return (select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout) > 
0);
 #else
 
diff --git a/parens.c b/parens.c
index 737f767..7e674c2 100644
--- a/parens.c
+++ b/parens.c
@@ -38,16 +38,7 @@
 #  include <unistd.h>
 #endif
 
-#if defined (FD_SET) && !defined (HAVE_SELECT)
-#  define HAVE_SELECT
-#endif
-
-#if defined (HAVE_SELECT)
-#  include <sys/time.h>
-#endif /* HAVE_SELECT */
-#if defined (HAVE_SYS_SELECT_H)
-#  include <sys/select.h>
-#endif
+#include "posixselect.h"
 
 #if defined (HAVE_STRING_H)
 #  include <string.h>
@@ -130,8 +121,7 @@ rl_insert_close (count, invoking_key)
 
       FD_ZERO (&readfds);
       FD_SET (fileno (rl_instream), &readfds);
-      timer.tv_sec = 0;
-      timer.tv_usec = _paren_blink_usec;
+      _rl_usec_to_timeval (_paren_blink_usec, timer);
 
       orig_point = rl_point;
       rl_point = match_point;
diff --git a/posixselect.h b/posixselect.h
new file mode 100644
index 0000000..8266ed5
--- /dev/null
+++ b/posixselect.h
@@ -0,0 +1,38 @@
+/*
+ * Handle various select() issues.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#if !defined (_POSIXSELECT_H_)
+#define _POSIXSELECT_H_
+
+#if defined (FD_SET) && !defined (HAVE_SELECT)
+#  define HAVE_SELECT
+#endif
+
+#if defined (HAVE_SELECT)
+#  if !defined (HAVE_SYS_SELECT_H) || !defined (M_UNIX)
+#    include <sys/time.h>
+#  endif
+#endif /* HAVE_SELECT */
+#if defined (HAVE_SYS_SELECT_H)
+#  include <sys/select.h>
+#endif
+
+#ifndef USEC_PER_SEC
+#  define USEC_PER_SEC 1000000
+#endif
+static inline void _rl_usec_to_timeval(int usec, struct timeval tv)
+{
+#if defined(__GLIBC__)
+       /* GNU extension -- usec can be greater than 1 second */
+       tv.tv_sec = 0;
+       tv.tv_usec = usec;
+#else
+       tv.tv_sec = usec / USEC_PER_SEC;
+       tv.tv_usec = usec % USEC_PER_SEC;
+#endif
+}
+
+#endif /* _POSIXSELECT_H_ */





reply via email to

[Prev in Thread] Current Thread [Next in Thread]