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