diff options
Diffstat (limited to 'ncurses-5.3/ncurses/tty/lib_twait.c')
-rw-r--r-- | ncurses-5.3/ncurses/tty/lib_twait.c | 440 |
1 files changed, 440 insertions, 0 deletions
diff --git a/ncurses-5.3/ncurses/tty/lib_twait.c b/ncurses-5.3/ncurses/tty/lib_twait.c new file mode 100644 index 0000000..459adbe --- /dev/null +++ b/ncurses-5.3/ncurses/tty/lib_twait.c @@ -0,0 +1,440 @@ +/**************************************************************************** + * Copyright (c) 1998-2001,2002 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * + * and: Eric S. Raymond <esr@snark.thyrsus.com> * + ****************************************************************************/ + +/* +** lib_twait.c +** +** The routine _nc_timed_wait(). +** +** (This file was originally written by Eric Raymond; however except for +** comments, none of the original code remains - T.Dickey). +*/ + +#include <curses.priv.h> + +#ifdef __BEOS__ +#undef false +#undef true +#include <OS.h> +#endif + +#if USE_FUNC_POLL +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# endif +#elif HAVE_SELECT +# if HAVE_SYS_TIME_H && HAVE_SYS_TIME_SELECT +# include <sys/time.h> +# endif +# if HAVE_SYS_SELECT_H +# include <sys/select.h> +# endif +#endif + +MODULE_ID("$Id$") + +static long +_nc_gettime(bool first) +{ + long res; + +#if HAVE_GETTIMEOFDAY +# define PRECISE_GETTIME 1 + static struct timeval t0; + struct timeval t1; + gettimeofday(&t1, (struct timezone *) 0); + if (first) { + t0 = t1; + } + res = (t1.tv_sec - t0.tv_sec) * 1000 + + (t1.tv_usec - t0.tv_usec) / 1000; +#else +# define PRECISE_GETTIME 0 + static time_t t0; + time_t t1 = time((time_t *) 0); + if (first) { + t0 = t1; + } + res = (t1 - t0) * 1000; +#endif + TR(TRACE_IEVENT, ("%s time: %ld msec", first ? "get" : "elapsed", res)); + return res; +} + +#ifdef NCURSES_WGETCH_EVENTS +NCURSES_EXPORT(int) +_nc_eventlist_timeout(_nc_eventlist * evl) +{ + _nc_event **ev, **last; + int event_delay = -1; + + if (evl != 0) { + + ev = evl->events; + last = ev + evl->count; + + while (ev < last) { + if ((*ev)->type == _NC_EVENT_TIMEOUT_MSEC) { + event_delay = (*ev)->data.timeout_msec; + if (event_delay < 0) + event_delay = LONG_MAX; /* FIXME Is this defined? */ + } + } + } + return event_delay; +} +#endif /* NCURSES_WGETCH_EVENTS */ + +/* + * Wait a specified number of milliseconds, returning nonzero 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. + * + * Experimental: if NCURSES_WGETCH_EVENTS is defined, (mode & 4) determines + * whether to pay attention to evl argument. If set, the smallest of + * millisecond and of timeout of evl is taken. + * + * We return a mask that corresponds to the mode (e.g., 2 for mouse activity). + * + * If the milliseconds given are -1, the wait blocks until activity on the + * descriptors. + */ +NCURSES_EXPORT(int) +_nc_timed_wait(int mode, + int milliseconds, + int *timeleft + EVENTLIST_2nd(_nc_eventlist * evl)) +{ + int fd; + int count; + int result; + +#ifdef NCURSES_WGETCH_EVENTS + int timeout_is_event = 0; +#endif + +#if USE_FUNC_POLL + struct pollfd fd_list[2]; + struct pollfd *fds = fd_list; +#elif defined(__BEOS__) +#elif HAVE_SELECT + static fd_set set; +#endif + + long starttime, returntime; + + TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d", + milliseconds, mode)); + +#ifdef NCURSES_WGETCH_EVENTS + if (mode & 4) { + int event_delay = _nc_eventlist_timeout(evl); + + if (event_delay >= 0 + && (milliseconds >= event_delay || milliseconds < 0)) { + milliseconds = event_delay; + timeout_is_event = 1; + } + } +#endif + +#if PRECISE_GETTIME + retry: +#endif + starttime = _nc_gettime(TRUE); + + count = 0; + +#ifdef NCURSES_WGETCH_EVENTS + if ((mode & 4) && evl) + evl->result_flags = 0; +#endif + +#if USE_FUNC_POLL + memset(fd_list, 0, sizeof(fd_list)); + +#ifdef NCURSES_WGETCH_EVENTS + if ((mode & 4) && evl) + fds = typeMalloc(struct pollfd, 2 + evl->count); +#endif + + if (mode & 1) { + fds[count].fd = SP->_ifd; + fds[count].events = POLLIN; + count++; + } + if ((mode & 2) + && (fd = SP->_mouse_fd) >= 0) { + fds[count].fd = fd; + fds[count].events = POLLIN; + count++; + } +#ifdef NCURSES_WGETCH_EVENTS + if ((mode & 4) && evl) { + _nc_event **ev = evl->events; + _nc_event **last = ev + evl->count; + + while (ev < last) { + if ((*ev)->type == _NC_EVENT_FILE + && ((*ev)->data.fev.flags & _NC_EVENT_FILE_READABLE)) { + fds[count].fd = (*ev)->data.fev.fd; + fds[count].events = POLLIN; + count++; + } + } + } +#endif + + result = poll(fds, count, milliseconds); + +#ifdef NCURSES_WGETCH_EVENTS + if ((mode & 4) && evl) { + _nc_event **ev = evl->events; + _nc_event **last = ev + evl->count; + int c; + + if (!result) + count = 0; + while (ev < last) { + if ((*ev)->type == _NC_EVENT_FILE + && ((*ev)->data.fev.flags & _NC_EVENT_FILE_READABLE)) { + (*ev)->data.fev.result = 0; + for (c = 0; c < count; c++) + if (fds[c].fd == (*ev)->data.fev.fd + && fds[c].revents & POLLIN) { + (*ev)->data.fev.result |= _NC_EVENT_FILE_READABLE; + evl->result_flags |= _NC_EVENT_FILE_READABLE; + } + } else if ((*ev)->type == _NC_EVENT_TIMEOUT_MSEC + && !result && timeout_is_event) { + evl->result_flags |= _NC_EVENT_TIMEOUT_MSEC; + } + } + } + + if (fds != fd_list) + free((char *) fds); + +#endif + +#elif defined(__BEOS__) + /* + * BeOS's select() is declared in socket.h, so the configure script does + * not see it. That's just as well, since that function works only for + * sockets. This (using snooze and ioctl) was distilled from Be's patch + * for ncurses which uses a separate thread to simulate select(). + * + * FIXME: the return values from the ioctl aren't very clear if we get + * interrupted. + * + * FIXME: this assumes mode&1 if milliseconds < 0 (see lib_getch.c). + */ + result = 0; + if (mode & 1) { + int step = (milliseconds < 0) ? 0 : 5000; + bigtime_t d; + bigtime_t useconds = milliseconds * 1000; + int n, howmany; + + if (useconds <= 0) /* we're here to go _through_ the loop */ + useconds = 1; + + for (d = 0; d < useconds; d += step) { + n = 0; + howmany = ioctl(0, 'ichr', &n); + if (howmany >= 0 && n > 0) { + result = 1; + break; + } + if (useconds > 1 && step > 0) { + snooze(step); + milliseconds -= (step / 1000); + if (milliseconds <= 0) { + milliseconds = 0; + break; + } + } + } + } else if (milliseconds > 0) { + snooze(milliseconds * 1000); + milliseconds = 0; + } +#elif HAVE_SELECT + /* + * select() modifies the fd_set arguments; do this in the + * loop. + */ + FD_ZERO(&set); + + if (mode & 1) { + FD_SET(SP->_ifd, &set); + count = SP->_ifd + 1; + } + if ((mode & 2) + && (fd = SP->_mouse_fd) >= 0) { + FD_SET(fd, &set); + count = max(fd, count) + 1; + } +#ifdef NCURSES_WGETCH_EVENTS + if ((mode & 4) && evl) { + _nc_event **ev = evl->events; + _nc_event **last = ev + evl->count; + + while (ev < last) { + if ((*ev)->type == _NC_EVENT_FILE + && ((*ev)->data.fev.flags & _NC_EVENT_FILE_READABLE)) { + FD_SET((*ev)->data.fev.fd, &set); + count = max((*ev)->data.fev.fd + 1, count); + } + } + } +#endif + + if (milliseconds >= 0) { + struct timeval ntimeout; + ntimeout.tv_sec = milliseconds / 1000; + ntimeout.tv_usec = (milliseconds % 1000) * 1000; + result = select(count, &set, NULL, NULL, &ntimeout); + } else { + result = select(count, &set, NULL, NULL, NULL); + } + +#ifdef NCURSES_WGETCH_EVENTS + if ((mode & 4) && evl) { + _nc_event **ev = evl->events; + _nc_event **last = ev + evl->count; + + evl->result_flags = 0; + while (ev < last) { + if ((*ev)->type == _NC_EVENT_FILE + && ((*ev)->data.fev.flags & _NC_EVENT_FILE_READABLE)) { + (*ev)->data.fev.result = 0; + if (FD_ISSET((*ev)->data.fev.fd, &set)) { + (*ev)->data.fev.result |= _NC_EVENT_FILE_READABLE; + evl->result_flags |= _NC_EVENT_FILE_READABLE; + } + } else if ((*ev)->type == _NC_EVENT_TIMEOUT_MSEC + && !result && timeout_is_event) + evl->result_flags |= _NC_EVENT_TIMEOUT_MSEC; + } + } +#endif + +#endif /* USE_FUNC_POLL, etc */ + + returntime = _nc_gettime(FALSE); + + if (milliseconds >= 0) + milliseconds -= (returntime - starttime); + +#ifdef NCURSES_WGETCH_EVENTS + if (evl) { + _nc_event **ev = evl->events; + _nc_event **last = ev + evl->count; + + evl->result_flags = 0; + while (ev < last) { + if ((*ev)->type == _NC_EVENT_TIMEOUT_MSEC) { + long diff = (returntime - starttime); + if ((*ev)->data.timeout_msec <= diff) + (*ev)->data.timeout_msec = 0; + else + (*ev)->data.timeout_msec -= diff; + } + + } + } +#endif + +#if PRECISE_GETTIME + /* + * 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 && milliseconds > 100) { + napms(100); + milliseconds -= 100; + goto retry; + } +#endif + + /* return approximate time left in milliseconds */ + if (timeleft) + *timeleft = milliseconds; + + TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec", + result, errno, milliseconds)); + + /* + * 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); + } + } +#elif defined(__BEOS__) + result = 1; /* redundant, but simple */ +#elif HAVE_SELECT + if ((mode & 2) + && (fd = SP->_mouse_fd) >= 0 + && FD_ISSET(fd, &set)) + result |= 2; + if ((mode & 1) + && FD_ISSET(SP->_ifd, &set)) + result |= 1; +#endif + } else + result = 0; + } +#ifdef NCURSES_WGETCH_EVENTS + if ((mode & 4) && evl && evl->result_flags) + result |= 4; +#endif + + return (result); +} |