lib_twait.c revision 50276
1/****************************************************************************
2 * Copyright (c) 1998 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#if USE_FUNC_POLL
46# include <stropts.h>
47# include <poll.h>
48# if HAVE_SYS_TIME_H
49#  include <sys/time.h>
50# endif
51#elif HAVE_SELECT
52# if HAVE_SYS_TIME_H && HAVE_SYS_TIME_SELECT
53#  include <sys/time.h>
54# endif
55# if HAVE_SYS_SELECT_H
56#  include <sys/select.h>
57# endif
58#endif
59
60#ifdef __BEOS__
61/* BeOS select() only works on sockets.  Use the tty hack instead */
62#include <socket.h>
63#define select check_select
64#endif
65
66MODULE_ID("$Id: lib_twait.c,v 1.32 1998/06/06 22:44:14 tom Exp $")
67
68static int _nc_gettime(void)
69{
70	int res;
71
72#if HAVE_GETTIMEOFDAY
73# define PRECISE_GETTIME 1
74	struct timeval t;
75	gettimeofday(&t, (struct timezone *)0);
76	res = t.tv_sec*1000 + t.tv_usec/1000;
77#else
78# define PRECISE_GETTIME 0
79	res = time(0)*1000;
80#endif
81	T(("time: %d msec", res));
82	return res;
83}
84
85/*
86 * Wait a specified number of milliseconds, returning nonzero if the timer
87 * didn't expire before there is activity on the specified file descriptors.
88 * The file-descriptors are specified by the mode:
89 *	0 - none (absolute time)
90 *	1 - ncurses' normal input-descriptor
91 *	2 - mouse descriptor, if any
92 *	3 - either input or mouse.
93 * We return a mask that corresponds to the mode (e.g., 2 for mouse activity).
94 *
95 * If the milliseconds given are -1, the wait blocks until activity on the
96 * descriptors.
97 */
98int _nc_timed_wait(int mode, int milliseconds, int *timeleft)
99{
100int	fd;
101int	count;
102
103int result;
104
105#if USE_FUNC_POLL
106struct pollfd fds[2];
107#elif HAVE_SELECT
108static fd_set set;
109#endif
110
111int starttime, returntime;
112
113	T(("start twait: %d milliseconds, mode: %d", milliseconds, mode));
114
115#if PRECISE_GETTIME
116retry:
117#endif
118	starttime = _nc_gettime();
119
120	count = 0;
121
122#if USE_FUNC_POLL
123	if (mode & 1) {
124		fds[count].fd     = SP->_ifd;
125		fds[count].events = POLLIN;
126		count++;
127	}
128	if ((mode & 2)
129	 && (fd = SP->_mouse_fd) >= 0) {
130		fds[count].fd     = fd;
131		fds[count].events = POLLIN;
132		count++;
133	}
134	result = poll(fds, count, milliseconds);
135
136#elif HAVE_SELECT
137	/*
138	 * select() modifies the fd_set arguments; do this in the
139	 * loop.
140	 */
141	FD_ZERO(&set);
142
143	if (mode & 1) {
144		FD_SET(SP->_ifd, &set);
145		count = SP->_ifd + 1;
146	}
147	if ((mode & 2)
148	 && (fd = SP->_mouse_fd) >= 0) {
149		FD_SET(fd, &set);
150		count = max(fd, count) + 1;
151	}
152
153	if (milliseconds >= 0) {
154		struct timeval ntimeout;
155		ntimeout.tv_sec  = milliseconds / 1000;
156		ntimeout.tv_usec = (milliseconds % 1000) * 1000;
157		result = select(count, &set, NULL, NULL, &ntimeout);
158	} else {
159		result = select(count, &set, NULL, NULL, NULL);
160	}
161#endif
162
163	returntime = _nc_gettime();
164
165	if (milliseconds >= 0)
166		milliseconds -= returntime-starttime;
167
168#if PRECISE_GETTIME
169	/*
170	 * If the timeout hasn't expired, and we've gotten no data,
171	 * this is probably a system where 'select()' needs to be left
172	 * alone so that it can complete.  Make this process sleep,
173	 * then come back for more.
174	 */
175	if (result == 0 && milliseconds > 100) {
176		napms(100);
177		milliseconds -= 100;
178		goto retry;
179	}
180#endif
181
182	/* return approximate time left in milliseconds */
183	if (timeleft)
184		*timeleft = milliseconds;
185
186	T(("end twait: returned %d (%d), remaining time %d msec",
187		result, errno, milliseconds));
188
189	/*
190	 * Both 'poll()' and 'select()' return the number of file descriptors
191	 * that are active.  Translate this back to the mask that denotes which
192	 * file-descriptors, so that we don't need all of this system-specific
193	 * code everywhere.
194	 */
195	if (result != 0) {
196		if (result > 0) {
197			result = 0;
198#if USE_FUNC_POLL
199			for (count = 0; count < 2; count++) {
200				if ((mode & (1 << count))
201				 && (fds[count].revents & POLLIN)) {
202					result |= (1 << count);
203					count++;
204				}
205			}
206#elif HAVE_SELECT
207			if ((mode & 2)
208			 && (fd = SP->_mouse_fd) >= 0
209			 && FD_ISSET(fd, &set))
210				result |= 2;
211			if ((mode & 1)
212			 && FD_ISSET(SP->_ifd, &set))
213				result |= 1;
214#endif
215		}
216		else
217			result = 0;
218	}
219
220	return (result);
221}
222