lib_twait.c revision 97049
1/**************************************************************************** 2 * Copyright (c) 1998,1999,2000,2001 Free Software Foundation, Inc. * 3 * * 4 * Permission is hereby granted, free of charge, to any person obtaining a * 5 * copy of this software and associated documentation files (the * 6 * "Software"), to deal in the Software without restriction, including * 7 * without limitation the rights to use, copy, modify, merge, publish, * 8 * distribute, distribute with modifications, sublicense, and/or sell * 9 * copies of the Software, and to permit persons to whom the Software is * 10 * furnished to do so, subject to the following conditions: * 11 * * 12 * The above copyright notice and this permission notice shall be included * 13 * in all copies or substantial portions of the Software. * 14 * * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 22 * * 23 * Except as contained in this notice, the name(s) of the above copyright * 24 * holders shall not be used in advertising or otherwise to promote the * 25 * sale, use or other dealings in this Software without prior written * 26 * authorization. * 27 ****************************************************************************/ 28 29/**************************************************************************** 30 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 31 * and: Eric S. Raymond <esr@snark.thyrsus.com> * 32 ****************************************************************************/ 33 34/* 35** lib_twait.c 36** 37** The routine _nc_timed_wait(). 38** 39** (This file was originally written by Eric Raymond; however except for 40** comments, none of the original code remains - T.Dickey). 41*/ 42 43#include <curses.priv.h> 44 45#ifdef __BEOS__ 46#undef false 47#undef true 48#include <OS.h> 49#endif 50 51#if USE_FUNC_POLL 52# if HAVE_SYS_TIME_H 53# include <sys/time.h> 54# endif 55#elif HAVE_SELECT 56# if HAVE_SYS_TIME_H && HAVE_SYS_TIME_SELECT 57# include <sys/time.h> 58# endif 59# if HAVE_SYS_SELECT_H 60# include <sys/select.h> 61# endif 62#endif 63 64MODULE_ID("$Id: lib_twait.c,v 1.44 2002/04/21 21:06:29 tom Exp $") 65 66static long 67_nc_gettime(bool first) 68{ 69 long res; 70 71#if HAVE_GETTIMEOFDAY 72# define PRECISE_GETTIME 1 73 static struct timeval t0; 74 struct timeval t1; 75 gettimeofday(&t1, (struct timezone *) 0); 76 if (first) { 77 t0 = t1; 78 } 79 res = (t1.tv_sec - t0.tv_sec) * 1000 80 + (t1.tv_usec - t0.tv_usec) / 1000; 81#else 82# define PRECISE_GETTIME 0 83 static time_t t0; 84 time_t t1 = time((time_t *) 0); 85 if (first) { 86 t0 = t1; 87 } 88 res = (t1 - t0) * 1000; 89#endif 90 TR(TRACE_IEVENT, ("%s time: %ld msec", first ? "get" : "elapsed", res)); 91 return res; 92} 93 94/* 95 * Wait a specified number of milliseconds, returning nonzero if the timer 96 * didn't expire before there is activity on the specified file descriptors. 97 * The file-descriptors are specified by the mode: 98 * 0 - none (absolute time) 99 * 1 - ncurses' normal input-descriptor 100 * 2 - mouse descriptor, if any 101 * 3 - either input or mouse. 102 * We return a mask that corresponds to the mode (e.g., 2 for mouse activity). 103 * 104 * If the milliseconds given are -1, the wait blocks until activity on the 105 * descriptors. 106 */ 107NCURSES_EXPORT(int) 108_nc_timed_wait(int mode, int milliseconds, int *timeleft) 109{ 110 int fd; 111 int count; 112 113 int result; 114 115#if USE_FUNC_POLL 116 struct pollfd fds[2]; 117#elif defined(__BEOS__) 118#elif HAVE_SELECT 119 static fd_set set; 120#endif 121 122 long starttime, returntime; 123 124 if (milliseconds < 0) 125 milliseconds = 0; 126 TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d", 127 milliseconds, mode)); 128 129#if PRECISE_GETTIME 130 retry: 131#endif 132 starttime = _nc_gettime(TRUE); 133 134 count = 0; 135 136#if USE_FUNC_POLL 137 memset(fds, 0, sizeof(fds)); 138 if (mode & 1) { 139 fds[count].fd = SP->_ifd; 140 fds[count].events = POLLIN; 141 count++; 142 } 143 if ((mode & 2) 144 && (fd = SP->_mouse_fd) >= 0) { 145 fds[count].fd = fd; 146 fds[count].events = POLLIN; 147 count++; 148 } 149 result = poll(fds, count, milliseconds); 150 151#elif defined(__BEOS__) 152 /* 153 * BeOS's select() is declared in socket.h, so the configure script does 154 * not see it. That's just as well, since that function works only for 155 * sockets. This (using snooze and ioctl) was distilled from Be's patch 156 * for ncurses which uses a separate thread to simulate select(). 157 * 158 * FIXME: the return values from the ioctl aren't very clear if we get 159 * interrupted. 160 */ 161 result = 0; 162 if (mode & 1) { 163 bigtime_t d; 164 bigtime_t useconds = milliseconds * 1000; 165 int n, howmany; 166 167 if (useconds == 0) /* we're here to go _through_ the loop */ 168 useconds = 1; 169 170 for (d = 0; d < useconds; d += 5000) { 171 n = 0; 172 howmany = ioctl(0, 'ichr', &n); 173 if (howmany >= 0 && n > 0) { 174 result = 1; 175 break; 176 } 177 if (useconds > 1) 178 snooze(5000); 179 milliseconds -= 5; 180 } 181 } else if (milliseconds > 0) { 182 snooze(milliseconds * 1000); 183 milliseconds = 0; 184 } 185#elif HAVE_SELECT 186 /* 187 * select() modifies the fd_set arguments; do this in the 188 * loop. 189 */ 190 FD_ZERO(&set); 191 192 if (mode & 1) { 193 FD_SET(SP->_ifd, &set); 194 count = SP->_ifd + 1; 195 } 196 if ((mode & 2) 197 && (fd = SP->_mouse_fd) >= 0) { 198 FD_SET(fd, &set); 199 count = max(fd, count) + 1; 200 } 201 202 if (milliseconds >= 0) { 203 struct timeval ntimeout; 204 ntimeout.tv_sec = milliseconds / 1000; 205 ntimeout.tv_usec = (milliseconds % 1000) * 1000; 206 result = select(count, &set, NULL, NULL, &ntimeout); 207 } else { 208 result = select(count, &set, NULL, NULL, NULL); 209 } 210#endif 211 212 returntime = _nc_gettime(FALSE); 213 214 if (milliseconds >= 0) 215 milliseconds -= (returntime - starttime); 216 217#if PRECISE_GETTIME 218 /* 219 * If the timeout hasn't expired, and we've gotten no data, 220 * this is probably a system where 'select()' needs to be left 221 * alone so that it can complete. Make this process sleep, 222 * then come back for more. 223 */ 224 if (result == 0 && milliseconds > 100) { 225 napms(100); 226 milliseconds -= 100; 227 goto retry; 228 } 229#endif 230 231 /* return approximate time left in milliseconds */ 232 if (timeleft) 233 *timeleft = milliseconds; 234 235 TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec", 236 result, errno, milliseconds)); 237 238 /* 239 * Both 'poll()' and 'select()' return the number of file descriptors 240 * that are active. Translate this back to the mask that denotes which 241 * file-descriptors, so that we don't need all of this system-specific 242 * code everywhere. 243 */ 244 if (result != 0) { 245 if (result > 0) { 246 result = 0; 247#if USE_FUNC_POLL 248 for (count = 0; count < 2; count++) { 249 if ((mode & (1 << count)) 250 && (fds[count].revents & POLLIN)) { 251 result |= (1 << count); 252 } 253 } 254#elif defined(__BEOS__) 255 result = 1; /* redundant, but simple */ 256#elif HAVE_SELECT 257 if ((mode & 2) 258 && (fd = SP->_mouse_fd) >= 0 259 && FD_ISSET(fd, &set)) 260 result |= 2; 261 if ((mode & 1) 262 && FD_ISSET(SP->_ifd, &set)) 263 result |= 1; 264#endif 265 } else 266 result = 0; 267 } 268 269 return (result); 270} 271