X-Git-Url: https://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=ncurses%2Ftty%2Flib_twait.c;h=7402a10354fc694c5ac21ebc1d008c7d956614f4;hp=f095c9b53c0c8c5e6c04c7ab56b764d14bb131f5;hb=a8987e73ec254703634802b4f7ee30d3a485524d;hpb=0eb88fc5281804773e2a0c7a488a4452463535ce diff --git a/ncurses/tty/lib_twait.c b/ncurses/tty/lib_twait.c index f095c9b5..7402a103 100644 --- a/ncurses/tty/lib_twait.c +++ b/ncurses/tty/lib_twait.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998 Free Software Foundation, Inc. * + * Copyright (c) 1998-2002,2003 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 * @@ -40,15 +40,15 @@ ** comments, none of the original code remains - T.Dickey). */ +#include + #ifdef __BEOS__ +#undef false +#undef true #include #endif -#include - #if USE_FUNC_POLL -# include -# include # if HAVE_SYS_TIME_H # include # endif @@ -61,35 +61,67 @@ # endif #endif -MODULE_ID("$Id: lib_twait.c,v 1.34 1999/10/16 21:25:10 tom Exp $") +MODULE_ID("$Id: lib_twait.c,v 1.49 2003/11/30 00:34:36 Philippe.Blain Exp $") -static long _nc_gettime(bool first) +static long +_nc_gettime(bool first) { - long res; + 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; + static struct timeval t0; + struct timeval t1; + gettimeofday(&t1, (struct timezone *) 0); + if (first) { + t0 = t1; + res = 0; + } else { + /* .tv_sec and .tv_usec are unsigned, be careful when subtracting */ + if (t0.tv_usec > t1.tv_usec) { /* Convert 1s in 1e6 microsecs */ + t1.tv_usec += 1000000; + t1.tv_sec--; } - res = (t1.tv_sec - t0.tv_sec) * 1000 + 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; + static time_t t0; + time_t t1 = time((time_t *) 0); + if (first) { + t0 = t1; + } + res = (t1 - t0) * 1000; #endif - T(("%s time: %ld msec", first ? "get" : "elapsed", res)); - return res; + 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. @@ -98,169 +130,318 @@ static long _nc_gettime(bool first) * 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. */ -int _nc_timed_wait(int mode, int milliseconds, int *timeleft) +NCURSES_EXPORT(int) +_nc_timed_wait(int mode, + int milliseconds, + int *timeleft + EVENTLIST_2nd(_nc_eventlist * evl)) { -int fd; -int count; + int fd; + int count; + int result; -int result; +#ifdef NCURSES_WGETCH_EVENTS + int timeout_is_event = 0; +#endif #if USE_FUNC_POLL -struct pollfd fds[2]; + struct pollfd fd_list[2]; + struct pollfd *fds = fd_list; #elif defined(__BEOS__) #elif HAVE_SELECT -static fd_set set; + static fd_set set; #endif -long starttime, returntime; + long starttime, returntime; - T(("start twait: %d milliseconds, mode: %d", milliseconds, mode)); + 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: + retry: #endif - starttime = _nc_gettime(TRUE); + starttime = _nc_gettime(TRUE); - count = 0; + count = 0; + +#ifdef NCURSES_WGETCH_EVENTS + if ((mode & 4) && evl) + evl->result_flags = 0; +#endif #if USE_FUNC_POLL - if (mode & 1) { - fds[count].fd = SP->_ifd; + 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++; + } } - if ((mode & 2) - && (fd = SP->_mouse_fd) >= 0) { - fds[count].fd = 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; + } } - result = poll(fds, count, milliseconds); + } + + 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. - */ - result = 0; - if (mode & 1) { - 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 += 5000) { - n = 0; - howmany = ioctl(0, 'ichr', &n); - if (howmany >= 0 && n > 0) { - result = 1; - break; - } - if (useconds > 1) - snooze(5000); - milliseconds -= 5; + /* + * 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; + } } + } 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; + /* + * 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); + 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 - returntime = _nc_gettime(FALSE); +#endif /* USE_FUNC_POLL, etc */ - if (milliseconds >= 0) - milliseconds -= (returntime - starttime); + 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; + } -#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 + +#if PRECISE_GETTIME && HAVE_NANOSLEEP + /* + * 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); /* FIXME: this won't be right if I recur! */ + milliseconds -= 100; + goto retry; + } #endif - /* return approximate time left in milliseconds */ - if (timeleft) - *timeleft = milliseconds; - - T(("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; + /* 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); - count++; - } - } + 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 */ + 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; + 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 - } - else - result = 0; - } - return (result); + return (result); }