summaryrefslogtreecommitdiff
path: root/lib/libcurses/lib_twait.c
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>1997-11-26 04:02:03 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>1997-11-26 04:02:03 +0000
commitbda33b7e716d56bf1a9ecccb7e2543889f9ab1d3 (patch)
tree7bc4bcdf70ecc1d045693a309e96b304e1b49c33 /lib/libcurses/lib_twait.c
parentcd15e61d557c4704743905eae7b88ae927cf0394 (diff)
ncurses 4.1 + changes to work with our terminfo libs (instead of
the ncurses ones). Changes are #ifdef EXTERN_TERMINFO. Post 4.1 patches will be applied in a separate commit.
Diffstat (limited to 'lib/libcurses/lib_twait.c')
-rw-r--r--lib/libcurses/lib_twait.c237
1 files changed, 193 insertions, 44 deletions
diff --git a/lib/libcurses/lib_twait.c b/lib/libcurses/lib_twait.c
index c9dee4e07be..92f29b8b748 100644
--- a/lib/libcurses/lib_twait.c
+++ b/lib/libcurses/lib_twait.c
@@ -26,93 +26,242 @@
**
*/
-#include "curses.priv.h"
+#include <curses.priv.h>
-#include <sys/types.h> /* some systems can't live without this */
-#include <string.h>
-
-#if HAVE_SYS_TIME_H && ! SYSTEM_LOOKS_LIKE_SCO
+#if USE_FUNC_POLL
+#include <stropts.h>
+#include <poll.h>
+#if HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
-
-#if HAVE_UNISTD_H
-#include <unistd.h>
+#elif HAVE_SELECT
+/* on SCO, <sys/time.h> conflicts with <sys/select.h> */
+#if HAVE_SYS_TIME_H && ! SYSTEM_LOOKS_LIKE_SCO
+#include <sys/time.h>
#endif
-
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
+#endif
+
+MODULE_ID("Id: lib_twait.c,v 1.18 1997/02/15 18:27:51 tom Exp $")
/*
- * We want to define GOOD_SELECT if the last argument of select(2) is
+ * We want to define GOOD_SELECT if the last argument of select(2) is
* modified to indicate time left. The code will deal gracefully with
* the other case, this is just an optimization to reduce the number
* of system calls per input event.
*
- * In general, expect System-V-like UNIXes to have this behavior and BSD-like
+ * In general, expect System-V-like UNIXes to have this behavior and BSD-like
* ones to not have it. Check your manual page. If it doesn't explicitly
* say the last argument is modified, assume it's not.
- *
+ *
* (We'd really like configure to autodetect this, but writing a proper test
* turns out to be hard.)
*/
-#if defined(linux)
-#define GOOD_SELECT
+
+#if HAVE_GETTIMEOFDAY
+#if (defined(TRACE) && !HAVE_USLEEP) || ! GOOD_SELECT
+static void _nc_gettime(struct timeval *tp)
+{
+ gettimeofday(tp, (struct timezone *)0);
+ T(("time: %ld.%06ld", tp->tv_sec, tp->tv_usec));
+}
+#endif
#endif
#if !HAVE_USLEEP
-int usleep(unsigned int usec)
+int _nc_usleep(unsigned int usec)
{
+int code;
struct timeval tval;
+#if defined(TRACE) && HAVE_GETTIMEOFDAY
+ _nc_gettime(&tval);
+#endif
+#if USE_FUNC_POLL
+ {
+ struct pollfd fds[1];
+ code = poll(fds, 0, usec / 1000);
+ }
+#elif HAVE_SELECT
tval.tv_sec = usec / 1000000;
tval.tv_usec = usec % 1000000;
- select(0, NULL, NULL, NULL, &tval);
+ code = select(0, NULL, NULL, NULL, &tval);
+#endif
-}
+#if defined(TRACE) && HAVE_GETTIMEOFDAY
+ _nc_gettime(&tval);
#endif
+ return code;
+}
+#endif /* !HAVE_USLEEP */
-int _nc_timed_wait(int fd, int wait, int *timeleft)
+/*
+ * Wait a specified number of milliseconds, returning true if the timer
+ * didn't expire before there is activity on the specified file descriptors.
+ * The file-descriptors are specified by the mode:
+ * 0 - none (absolute time)
+ * 1 - ncurses' normal input-descriptor
+ * 2 - mouse descriptor, if any
+ * 3 - either input or mouse.
+ *
+ * If the milliseconds given are -1, the wait blocks until activity on the
+ * descriptors.
+ */
+int _nc_timed_wait(int mode, int milliseconds, int *timeleft)
{
-int result;
+int fd;
+int count = 0;
+long whole_secs = milliseconds / 1000;
+long micro_secs = (milliseconds % 1000) * 1000;
+
+int result = 0;
struct timeval ntimeout;
+
+#if USE_FUNC_POLL
+struct pollfd fds[2];
+#elif HAVE_SELECT
static fd_set set;
-#if !defined(GOOD_SELECT) && HAVE_GETTIMEOFDAY
+#endif
+
+#if !GOOD_SELECT && HAVE_GETTIMEOFDAY
struct timeval starttime, returntime;
+long delta;
- gettimeofday(&starttime, NULL);
+ _nc_gettime(&starttime);
#endif
- FD_ZERO(&set);
- FD_SET(fd, &set);
+ if (milliseconds >= 0) {
+ ntimeout.tv_sec = whole_secs;
+ ntimeout.tv_usec = micro_secs;
+ } else {
+ ntimeout.tv_sec = 0;
+ ntimeout.tv_usec = 0;
+ }
+
+ T(("start twait: %lu.%06lu secs", (long) ntimeout.tv_sec, (long) ntimeout.tv_usec));
- /* the units of wait are milliseconds */
- ntimeout.tv_sec = wait / 1000;
- ntimeout.tv_usec = (wait % 1000) * 1000;
+ /*
+ * The do loop tries to make it look like we have restarting signals,
+ * even if we don't.
+ */
+ do {
+ count = 0;
+#if USE_FUNC_POLL
- T(("start twait: sec = %ld, usec = %ld", ntimeout.tv_sec, ntimeout.tv_usec));
+ if (mode & 1) {
+ fds[count].fd = SP->_ifd;
+ fds[count].events = POLLIN;
+ count++;
+ }
+ if ((mode & 2)
+ && (fd = _nc_mouse_fd()) >= 0) {
+ fds[count].fd = fd;
+ fds[count].events = POLLIN;
+ count++;
+ }
- result = select(fd+1, &set, NULL, NULL, &ntimeout);
+ result = poll(fds, count, milliseconds);
+#elif HAVE_SELECT
+ /*
+ * Some systems modify the fd_set arguments; do this in the
+ * loop.
+ */
+ FD_ZERO(&set);
-#if !defined(GOOD_SELECT) && HAVE_GETTIMEOFDAY
- gettimeofday(&returntime, NULL);
- ntimeout.tv_sec -= (returntime.tv_sec - starttime.tv_sec);
- ntimeout.tv_usec -= (returntime.tv_usec - starttime.tv_usec);
- if (ntimeout.tv_usec < 0 && ntimeout.tv_sec > 0) {
- ntimeout.tv_sec--;
- ntimeout.tv_usec += 1000000;
- }
- if (ntimeout.tv_sec < 0)
- ntimeout.tv_sec = ntimeout.tv_usec = 0;
+ if (mode & 1) {
+ FD_SET(SP->_ifd, &set);
+ count = SP->_ifd + 1;
+ }
+ if ((mode & 2)
+ && (fd = _nc_mouse_fd()) >= 0) {
+ FD_SET(fd, &set);
+ count = max(fd, count) + 1;
+ }
+
+ errno = 0;
+ result = select(count, &set, NULL, NULL, milliseconds >= 0 ? &ntimeout : 0);
#endif
- /* return approximate time left on the ntimeout, in milliseconds */
- if (timeleft)
+#if !GOOD_SELECT && HAVE_GETTIMEOFDAY
+ _nc_gettime(&returntime);
+
+ /* The contents of ntimeout aren't guaranteed after return from
+ * 'select()', so we disregard its contents. Also, note that
+ * on some systems, tv_sec and tv_usec are unsigned.
+ */
+ ntimeout.tv_sec = whole_secs;
+ ntimeout.tv_usec = micro_secs;
+
+#define DELTA(f) (long)ntimeout.f - (long)returntime.f + (long)starttime.f
+
+ delta = DELTA(tv_sec);
+ if (delta < 0)
+ delta = 0;
+ ntimeout.tv_sec = delta;
+
+ delta = DELTA(tv_usec);
+ while (delta < 0 && ntimeout.tv_sec != 0) {
+ ntimeout.tv_sec--;
+ delta += 1000000;
+ }
+ ntimeout.tv_usec = delta;
+ if (delta < 0)
+ ntimeout.tv_sec = ntimeout.tv_usec = 0;
+
+ /*
+ * If the timeout hasn't expired, and we've gotten no data,
+ * this is probably a system where 'select()' needs to be left
+ * alone so that it can complete. Make this process sleep,
+ * then come back for more.
+ */
+ if (result == 0
+ && (ntimeout.tv_sec != 0 || ntimeout.tv_usec > 100000)) {
+ napms(100);
+ continue;
+ }
+#endif
+ } while (result == -1 && errno == EINTR);
+
+ /* return approximate time left on the ntimeout, in milliseconds */
+ if (timeleft)
*timeleft = (ntimeout.tv_sec * 1000) + (ntimeout.tv_usec / 1000);
- T(("end twait: returned %d, sec = %ld, usec = %ld (%d msec)",
- result, ntimeout.tv_sec, ntimeout.tv_usec,
- timeleft ? *timeleft : -1));
+ T(("end twait: returned %d, remaining time %lu.%06lu secs (%d msec)",
+ result, (long) ntimeout.tv_sec, (long) ntimeout.tv_usec,
+ timeleft ? *timeleft : -1));
+
+ /*
+ * Both 'poll()' and 'select()' return the number of file descriptors
+ * that are active. Translate this back to the mask that denotes which
+ * file-descriptors, so that we don't need all of this system-specific
+ * code everywhere.
+ */
+ if (result != 0) {
+ if (result > 0) {
+ result = 0;
+#if USE_FUNC_POLL
+ for (count = 0; count < 2; count++) {
+ if ((mode & (1 << count))
+ && (fds[count].revents & POLLIN)) {
+ result |= (1 << count);
+ count++;
+ }
+ }
+#elif HAVE_SELECT
+ if ((mode & 2)
+ && (fd = _nc_mouse_fd()) >= 0
+ && FD_ISSET(fd, &set))
+ result |= 2;
+ if ((mode & 1)
+ && FD_ISSET(SP->_ifd, &set))
+ result |= 1;
+#endif
+ }
+ else
+ result = 0;
+ }
- return(result);
+ return (result);
}