150276Speter/**************************************************************************** 2178866Srafan * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc. * 350276Speter * * 450276Speter * Permission is hereby granted, free of charge, to any person obtaining a * 550276Speter * copy of this software and associated documentation files (the * 650276Speter * "Software"), to deal in the Software without restriction, including * 750276Speter * without limitation the rights to use, copy, modify, merge, publish, * 850276Speter * distribute, distribute with modifications, sublicense, and/or sell * 950276Speter * copies of the Software, and to permit persons to whom the Software is * 1050276Speter * furnished to do so, subject to the following conditions: * 1150276Speter * * 1250276Speter * The above copyright notice and this permission notice shall be included * 1350276Speter * in all copies or substantial portions of the Software. * 1450276Speter * * 1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 2250276Speter * * 2350276Speter * Except as contained in this notice, the name(s) of the above copyright * 2450276Speter * holders shall not be used in advertising or otherwise to promote the * 2550276Speter * sale, use or other dealings in this Software without prior written * 2650276Speter * authorization. * 2750276Speter ****************************************************************************/ 2850276Speter 2950276Speter/**************************************************************************** 3050276Speter * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 3150276Speter * and: Eric S. Raymond <esr@snark.thyrsus.com> * 32174993Srafan * and: Thomas E. Dickey 1996-on * 3350276Speter ****************************************************************************/ 3450276Speter 3550276Speter/* 3650276Speter** lib_twait.c 3750276Speter** 3850276Speter** The routine _nc_timed_wait(). 3950276Speter** 4050276Speter** (This file was originally written by Eric Raymond; however except for 4150276Speter** comments, none of the original code remains - T.Dickey). 4250276Speter*/ 4350276Speter 4497049Speter#include <curses.priv.h> 4597049Speter 46184989Srafan#if defined __HAIKU__ && defined __BEOS__ 47184989Srafan#undef __BEOS__ 48184989Srafan#endif 49184989Srafan 5056639Speter#ifdef __BEOS__ 5197049Speter#undef false 5297049Speter#undef true 5356639Speter#include <OS.h> 5456639Speter#endif 5556639Speter 5650276Speter#if USE_FUNC_POLL 5750276Speter# if HAVE_SYS_TIME_H 5850276Speter# include <sys/time.h> 5950276Speter# endif 6050276Speter#elif HAVE_SELECT 6150276Speter# if HAVE_SYS_TIME_H && HAVE_SYS_TIME_SELECT 6250276Speter# include <sys/time.h> 6350276Speter# endif 6450276Speter# if HAVE_SYS_SELECT_H 6550276Speter# include <sys/select.h> 6650276Speter# endif 6750276Speter#endif 6850276Speter 69184989Srafan#undef CUR 7050276Speter 71184989SrafanMODULE_ID("$Id: lib_twait.c,v 1.59 2008/08/30 20:08:19 tom Exp $") 72184989Srafan 7366963Speterstatic long 74174993Srafan_nc_gettime(TimeType * t0, bool first) 7550276Speter{ 7666963Speter long res; 7750276Speter 78174993Srafan#if PRECISE_GETTIME 79174993Srafan TimeType t1; 8066963Speter gettimeofday(&t1, (struct timezone *) 0); 8166963Speter if (first) { 82174993Srafan *t0 = t1; 83166124Srafan res = 0; 84166124Srafan } else { 85166124Srafan /* .tv_sec and .tv_usec are unsigned, be careful when subtracting */ 86174993Srafan if (t0->tv_usec > t1.tv_usec) { 87174993Srafan t1.tv_usec += 1000000; /* Convert 1s in 1e6 microsecs */ 88166124Srafan t1.tv_sec--; 89166124Srafan } 90174993Srafan res = (t1.tv_sec - t0->tv_sec) * 1000 91174993Srafan + (t1.tv_usec - t0->tv_usec) / 1000; 9266963Speter } 9350276Speter#else 9466963Speter time_t t1 = time((time_t *) 0); 9566963Speter if (first) { 96174993Srafan *t0 = t1; 9766963Speter } 98174993Srafan res = (t1 - *t0) * 1000; 9950276Speter#endif 10097049Speter TR(TRACE_IEVENT, ("%s time: %ld msec", first ? "get" : "elapsed", res)); 10166963Speter return res; 10250276Speter} 10350276Speter 104166124Srafan#ifdef NCURSES_WGETCH_EVENTS 105166124SrafanNCURSES_EXPORT(int) 106166124Srafan_nc_eventlist_timeout(_nc_eventlist * evl) 107166124Srafan{ 108166124Srafan int event_delay = -1; 109166124Srafan int n; 110166124Srafan 111166124Srafan if (evl != 0) { 112166124Srafan 113166124Srafan for (n = 0; n < evl->count; ++n) { 114166124Srafan _nc_event *ev = evl->events[n]; 115166124Srafan 116166124Srafan if (ev->type == _NC_EVENT_TIMEOUT_MSEC) { 117166124Srafan event_delay = ev->data.timeout_msec; 118166124Srafan if (event_delay < 0) 119166124Srafan event_delay = INT_MAX; /* FIXME Is this defined? */ 120166124Srafan } 121166124Srafan } 122166124Srafan } 123166124Srafan return event_delay; 124166124Srafan} 125166124Srafan#endif /* NCURSES_WGETCH_EVENTS */ 126166124Srafan 12750276Speter/* 12850276Speter * Wait a specified number of milliseconds, returning nonzero if the timer 12950276Speter * didn't expire before there is activity on the specified file descriptors. 13050276Speter * The file-descriptors are specified by the mode: 13150276Speter * 0 - none (absolute time) 13250276Speter * 1 - ncurses' normal input-descriptor 13350276Speter * 2 - mouse descriptor, if any 13450276Speter * 3 - either input or mouse. 135166124Srafan * 136166124Srafan * Experimental: if NCURSES_WGETCH_EVENTS is defined, (mode & 4) determines 137166124Srafan * whether to pay attention to evl argument. If set, the smallest of 138166124Srafan * millisecond and of timeout of evl is taken. 139166124Srafan * 14050276Speter * We return a mask that corresponds to the mode (e.g., 2 for mouse activity). 14150276Speter * 14250276Speter * If the milliseconds given are -1, the wait blocks until activity on the 14350276Speter * descriptors. 14450276Speter */ 14576726SpeterNCURSES_EXPORT(int) 146178866Srafan_nc_timed_wait(SCREEN *sp, 147178866Srafan int mode, 148166124Srafan int milliseconds, 149166124Srafan int *timeleft 150166124Srafan EVENTLIST_2nd(_nc_eventlist * evl)) 15150276Speter{ 15266963Speter int fd; 15366963Speter int count; 154174993Srafan int result = 0; 155174993Srafan TimeType t0; 15650276Speter 157166124Srafan#ifdef NCURSES_WGETCH_EVENTS 158166124Srafan int timeout_is_event = 0; 159166124Srafan int n; 160166124Srafan#endif 161166124Srafan 16250276Speter#if USE_FUNC_POLL 163166124Srafan#define MIN_FDS 2 164166124Srafan struct pollfd fd_list[MIN_FDS]; 165166124Srafan struct pollfd *fds = fd_list; 16656639Speter#elif defined(__BEOS__) 16750276Speter#elif HAVE_SELECT 168174993Srafan fd_set set; 16950276Speter#endif 17050276Speter 17166963Speter long starttime, returntime; 17250276Speter 17397049Speter TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d", 17497049Speter milliseconds, mode)); 17550276Speter 176166124Srafan#ifdef NCURSES_WGETCH_EVENTS 177166124Srafan if (mode & 4) { 178166124Srafan int event_delay = _nc_eventlist_timeout(evl); 179166124Srafan 180166124Srafan if (event_delay >= 0 181166124Srafan && (milliseconds >= event_delay || milliseconds < 0)) { 182166124Srafan milliseconds = event_delay; 183166124Srafan timeout_is_event = 1; 184166124Srafan } 185166124Srafan } 186166124Srafan#endif 187166124Srafan 188174993Srafan#if PRECISE_GETTIME && HAVE_NANOSLEEP 18966963Speter retry: 19050276Speter#endif 191174993Srafan starttime = _nc_gettime(&t0, TRUE); 19250276Speter 19366963Speter count = 0; 19450276Speter 195166124Srafan#ifdef NCURSES_WGETCH_EVENTS 196166124Srafan if ((mode & 4) && evl) 197166124Srafan evl->result_flags = 0; 198166124Srafan#endif 199166124Srafan 20050276Speter#if USE_FUNC_POLL 201166124Srafan memset(fd_list, 0, sizeof(fd_list)); 202166124Srafan 203166124Srafan#ifdef NCURSES_WGETCH_EVENTS 204166124Srafan if ((mode & 4) && evl) 205166124Srafan fds = typeMalloc(struct pollfd, MIN_FDS + evl->count); 206166124Srafan#endif 207166124Srafan 20866963Speter if (mode & 1) { 209178866Srafan fds[count].fd = sp->_ifd; 21066963Speter fds[count].events = POLLIN; 21166963Speter count++; 21266963Speter } 21366963Speter if ((mode & 2) 214178866Srafan && (fd = sp->_mouse_fd) >= 0) { 21566963Speter fds[count].fd = fd; 21666963Speter fds[count].events = POLLIN; 21766963Speter count++; 21866963Speter } 219166124Srafan#ifdef NCURSES_WGETCH_EVENTS 220166124Srafan if ((mode & 4) && evl) { 221166124Srafan for (n = 0; n < evl->count; ++n) { 222166124Srafan _nc_event *ev = evl->events[n]; 22350276Speter 224166124Srafan if (ev->type == _NC_EVENT_FILE 225166124Srafan && (ev->data.fev.flags & _NC_EVENT_FILE_READABLE)) { 226166124Srafan fds[count].fd = ev->data.fev.fd; 227166124Srafan fds[count].events = POLLIN; 228166124Srafan count++; 229166124Srafan } 230166124Srafan } 231166124Srafan } 232166124Srafan#endif 233166124Srafan 234166124Srafan result = poll(fds, (unsigned) count, milliseconds); 235166124Srafan 236166124Srafan#ifdef NCURSES_WGETCH_EVENTS 237166124Srafan if ((mode & 4) && evl) { 238166124Srafan int c; 239166124Srafan 240166124Srafan if (!result) 241166124Srafan count = 0; 242166124Srafan 243166124Srafan for (n = 0; n < evl->count; ++n) { 244166124Srafan _nc_event *ev = evl->events[n]; 245166124Srafan 246166124Srafan if (ev->type == _NC_EVENT_FILE 247166124Srafan && (ev->data.fev.flags & _NC_EVENT_FILE_READABLE)) { 248166124Srafan ev->data.fev.result = 0; 249166124Srafan for (c = 0; c < count; c++) 250166124Srafan if (fds[c].fd == ev->data.fev.fd 251166124Srafan && fds[c].revents & POLLIN) { 252166124Srafan ev->data.fev.result |= _NC_EVENT_FILE_READABLE; 253166124Srafan evl->result_flags |= _NC_EVENT_FILE_READABLE; 254166124Srafan } 255166124Srafan } else if (ev->type == _NC_EVENT_TIMEOUT_MSEC 256166124Srafan && !result && timeout_is_event) { 257166124Srafan evl->result_flags |= _NC_EVENT_TIMEOUT_MSEC; 258166124Srafan } 259166124Srafan } 260166124Srafan } 261166124Srafan 262166124Srafan if (fds != fd_list) 263166124Srafan free((char *) fds); 264166124Srafan 265166124Srafan#endif 266166124Srafan 26756639Speter#elif defined(__BEOS__) 26866963Speter /* 26966963Speter * BeOS's select() is declared in socket.h, so the configure script does 27066963Speter * not see it. That's just as well, since that function works only for 27166963Speter * sockets. This (using snooze and ioctl) was distilled from Be's patch 27266963Speter * for ncurses which uses a separate thread to simulate select(). 27366963Speter * 27466963Speter * FIXME: the return values from the ioctl aren't very clear if we get 27566963Speter * interrupted. 276166124Srafan * 277166124Srafan * FIXME: this assumes mode&1 if milliseconds < 0 (see lib_getch.c). 27866963Speter */ 27966963Speter result = 0; 28066963Speter if (mode & 1) { 281166124Srafan int step = (milliseconds < 0) ? 0 : 5000; 28266963Speter bigtime_t d; 28366963Speter bigtime_t useconds = milliseconds * 1000; 28466963Speter int n, howmany; 28556639Speter 286166124Srafan if (useconds <= 0) /* we're here to go _through_ the loop */ 28766963Speter useconds = 1; 28856639Speter 289166124Srafan for (d = 0; d < useconds; d += step) { 29066963Speter n = 0; 29166963Speter howmany = ioctl(0, 'ichr', &n); 29266963Speter if (howmany >= 0 && n > 0) { 29366963Speter result = 1; 29466963Speter break; 29566963Speter } 296166124Srafan if (useconds > 1 && step > 0) { 297166124Srafan snooze(step); 298166124Srafan milliseconds -= (step / 1000); 299166124Srafan if (milliseconds <= 0) { 300166124Srafan milliseconds = 0; 301166124Srafan break; 302166124Srafan } 303166124Srafan } 30456639Speter } 30566963Speter } else if (milliseconds > 0) { 30666963Speter snooze(milliseconds * 1000); 30766963Speter milliseconds = 0; 30866963Speter } 30950276Speter#elif HAVE_SELECT 31066963Speter /* 31166963Speter * select() modifies the fd_set arguments; do this in the 31266963Speter * loop. 31366963Speter */ 31466963Speter FD_ZERO(&set); 31550276Speter 31666963Speter if (mode & 1) { 317178866Srafan FD_SET(sp->_ifd, &set); 318178866Srafan count = sp->_ifd + 1; 31966963Speter } 32066963Speter if ((mode & 2) 321178866Srafan && (fd = sp->_mouse_fd) >= 0) { 32266963Speter FD_SET(fd, &set); 32366963Speter count = max(fd, count) + 1; 32466963Speter } 325166124Srafan#ifdef NCURSES_WGETCH_EVENTS 326166124Srafan if ((mode & 4) && evl) { 327166124Srafan for (n = 0; n < evl->count; ++n) { 328166124Srafan _nc_event *ev = evl->events[n]; 32950276Speter 330166124Srafan if (ev->type == _NC_EVENT_FILE 331166124Srafan && (ev->data.fev.flags & _NC_EVENT_FILE_READABLE)) { 332166124Srafan FD_SET(ev->data.fev.fd, &set); 333166124Srafan count = max(ev->data.fev.fd + 1, count); 334166124Srafan } 335166124Srafan } 336166124Srafan } 337166124Srafan#endif 338166124Srafan 33966963Speter if (milliseconds >= 0) { 34066963Speter struct timeval ntimeout; 34166963Speter ntimeout.tv_sec = milliseconds / 1000; 34266963Speter ntimeout.tv_usec = (milliseconds % 1000) * 1000; 34366963Speter result = select(count, &set, NULL, NULL, &ntimeout); 34466963Speter } else { 34566963Speter result = select(count, &set, NULL, NULL, NULL); 34666963Speter } 347166124Srafan 348166124Srafan#ifdef NCURSES_WGETCH_EVENTS 349166124Srafan if ((mode & 4) && evl) { 350166124Srafan evl->result_flags = 0; 351166124Srafan for (n = 0; n < evl->count; ++n) { 352166124Srafan _nc_event *ev = evl->events[n]; 353166124Srafan 354166124Srafan if (ev->type == _NC_EVENT_FILE 355166124Srafan && (ev->data.fev.flags & _NC_EVENT_FILE_READABLE)) { 356166124Srafan ev->data.fev.result = 0; 357166124Srafan if (FD_ISSET(ev->data.fev.fd, &set)) { 358166124Srafan ev->data.fev.result |= _NC_EVENT_FILE_READABLE; 359166124Srafan evl->result_flags |= _NC_EVENT_FILE_READABLE; 360166124Srafan } 361166124Srafan } else if (ev->type == _NC_EVENT_TIMEOUT_MSEC 362166124Srafan && !result && timeout_is_event) 363166124Srafan evl->result_flags |= _NC_EVENT_TIMEOUT_MSEC; 364166124Srafan } 365166124Srafan } 36650276Speter#endif 36750276Speter 368166124Srafan#endif /* USE_FUNC_POLL, etc */ 369166124Srafan 370174993Srafan returntime = _nc_gettime(&t0, FALSE); 37150276Speter 37266963Speter if (milliseconds >= 0) 37366963Speter milliseconds -= (returntime - starttime); 37450276Speter 375166124Srafan#ifdef NCURSES_WGETCH_EVENTS 376166124Srafan if (evl) { 377166124Srafan evl->result_flags = 0; 378166124Srafan for (n = 0; n < evl->count; ++n) { 379166124Srafan _nc_event *ev = evl->events[n]; 380166124Srafan 381166124Srafan if (ev->type == _NC_EVENT_TIMEOUT_MSEC) { 382166124Srafan long diff = (returntime - starttime); 383166124Srafan if (ev->data.timeout_msec <= diff) 384166124Srafan ev->data.timeout_msec = 0; 385166124Srafan else 386166124Srafan ev->data.timeout_msec -= diff; 387166124Srafan } 388166124Srafan 389166124Srafan } 390166124Srafan } 391166124Srafan#endif 392166124Srafan 393166124Srafan#if PRECISE_GETTIME && HAVE_NANOSLEEP 39466963Speter /* 39566963Speter * If the timeout hasn't expired, and we've gotten no data, 39666963Speter * this is probably a system where 'select()' needs to be left 39766963Speter * alone so that it can complete. Make this process sleep, 39866963Speter * then come back for more. 39966963Speter */ 40066963Speter if (result == 0 && milliseconds > 100) { 401166124Srafan napms(100); /* FIXME: this won't be right if I recur! */ 40266963Speter milliseconds -= 100; 40366963Speter goto retry; 40466963Speter } 40550276Speter#endif 40650276Speter 40766963Speter /* return approximate time left in milliseconds */ 40866963Speter if (timeleft) 40966963Speter *timeleft = milliseconds; 41050276Speter 41197049Speter TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec", 41297049Speter result, errno, milliseconds)); 41350276Speter 41466963Speter /* 41566963Speter * Both 'poll()' and 'select()' return the number of file descriptors 41666963Speter * that are active. Translate this back to the mask that denotes which 41766963Speter * file-descriptors, so that we don't need all of this system-specific 41866963Speter * code everywhere. 41966963Speter */ 42066963Speter if (result != 0) { 42166963Speter if (result > 0) { 42266963Speter result = 0; 42350276Speter#if USE_FUNC_POLL 424166124Srafan for (count = 0; count < MIN_FDS; count++) { 42566963Speter if ((mode & (1 << count)) 42666963Speter && (fds[count].revents & POLLIN)) { 42766963Speter result |= (1 << count); 42866963Speter } 42966963Speter } 43056639Speter#elif defined(__BEOS__) 43166963Speter result = 1; /* redundant, but simple */ 43250276Speter#elif HAVE_SELECT 43366963Speter if ((mode & 2) 434178866Srafan && (fd = sp->_mouse_fd) >= 0 43566963Speter && FD_ISSET(fd, &set)) 43666963Speter result |= 2; 43766963Speter if ((mode & 1) 438178866Srafan && FD_ISSET(sp->_ifd, &set)) 43966963Speter result |= 1; 44050276Speter#endif 44166963Speter } else 44266963Speter result = 0; 44366963Speter } 444166124Srafan#ifdef NCURSES_WGETCH_EVENTS 445166124Srafan if ((mode & 4) && evl && evl->result_flags) 446166124Srafan result |= 4; 447166124Srafan#endif 44850276Speter 44966963Speter return (result); 45050276Speter} 451