Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libtksh/tcl/tclUnixNotfy.c
1810 views
1
/*
2
* tclUnixNotify.c --
3
*
4
* This file contains Unix-specific procedures for the notifier,
5
* which is the lowest-level part of the Tcl event loop. This file
6
* works together with ../generic/tclNotify.c.
7
*
8
* Copyright (c) 1995 Sun Microsystems, Inc.
9
*
10
* See the file "license.terms" for information on usage and redistribution
11
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12
*
13
* SCCS: @(#) tclUnixNotfy.c 1.31 96/07/23 16:17:29
14
*/
15
16
#include "tclInt.h"
17
#include "tclPort.h"
18
#include <signal.h>
19
20
#ifdef WIN32
21
#undef _DLL
22
#undef VOID
23
#include <windows.h>
24
#define _DLL 1
25
#endif
26
27
#if HAVE_SYS_SELECT_H && !defined(NFDBITS)
28
#include <sys/select.h>
29
#endif
30
31
/*
32
* The information below is used to provide read, write, and
33
* exception masks to select during calls to Tcl_DoOneEvent.
34
*/
35
36
static fd_mask checkMasks[3*MASK_SIZE];
37
/* This array is used to build up the masks
38
* to be used in the next call to select.
39
* Bits are set in response to calls to
40
* Tcl_WatchFile. */
41
static fd_mask readyMasks[3*MASK_SIZE];
42
/* This array reflects the readable/writable
43
* conditions that were found to exist by the
44
* last call to select. */
45
static int numFdBits; /* Number of valid bits in checkMasks
46
* (one more than highest fd for which
47
* Tcl_WatchFile has been called). */
48
49
#if 1
50
static int eventsFound;
51
static int ignoreEvents;
52
#endif
53
54
/*
55
* Static routines in this file:
56
*/
57
58
static int MaskEmpty _ANSI_ARGS_((long *maskPtr));
59
60
extern void TclWinFlushEvents()
61
{
62
ignoreEvents = 1;
63
while (Tcl_DoOneEvent(TCL_DONT_WAIT|TCL_WINDOW_EVENTS|TCL_IDLE_EVENTS)) {
64
}
65
ignoreEvents = 0;
66
}
67
68
/*
69
*----------------------------------------------------------------------
70
*
71
* Tcl_WatchFile --
72
*
73
* Arrange for Tcl_DoOneEvent to include this file in the masks
74
* for the next call to select. This procedure is invoked by
75
* event sources, which are in turn invoked by Tcl_DoOneEvent
76
* before it invokes select.
77
*
78
* Results:
79
* None.
80
*
81
* Side effects:
82
*
83
* The notifier will generate a file event when the I/O channel
84
* given by fd next becomes ready in the way indicated by mask.
85
* If fd is already registered then the old mask will be replaced
86
* with the new one. Once the event is sent, the notifier will
87
* not send any more events about the fd until the next call to
88
* Tcl_NotifyFile.
89
*
90
*----------------------------------------------------------------------
91
*/
92
93
void
94
Tcl_WatchFile(file, mask)
95
Tcl_File file; /* Generic file handle for a stream. */
96
int mask; /* OR'ed combination of TCL_READABLE,
97
* TCL_WRITABLE, and TCL_EXCEPTION:
98
* indicates conditions to wait for
99
* in select. */
100
{
101
int fd, type, index;
102
fd_mask bit;
103
104
fd = (int) Tcl_GetFileInfo(file, &type);
105
106
if (type != TCL_UNIX_FD) {
107
panic("Tcl_WatchFile: unexpected file type");
108
}
109
110
if (fd >= FD_SETSIZE) {
111
panic("Tcl_WatchFile can't handle file id %d", fd);
112
}
113
114
index = fd/(NBBY*sizeof(fd_mask));
115
bit = 1 << (fd%(NBBY*sizeof(fd_mask)));
116
if (mask & TCL_READABLE) {
117
checkMasks[index] |= bit;
118
}
119
if (mask & TCL_WRITABLE) {
120
(checkMasks+MASK_SIZE)[index] |= bit;
121
}
122
if (mask & TCL_EXCEPTION) {
123
(checkMasks+2*(MASK_SIZE))[index] |= bit;
124
}
125
if (numFdBits <= fd) {
126
numFdBits = fd+1;
127
}
128
}
129
130
#if 1
131
extern int Tcl_NumEventsFound()
132
{
133
return eventsFound;
134
}
135
#endif
136
137
/*
138
*----------------------------------------------------------------------
139
*
140
* Tcl_FileReady --
141
*
142
* Indicates what conditions (readable, writable, etc.) were
143
* present on a file the last time the notifier invoked select.
144
* This procedure is typically invoked by event sources to see
145
* if they should queue events.
146
*
147
* Results:
148
* The return value is 0 if none of the conditions specified by mask
149
* was true for fd the last time the system checked. If any of the
150
* conditions were true, then the return value is a mask of those
151
* that were true.
152
*
153
* Side effects:
154
* None.
155
*
156
*----------------------------------------------------------------------
157
*/
158
159
int
160
Tcl_FileReady(file, mask)
161
Tcl_File file; /* Generic file handle for a stream. */
162
int mask; /* OR'ed combination of TCL_READABLE,
163
* TCL_WRITABLE, and TCL_EXCEPTION:
164
* indicates conditions caller cares about. */
165
{
166
int index, result, type, fd;
167
fd_mask bit;
168
169
fd = (int) Tcl_GetFileInfo(file, &type);
170
if (type != TCL_UNIX_FD) {
171
panic("Tcl_FileReady: unexpected file type");
172
}
173
174
index = fd/(NBBY*sizeof(fd_mask));
175
bit = 1 << (fd%(NBBY*sizeof(fd_mask)));
176
result = 0;
177
if ((mask & TCL_READABLE) && (readyMasks[index] & bit)) {
178
result |= TCL_READABLE;
179
}
180
if ((mask & TCL_WRITABLE) && ((readyMasks+MASK_SIZE)[index] & bit)) {
181
result |= TCL_WRITABLE;
182
}
183
if ((mask & TCL_EXCEPTION) && ((readyMasks+(2*MASK_SIZE))[index] & bit)) {
184
result |= TCL_EXCEPTION;
185
}
186
return result;
187
}
188
189
/*
190
*----------------------------------------------------------------------
191
*
192
* MaskEmpty --
193
*
194
* Returns nonzero if mask is empty (has no bits set).
195
*
196
* Results:
197
* Nonzero if the mask is empty, zero otherwise.
198
*
199
* Side effects:
200
* None
201
*
202
*----------------------------------------------------------------------
203
*/
204
205
static int
206
MaskEmpty(maskPtr)
207
long *maskPtr;
208
{
209
long *runPtr, *tailPtr;
210
int found, sz;
211
212
sz = 3 * ((MASK_SIZE) / sizeof(long)) * sizeof(fd_mask);
213
for (runPtr = maskPtr, tailPtr = maskPtr + sz, found = 0;
214
runPtr < tailPtr;
215
runPtr++) {
216
if (*runPtr != 0) {
217
found = 1;
218
break;
219
}
220
}
221
return !found;
222
}
223
224
/*
225
*----------------------------------------------------------------------
226
*
227
* Tcl_WaitForEvent --
228
*
229
* This procedure does the lowest level wait for events in a
230
* platform-specific manner. It uses information provided by
231
* previous calls to Tcl_WatchFile, plus the timePtr argument,
232
* to determine what to wait for and how long to wait.
233
*
234
* Results:
235
* The return value is normally TCL_OK. However, if there are
236
* no events to wait for (e.g. no files and no timers) so that
237
* the procedure would block forever, then it returns TCL_ERROR.
238
*
239
* Side effects:
240
* May put the process to sleep for a while, depending on timePtr.
241
* When this procedure returns, an event of interest to the application
242
* has probably, but not necessarily, occurred.
243
*
244
*----------------------------------------------------------------------
245
*/
246
247
int
248
Tcl_WaitForEvent(timePtr)
249
Tcl_Time *timePtr; /* Specifies the maximum amount of time
250
* that this procedure should block before
251
* returning. The time is given as an
252
* interval, not an absolute wakeup time.
253
* NULL means block forever. */
254
{
255
struct timeval timeout, *timeoutPtr;
256
int numFound;
257
#ifdef WIN32
258
static int winFd = -1;
259
if (ignoreEvents)
260
return TCL_OK;
261
if (winFd < 0)
262
winFd = open("/dev/windows", 0);
263
Tcl_WatchFile(Tcl_GetFile((ClientData)winFd,TCL_UNIX_FD),TCL_READABLE);
264
#endif
265
266
memcpy((VOID *) readyMasks, (VOID *) checkMasks,
267
3*MASK_SIZE*sizeof(fd_mask));
268
if (timePtr == NULL) {
269
if ((numFdBits == 0) || (MaskEmpty((long *) readyMasks))) {
270
return TCL_ERROR;
271
}
272
timeoutPtr = NULL;
273
} else {
274
timeoutPtr = &timeout;
275
timeout.tv_sec = timePtr->sec;
276
timeout.tv_usec = timePtr->usec;
277
}
278
numFound = select(numFdBits, (SELECT_MASK *) &readyMasks[0],
279
(SELECT_MASK *) &readyMasks[MASK_SIZE],
280
(SELECT_MASK *) &readyMasks[2*MASK_SIZE], timeoutPtr);
281
282
#ifdef WIN32
283
if (FD_ISSET(winFd, ((SELECT_MASK *) &readyMasks[0])))
284
{
285
MSG msg;
286
GetMessage(&msg, NULL, 0, 0);
287
TranslateMessage(&msg);
288
DispatchMessage(&msg);
289
}
290
#endif
291
292
/*
293
* Some systems don't clear the masks after an error, so
294
* we have to do it here.
295
*/
296
297
eventsFound = numFound;
298
if (numFound == -1) {
299
memset((VOID *) readyMasks, 0, 3*MASK_SIZE*sizeof(fd_mask));
300
}
301
302
/*
303
* Reset the check masks in preparation for the next call to
304
* select.
305
*/
306
307
numFdBits = 0;
308
memset((VOID *) checkMasks, 0, 3*MASK_SIZE*sizeof(fd_mask));
309
return TCL_OK;
310
}
311
312
/*
313
*----------------------------------------------------------------------
314
*
315
* Tcl_Sleep --
316
*
317
* Delay execution for the specified number of milliseconds.
318
*
319
* Results:
320
* None.
321
*
322
* Side effects:
323
* Time passes.
324
*
325
*----------------------------------------------------------------------
326
*/
327
328
void
329
Tcl_Sleep(ms)
330
int ms; /* Number of milliseconds to sleep. */
331
{
332
static struct timeval delay;
333
Tcl_Time before, after;
334
335
/*
336
* The only trick here is that select appears to return early
337
* under some conditions, so we have to check to make sure that
338
* the right amount of time really has elapsed. If it's too
339
* early, go back to sleep again.
340
*/
341
342
TclpGetTime(&before);
343
after = before;
344
after.sec += ms/1000;
345
after.usec += (ms%1000)*1000;
346
if (after.usec > 1000000) {
347
after.usec -= 1000000;
348
after.sec += 1;
349
}
350
while (1) {
351
delay.tv_sec = after.sec - before.sec;
352
delay.tv_usec = after.usec - before.usec;
353
if (delay.tv_usec < 0) {
354
delay.tv_usec += 1000000;
355
delay.tv_sec -= 1;
356
}
357
358
/*
359
* Special note: must convert delay.tv_sec to int before comparing
360
* to zero, since delay.tv_usec is unsigned on some platforms.
361
*/
362
363
if ((((int) delay.tv_sec) < 0)
364
|| ((delay.tv_usec == 0) && (delay.tv_sec == 0))) {
365
break;
366
}
367
(void) select(0, (SELECT_MASK *) 0, (SELECT_MASK *) 0,
368
(SELECT_MASK *) 0, &delay);
369
TclpGetTime(&before);
370
}
371
}
372
373
374