resetting manifest requested domain to floor
[platform/upstream/expect.git] / exp_simple.c
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
14 static char sccsid[] = "@(#) tclUnixNotify.c 1.27 96/01/19 10:30:23";
15
16 #include "tclInt.h"
17 #include "tclPort.h"
18 #include <signal.h> 
19
20 /*
21  * The information below is used to provide read, write, and
22  * exception masks to select during calls to Tcl_DoOneEvent.
23  */
24
25 static fd_mask checkMasks[3*MASK_SIZE];
26                                 /* This array is used to build up the masks
27                                  * to be used in the next call to select.
28                                  * Bits are set in response to calls to
29                                  * Tcl_WatchFile. */
30 static fd_mask readyMasks[3*MASK_SIZE];
31                                 /* This array reflects the readable/writable
32                                  * conditions that were found to exist by the
33                                  * last call to select. */
34 static int numFdBits;           /* Number of valid bits in checkMasks
35                                  * (one more than highest fd for which
36                                  * Tcl_WatchFile has been called). */
37 \f
38 /*
39  *----------------------------------------------------------------------
40  *
41  * Tcl_WatchFile --
42  *
43  *      Arrange for Tcl_DoOneEvent to include this file in the masks
44  *      for the next call to select.  This procedure is invoked by
45  *      event sources, which are in turn invoked by Tcl_DoOneEvent
46  *      before it invokes select.
47  *
48  * Results:
49  *      None.
50  *
51  * Side effects:
52  *      
53  *      The notifier will generate a file event when the I/O channel
54  *      given by fd next becomes ready in the way indicated by mask.
55  *      If fd is already registered then the old mask will be replaced
56  *      with the new one.  Once the event is sent, the notifier will
57  *      not send any more events about the fd until the next call to
58  *      Tcl_NotifyFile. 
59  *
60  *----------------------------------------------------------------------
61  */
62
63 void
64 Tcl_WatchFile(file, mask)
65     Tcl_File file;      /* Generic file handle for a stream. */
66     int mask;                   /* OR'ed combination of TCL_READABLE,
67                                  * TCL_WRITABLE, and TCL_EXCEPTION:
68                                  * indicates conditions to wait for
69                                  * in select. */
70 {
71     int fd, type, index;
72     fd_mask bit;
73
74     fd = (int) Tcl_GetFileInfo(file, &type);
75
76     if (type != TCL_UNIX_FD) {
77         panic("Tcl_WatchFile: unexpected file type");
78     }
79
80     if (fd >= FD_SETSIZE) {
81         panic("Tcl_WatchFile can't handle file id %d", fd);
82     }
83
84     index = fd/(NBBY*sizeof(fd_mask));
85     bit = 1 << (fd%(NBBY*sizeof(fd_mask)));
86     if (mask & TCL_READABLE) {
87         checkMasks[index] |= bit;
88     }
89     if (mask & TCL_WRITABLE) {
90         (checkMasks+MASK_SIZE)[index] |= bit;
91     }
92     if (mask & TCL_EXCEPTION) {
93         (checkMasks+2*(MASK_SIZE))[index] |= bit;
94     }
95     if (numFdBits <= fd) {
96         numFdBits = fd+1;
97     }
98 }
99 \f
100 /*
101  *----------------------------------------------------------------------
102  *
103  * Tcl_FileReady --
104  *
105  *      Indicates what conditions (readable, writable, etc.) were
106  *      present on a file the last time the notifier invoked select.
107  *      This procedure is typically invoked by event sources to see
108  *      if they should queue events.
109  *
110  * Results:
111  *      The return value is 0 if none of the conditions specified by mask
112  *      was true for fd the last time the system checked.  If any of the
113  *      conditions were true, then the return value is a mask of those
114  *      that were true.
115  *
116  * Side effects:
117  *      None.
118  *
119  *----------------------------------------------------------------------
120  */
121
122 int
123 Tcl_FileReady(file, mask)
124     Tcl_File file;      /* Generic file handle for a stream. */
125     int mask;                   /* OR'ed combination of TCL_READABLE,
126                                  * TCL_WRITABLE, and TCL_EXCEPTION:
127                                  * indicates conditions caller cares about. */
128 {
129     int index, result, type, fd;
130     fd_mask bit;
131
132     fd = (int) Tcl_GetFileInfo(file, &type);
133     if (type != TCL_UNIX_FD) {
134         panic("Tcl_FileReady: unexpected file type");
135     }
136
137     index = fd/(NBBY*sizeof(fd_mask));
138     bit = 1 << (fd%(NBBY*sizeof(fd_mask)));
139     result = 0;
140     if ((mask & TCL_READABLE) && (readyMasks[index] & bit)) {
141         result |= TCL_READABLE;
142     }
143     if ((mask & TCL_WRITABLE) && ((readyMasks+MASK_SIZE)[index] & bit)) {
144         result |= TCL_WRITABLE;
145     }
146     if ((mask & TCL_EXCEPTION) && ((readyMasks+(2*MASK_SIZE))[index] & bit)) {
147         result |= TCL_EXCEPTION;
148     }
149     return result;
150 }
151 \f
152 /*
153  *----------------------------------------------------------------------
154  *
155  * Tcl_WaitForEvent --
156  *
157  *      This procedure does the lowest level wait for events in a
158  *      platform-specific manner.  It uses information provided by
159  *      previous calls to Tcl_WatchFile, plus the timePtr argument,
160  *      to determine what to wait for and how long to wait.
161  *
162  * Results:
163  *      None.
164  *
165  * Side effects:
166  *      May put the process to sleep for a while, depending on timePtr.
167  *      When this procedure returns, an event of interest to the application
168  *      has probably, but not necessarily, occurred.
169  *
170  *----------------------------------------------------------------------
171  */
172
173 void
174 Tcl_WaitForEvent(timePtr)
175     Tcl_Time *timePtr;          /* Specifies the maximum amount of time
176                                  * that this procedure should block before
177                                  * returning.  The time is given as an
178                                  * interval, not an absolute wakeup time.
179                                  * NULL means block forever. */
180 {
181     struct timeval timeout, *timeoutPtr;
182     int numFound;
183
184     memcpy((VOID *) readyMasks, (VOID *) checkMasks,
185             3*MASK_SIZE*sizeof(fd_mask));
186     if (timePtr == NULL) {
187         timeoutPtr = NULL;
188     } else {
189         timeoutPtr = &timeout;
190         timeout.tv_sec = timePtr->sec;
191         timeout.tv_usec = timePtr->usec;
192     }
193     numFound = select(numFdBits, (SELECT_MASK *) &readyMasks[0],
194             (SELECT_MASK *) &readyMasks[MASK_SIZE],
195             (SELECT_MASK *) &readyMasks[2*MASK_SIZE], timeoutPtr);
196
197     /*
198      * Some systems don't clear the masks after an error, so
199      * we have to do it here.
200      */
201
202     if (numFound == -1) {
203         memset((VOID *) readyMasks, 0, 3*MASK_SIZE*sizeof(fd_mask));
204     }
205
206     /*
207      * Reset the check masks in preparation for the next call to
208      * select.
209      */
210
211     numFdBits = 0;
212     memset((VOID *) checkMasks, 0, 3*MASK_SIZE*sizeof(fd_mask));
213 }
214 \f
215 /*
216  *----------------------------------------------------------------------
217  *
218  * Tcl_Sleep --
219  *
220  *      Delay execution for the specified number of milliseconds.
221  *
222  * Results:
223  *      None.
224  *
225  * Side effects:
226  *      Time passes.
227  *
228  *----------------------------------------------------------------------
229  */
230
231 void
232 Tcl_Sleep(ms)
233     int ms;                     /* Number of milliseconds to sleep. */
234 {
235     static struct timeval delay;
236     Tcl_Time before, after;
237
238     /*
239      * The only trick here is that select appears to return early
240      * under some conditions, so we have to check to make sure that
241      * the right amount of time really has elapsed.  If it's too
242      * early, go back to sleep again.
243      */
244
245     TclGetTime(&before);
246     after = before;
247     after.sec += ms/1000;
248     after.usec += (ms%1000)*1000;
249     if (after.usec > 1000000) {
250         after.usec -= 1000000;
251         after.sec += 1;
252     }
253     while (1) {
254         delay.tv_sec = after.sec - before.sec;
255         delay.tv_usec = after.usec - before.usec;
256         if (delay.tv_usec < 0) {
257             delay.tv_usec += 1000000;
258             delay.tv_sec -= 1;
259         }
260
261         /*
262          * Special note:  must convert delay.tv_sec to int before comparing
263          * to zero, since delay.tv_usec is unsigned on some platforms.
264          */
265
266         if ((((int) delay.tv_sec) < 0)
267                 || ((delay.tv_usec == 0) && (delay.tv_sec == 0))) {
268             break;
269         }
270         (void) select(0, (SELECT_MASK *) 0, (SELECT_MASK *) 0,
271                 (SELECT_MASK *) 0, &delay);
272         TclGetTime(&before);
273     }
274 }
275
276
277
278
279
280
281
282 #if 0 /* WHOLE FILE */
283
284
285
286 /* interact (with only one process) - give user keyboard control
287
288 Written by: Don Libes, NIST, 2/6/90
289
290 Design and implementation of this program was paid for by U.S. tax
291 dollars.  Therefore it is public domain.  However, the author and NIST
292 would appreciate credit if this program or parts of it are used.
293 */
294
295 /* This file exists for deficient versions of UNIX that lack select,
296 poll, or some other multiplexing hook.  Instead, this code uses two
297 processes per spawned process.  One sends characters from the spawnee
298 to the spawner; a second send chars the other way.
299
300 This will work on any UNIX system.  The only sacrifice is that it
301 doesn't support multiple processes.  Eventually, it should catch
302 SIGCHLD on dead processes and do the right thing.  But it is pretty
303 gruesome to imagine so many processes to do all this.  If you change
304 it successfully, please mail back the changes to me.  - Don
305 */
306
307 #include "expect_cf.h"
308 #include <stdio.h>
309 #include <sys/types.h>
310 #include <sys/time.h>
311
312 #ifdef HAVE_SYS_WAIT_H
313 #include <sys/wait.h>
314 #endif
315
316 #include "tcl.h"
317 #include "exp_prog.h"
318 #include "exp_command.h"        /* for struct ExpState defs */
319 #include "exp_event.h"
320
321 /*ARGSUSED*/
322 void
323 exp_arm_background_channelhandler(esPtr)
324 ExpState *esPtr;
325 {
326 }
327
328 /*ARGSUSED*/
329 void
330 exp_disarm_background_channelhandler(esPtr)
331 ExpState *esPtr;
332 {
333 }
334
335 /*ARGSUSED*/
336 void
337 exp_disarm_background_channelhandler_force(esPtr)
338 ExpState *esPtr;
339 {
340 }
341
342 /*ARGSUSED*/
343 void
344 exp_unblock_background_channelhandler(esPtr)
345 ExpState *esPtr;
346 {
347 }
348
349 /*ARGSUSED*/
350 void
351 exp_block_background_channelhandler(esPtr)
352 ExpState *esPtr;
353 {
354 }
355
356 /*ARGSUSED*/
357 void
358 exp_event_disarm(fd)
359 int fd;
360 {
361 }
362
363 /* returns status, one of EOF, TIMEOUT, ERROR or DATA */
364 /*ARGSUSED*/
365 int
366 exp_get_next_event(interp,esPtrs, n,esPtrOut,timeout,key)
367 Tcl_Interp *interp;
368 ExpState (*esPtrs)[];
369 int n;                  /* # of esPtrs */
370 ExpState **esPtrOut;    /* 1st event master, not set if none */
371 int timeout;            /* seconds */
372 int key;
373 {
374     ExpState *esPtr;
375
376     if (n > 1) {
377         exp_error(interp,"expect not compiled with multiprocess support");
378         /* select a different INTERACT_TYPE in Makefile */
379         return(TCL_ERROR);
380     }
381
382     esPtr = *esPtrOut = esPtrs[0];
383
384     if (esPtr->key != key) {
385         esPtr->key = key;
386         esPtr->force_read = FALSE;
387         return(EXP_DATA_OLD);
388     } else if ((!esPtr->force_read) && (esPtr->size != 0)) {
389         return(EXP_DATA_OLD);
390     }
391
392     return(EXP_DATA_NEW);
393 }
394
395 /*ARGSUSED*/
396 int
397 exp_get_next_event_info(interp,esPtr,ready_mask)
398 Tcl_Interp *interp;
399 ExpState *esPtr;
400 int ready_mask;
401 {
402 }
403
404 /* There is no portable way to do sub-second sleeps on such a system, so */
405 /* do the next best thing (without a busy loop) and fake it: sleep the right */
406 /* amount of time over the long run.  Note that while "subtotal" isn't */
407 /* reinitialized, it really doesn't matter for such a gross hack as random */
408 /* scheduling pauses will easily introduce occasional one second delays. */
409 int     /* returns TCL_XXX */
410 exp_dsleep(interp,sec)
411 Tcl_Interp *interp;
412 double sec;
413 {
414         static double subtotal = 0;
415         int seconds;
416
417         subtotal += sec;
418         if (subtotal < 1) return TCL_OK;
419         seconds = subtotal;
420         subtotal -= seconds;
421  restart:
422         if (Tcl_AsyncReady()) {
423                 int rc = Tcl_AsyncInvoke(interp,TCL_OK);
424                 if (rc != TCL_OK) return(rc);
425         }
426         sleep(seconds);
427         return TCL_OK;
428 }
429
430 #if 0
431 /* There is no portable way to do sub-second sleeps on such a system, so */
432 /* do the next best thing (without a busy loop) and fake it: sleep the right */
433 /* amount of time over the long run.  Note that while "subtotal" isn't */
434 /* reinitialized, it really doesn't matter for such a gross hack as random */
435 /* scheduling pauses will easily introduce occasional one second delays. */
436 int     /* returns TCL_XXX */
437 exp_usleep(interp,usec)
438 Tcl_Interp *interp;
439 long usec;              /* microseconds */
440 {
441         static subtotal = 0;
442         int seconds;
443
444         subtotal += usec;
445         if (subtotal < 1000000) return TCL_OK;
446         seconds = subtotal/1000000;
447         subtotal = subtotal%1000000;
448  restart:
449         if (Tcl_AsyncReady()) {
450                 int rc = Tcl_AsyncInvoke(interp,TCL_OK);
451                 if (rc != TCL_OK) return(exp_tcl2_returnvalue(rc));
452         }
453         sleep(seconds);
454         return TCL_OK;
455 }
456 #endif /*0*/
457
458 /* set things up for later calls to event handler */
459 void
460 exp_init_event()
461 {
462         exp_event_exit = 0;
463 }
464
465 #endif /* WHOLE FILE! */