lib_twait.c revision 97049
150276Speter/**************************************************************************** 297049Speter * Copyright (c) 1998,1999,2000,2001 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> * 3250276Speter ****************************************************************************/ 3350276Speter 3450276Speter/* 3550276Speter** lib_twait.c 3650276Speter** 3750276Speter** The routine _nc_timed_wait(). 3850276Speter** 3950276Speter** (This file was originally written by Eric Raymond; however except for 4050276Speter** comments, none of the original code remains - T.Dickey). 4150276Speter*/ 4250276Speter 4397049Speter#include <curses.priv.h> 4497049Speter 4556639Speter#ifdef __BEOS__ 4697049Speter#undef false 4797049Speter#undef true 4856639Speter#include <OS.h> 4956639Speter#endif 5056639Speter 5150276Speter#if USE_FUNC_POLL 5250276Speter# if HAVE_SYS_TIME_H 5350276Speter# include <sys/time.h> 5450276Speter# endif 5550276Speter#elif HAVE_SELECT 5650276Speter# if HAVE_SYS_TIME_H && HAVE_SYS_TIME_SELECT 5750276Speter# include <sys/time.h> 5850276Speter# endif 5950276Speter# if HAVE_SYS_SELECT_H 6050276Speter# include <sys/select.h> 6150276Speter# endif 6250276Speter#endif 6350276Speter 6497049SpeterMODULE_ID("$Id: lib_twait.c,v 1.44 2002/04/21 21:06:29 tom Exp $") 6550276Speter 6666963Speterstatic long 6766963Speter_nc_gettime(bool first) 6850276Speter{ 6966963Speter long res; 7050276Speter 7150276Speter#if HAVE_GETTIMEOFDAY 7250276Speter# define PRECISE_GETTIME 1 7366963Speter static struct timeval t0; 7466963Speter struct timeval t1; 7566963Speter gettimeofday(&t1, (struct timezone *) 0); 7666963Speter if (first) { 7766963Speter t0 = t1; 7866963Speter } 7966963Speter res = (t1.tv_sec - t0.tv_sec) * 1000 8066963Speter + (t1.tv_usec - t0.tv_usec) / 1000; 8150276Speter#else 8250276Speter# define PRECISE_GETTIME 0 8366963Speter static time_t t0; 8466963Speter time_t t1 = time((time_t *) 0); 8566963Speter if (first) { 8666963Speter t0 = t1; 8766963Speter } 8866963Speter res = (t1 - t0) * 1000; 8950276Speter#endif 9097049Speter TR(TRACE_IEVENT, ("%s time: %ld msec", first ? "get" : "elapsed", res)); 9166963Speter return res; 9250276Speter} 9350276Speter 9450276Speter/* 9550276Speter * Wait a specified number of milliseconds, returning nonzero if the timer 9650276Speter * didn't expire before there is activity on the specified file descriptors. 9750276Speter * The file-descriptors are specified by the mode: 9850276Speter * 0 - none (absolute time) 9950276Speter * 1 - ncurses' normal input-descriptor 10050276Speter * 2 - mouse descriptor, if any 10150276Speter * 3 - either input or mouse. 10250276Speter * We return a mask that corresponds to the mode (e.g., 2 for mouse activity). 10350276Speter * 10450276Speter * If the milliseconds given are -1, the wait blocks until activity on the 10550276Speter * descriptors. 10650276Speter */ 10776726SpeterNCURSES_EXPORT(int) 10897049Speter_nc_timed_wait(int mode, int milliseconds, int *timeleft) 10950276Speter{ 11066963Speter int fd; 11166963Speter int count; 11250276Speter 11366963Speter int result; 11450276Speter 11550276Speter#if USE_FUNC_POLL 11666963Speter struct pollfd fds[2]; 11756639Speter#elif defined(__BEOS__) 11850276Speter#elif HAVE_SELECT 11966963Speter static fd_set set; 12050276Speter#endif 12150276Speter 12266963Speter long starttime, returntime; 12350276Speter 12497049Speter if (milliseconds < 0) 12597049Speter milliseconds = 0; 12697049Speter TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d", 12797049Speter milliseconds, mode)); 12850276Speter 12950276Speter#if PRECISE_GETTIME 13066963Speter retry: 13150276Speter#endif 13266963Speter starttime = _nc_gettime(TRUE); 13350276Speter 13466963Speter count = 0; 13550276Speter 13650276Speter#if USE_FUNC_POLL 13766963Speter memset(fds, 0, sizeof(fds)); 13866963Speter if (mode & 1) { 13966963Speter fds[count].fd = SP->_ifd; 14066963Speter fds[count].events = POLLIN; 14166963Speter count++; 14266963Speter } 14366963Speter if ((mode & 2) 14466963Speter && (fd = SP->_mouse_fd) >= 0) { 14566963Speter fds[count].fd = fd; 14666963Speter fds[count].events = POLLIN; 14766963Speter count++; 14866963Speter } 14966963Speter result = poll(fds, count, milliseconds); 15050276Speter 15156639Speter#elif defined(__BEOS__) 15266963Speter /* 15366963Speter * BeOS's select() is declared in socket.h, so the configure script does 15466963Speter * not see it. That's just as well, since that function works only for 15566963Speter * sockets. This (using snooze and ioctl) was distilled from Be's patch 15666963Speter * for ncurses which uses a separate thread to simulate select(). 15766963Speter * 15866963Speter * FIXME: the return values from the ioctl aren't very clear if we get 15966963Speter * interrupted. 16066963Speter */ 16166963Speter result = 0; 16266963Speter if (mode & 1) { 16366963Speter bigtime_t d; 16466963Speter bigtime_t useconds = milliseconds * 1000; 16566963Speter int n, howmany; 16656639Speter 16766963Speter if (useconds == 0) /* we're here to go _through_ the loop */ 16866963Speter useconds = 1; 16956639Speter 17066963Speter for (d = 0; d < useconds; d += 5000) { 17166963Speter n = 0; 17266963Speter howmany = ioctl(0, 'ichr', &n); 17366963Speter if (howmany >= 0 && n > 0) { 17466963Speter result = 1; 17566963Speter break; 17666963Speter } 17766963Speter if (useconds > 1) 17866963Speter snooze(5000); 17966963Speter milliseconds -= 5; 18056639Speter } 18166963Speter } else if (milliseconds > 0) { 18266963Speter snooze(milliseconds * 1000); 18366963Speter milliseconds = 0; 18466963Speter } 18550276Speter#elif HAVE_SELECT 18666963Speter /* 18766963Speter * select() modifies the fd_set arguments; do this in the 18866963Speter * loop. 18966963Speter */ 19066963Speter FD_ZERO(&set); 19150276Speter 19266963Speter if (mode & 1) { 19366963Speter FD_SET(SP->_ifd, &set); 19466963Speter count = SP->_ifd + 1; 19566963Speter } 19666963Speter if ((mode & 2) 19766963Speter && (fd = SP->_mouse_fd) >= 0) { 19866963Speter FD_SET(fd, &set); 19966963Speter count = max(fd, count) + 1; 20066963Speter } 20150276Speter 20266963Speter if (milliseconds >= 0) { 20366963Speter struct timeval ntimeout; 20466963Speter ntimeout.tv_sec = milliseconds / 1000; 20566963Speter ntimeout.tv_usec = (milliseconds % 1000) * 1000; 20666963Speter result = select(count, &set, NULL, NULL, &ntimeout); 20766963Speter } else { 20866963Speter result = select(count, &set, NULL, NULL, NULL); 20966963Speter } 21050276Speter#endif 21150276Speter 21266963Speter returntime = _nc_gettime(FALSE); 21350276Speter 21466963Speter if (milliseconds >= 0) 21566963Speter milliseconds -= (returntime - starttime); 21650276Speter 21750276Speter#if PRECISE_GETTIME 21866963Speter /* 21966963Speter * If the timeout hasn't expired, and we've gotten no data, 22066963Speter * this is probably a system where 'select()' needs to be left 22166963Speter * alone so that it can complete. Make this process sleep, 22266963Speter * then come back for more. 22366963Speter */ 22466963Speter if (result == 0 && milliseconds > 100) { 22566963Speter napms(100); 22666963Speter milliseconds -= 100; 22766963Speter goto retry; 22866963Speter } 22950276Speter#endif 23050276Speter 23166963Speter /* return approximate time left in milliseconds */ 23266963Speter if (timeleft) 23366963Speter *timeleft = milliseconds; 23450276Speter 23597049Speter TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec", 23697049Speter result, errno, milliseconds)); 23750276Speter 23866963Speter /* 23966963Speter * Both 'poll()' and 'select()' return the number of file descriptors 24066963Speter * that are active. Translate this back to the mask that denotes which 24166963Speter * file-descriptors, so that we don't need all of this system-specific 24266963Speter * code everywhere. 24366963Speter */ 24466963Speter if (result != 0) { 24566963Speter if (result > 0) { 24666963Speter result = 0; 24750276Speter#if USE_FUNC_POLL 24866963Speter for (count = 0; count < 2; count++) { 24966963Speter if ((mode & (1 << count)) 25066963Speter && (fds[count].revents & POLLIN)) { 25166963Speter result |= (1 << count); 25266963Speter } 25366963Speter } 25456639Speter#elif defined(__BEOS__) 25566963Speter result = 1; /* redundant, but simple */ 25650276Speter#elif HAVE_SELECT 25766963Speter if ((mode & 2) 25866963Speter && (fd = SP->_mouse_fd) >= 0 25966963Speter && FD_ISSET(fd, &set)) 26066963Speter result |= 2; 26166963Speter if ((mode & 1) 26266963Speter && FD_ISSET(SP->_ifd, &set)) 26366963Speter result |= 1; 26450276Speter#endif 26566963Speter } else 26666963Speter result = 0; 26766963Speter } 26850276Speter 26966963Speter return (result); 27050276Speter} 271