OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [expect/] [exp_poll.c] - Blame information for rev 1780

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/* exp_poll.c - This file contains UNIX specific procedures for
2
 * poll-based notifier, which is the lowest-level part of the Tcl
3
 * event loop.  This file works together with ../generic/tclNotify.c.
4
 *
5
 * Design and implementation of this program was paid for by U.S. tax
6
 * dollars.  Therefore it is public domain.  However, the author and
7
 * NIST would appreciate credit if this program or parts of it are
8
 * used.
9
 *
10
 * Written by Don Libes, NIST, 2/6/90
11
 * Rewritten by Don Libes, 2/96 for new Tcl notifier paradigm.
12
 * Rewritten again by Don Libes, 8/97 for yet another Tcl notifier paradigm.
13
 */
14
 
15
#include "tclInt.h"
16
#include "tclPort.h"
17
#include <signal.h> 
18
 
19
#include <poll.h>
20
#include <sys/types.h>
21
 
22
#ifdef HAVE_UNISTD_H
23
#  include <unistd.h>
24
#endif
25
 
26
/* Some systems require that the poll array be non-empty so provide a
27
 * 1-elt array for starters.  It will be ignored as soon as it grows
28
 * larger.
29
 */
30
 
31
static struct pollfd initialFdArray;
32
static struct pollfd *fdArray = &initialFdArray;
33
static int fdsInUse = 0; /* space in use */
34
static int fdsMaxSpace = 1;     /* space that has actually been allocated */
35
 
36
#if TCL_MAJOR_VERSION >= 8
37
 
38
/*
39
 * tclUnixNotify.c --
40
 *
41
 *      This file contains the implementation of the select-based
42
 *      Unix-specific notifier, which is the lowest-level part of the
43
 *      Tcl event loop.  This file works together with
44
 *      ../generic/tclNotify.c.
45
 *
46
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
47
 *
48
 * See the file "license.terms" for information on usage and redistribution
49
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
50
 *
51
 * SCCS: @(#) tclUnixNotfy.c 1.42 97/07/02 20:55:44
52
 */
53
 
54
/*
55
 * This structure is used to keep track of the notifier info for a
56
 * a registered file.
57
 */
58
 
59
typedef struct FileHandler {
60
    int fd;
61
    int mask;                   /* Mask of desired events: TCL_READABLE,
62
                                 * etc. */
63
    int readyMask;              /* Mask of events that have been seen since the
64
                                 * last time file handlers were invoked for
65
                                 * this file. */
66
    Tcl_FileProc *proc;         /* Procedure to call, in the style of
67
                                 * Tcl_CreateFileHandler. */
68
    ClientData clientData;      /* Argument to pass to proc. */
69
    int pollArrayIndex;         /* index into poll array */
70
    struct FileHandler *nextPtr;/* Next in list of all files we care about. */
71
} FileHandler;
72
 
73
/*
74
 * The following structure is what is added to the Tcl event queue when
75
 * file handlers are ready to fire.
76
 */
77
 
78
typedef struct FileHandlerEvent {
79
    Tcl_Event header;           /* Information that is standard for
80
                                 * all events. */
81
    int fd;                     /* File descriptor that is ready.  Used
82
                                 * to find the FileHandler structure for
83
                                 * the file (can't point directly to the
84
                                 * FileHandler structure because it could
85
                                 * go away while the event is queued). */
86
} FileHandlerEvent;
87
 
88
/*
89
 * The following static structure contains the state information for the
90
 * select based implementation of the Tcl notifier.
91
 */
92
 
93
static struct {
94
    FileHandler *firstFileHandlerPtr;
95
                                /* Pointer to head of file handler list. */
96
    fd_mask checkMasks[3*MASK_SIZE];
97
                                /* This array is used to build up the masks
98
                                 * to be used in the next call to select.
99
                                 * Bits are set in response to calls to
100
                                 * Tcl_CreateFileHandler. */
101
    fd_mask readyMasks[3*MASK_SIZE];
102
                                /* This array reflects the readable/writable
103
                                 * conditions that were found to exist by the
104
                                 * last call to select. */
105
    int numFdBits;              /* Number of valid bits in checkMasks
106
                                 * (one more than highest fd for which
107
                                 * Tcl_WatchFile has been called). */
108
} notifier;
109
 
110
/*
111
 * The following static indicates whether this module has been initialized.
112
 */
113
 
114
static int initialized = 0;
115
 
116
/*
117
 * Static routines defined in this file.
118
 */
119
 
120
static void             InitNotifier _ANSI_ARGS_((void));
121
static void             NotifierExitHandler _ANSI_ARGS_((
122
                            ClientData clientData));
123
static int              FileHandlerEventProc _ANSI_ARGS_((Tcl_Event *evPtr,
124
                            int flags));
125
 
126
/*
127
 *----------------------------------------------------------------------
128
 *
129
 * InitNotifier --
130
 *
131
 *      Initializes the notifier state.
132
 *
133
 * Results:
134
 *      None.
135
 *
136
 * Side effects:
137
 *      Creates a new exit handler.
138
 *
139
 *----------------------------------------------------------------------
140
 */
141
 
142
static void
143
InitNotifier()
144
{
145
    initialized = 1;
146
    memset(&notifier, 0, sizeof(notifier));
147
    Tcl_CreateExitHandler(NotifierExitHandler, NULL);
148
}
149
 
150
/*
151
 *----------------------------------------------------------------------
152
 *
153
 * NotifierExitHandler --
154
 *
155
 *      This function is called to cleanup the notifier state before
156
 *      Tcl is unloaded.
157
 *
158
 * Results:
159
 *      None.
160
 *
161
 * Side effects:
162
 *      Destroys the notifier window.
163
 *
164
 *----------------------------------------------------------------------
165
 */
166
 
167
static void
168
NotifierExitHandler(clientData)
169
    ClientData clientData;              /* Not used. */
170
{
171
    initialized = 0;
172
}
173
 
174
/*
175
 *----------------------------------------------------------------------
176
 *
177
 * Tcl_SetTimer --
178
 *
179
 *      This procedure sets the current notifier timer value.  This
180
 *      interface is not implemented in this notifier because we are
181
 *      always running inside of Tcl_DoOneEvent.
182
 *
183
 * Results:
184
 *      None.
185
 *
186
 * Side effects:
187
 *      None.
188
 *
189
 *----------------------------------------------------------------------
190
 */
191
 
192
void
193
Tcl_SetTimer(timePtr)
194
    Tcl_Time *timePtr;          /* Timeout value, may be NULL. */
195
{
196
    /*
197
     * The interval timer doesn't do anything in this implementation,
198
     * because the only event loop is via Tcl_DoOneEvent, which passes
199
     * timeout values to Tcl_WaitForEvent.
200
     */
201
}
202
 
203
/*
204
 *----------------------------------------------------------------------
205
 *
206
 * Tcl_CreateFileHandler --
207
 *
208
 *      This procedure registers a file handler with the Xt notifier.
209
 *
210
 * Results:
211
 *      None.
212
 *
213
 * Side effects:
214
 *      Creates a new file handler structure and registers one or more
215
 *      input procedures with Xt.
216
 *
217
 *----------------------------------------------------------------------
218
 */
219
 
220
void
221
Tcl_CreateFileHandler(fd, mask, proc, clientData)
222
    int fd;                     /* Handle of stream to watch. */
223
    int mask;                   /* OR'ed combination of TCL_READABLE,
224
                                 * TCL_WRITABLE, and TCL_EXCEPTION:
225
                                 * indicates conditions under which
226
                                 * proc should be called. */
227
    Tcl_FileProc *proc;         /* Procedure to call for each
228
                                 * selected event. */
229
    ClientData clientData;      /* Arbitrary data to pass to proc. */
230
{
231
    FileHandler *filePtr;
232
    int index, bit;
233
    int cur_fd_index;
234
 
235
    if (!initialized) {
236
        InitNotifier();
237
    }
238
 
239
    for (filePtr = notifier.firstFileHandlerPtr; filePtr != NULL;
240
            filePtr = filePtr->nextPtr) {
241
        if (filePtr->fd == fd) {
242
            break;
243
        }
244
    }
245
    if (filePtr == NULL) {
246
        filePtr = (FileHandler*) ckalloc(sizeof(FileHandler)); /* MLK */
247
        filePtr->fd = fd;
248
        filePtr->readyMask = 0;
249
        filePtr->nextPtr = notifier.firstFileHandlerPtr;
250
        notifier.firstFileHandlerPtr = filePtr;
251
    }
252
    filePtr->proc = proc;
253
    filePtr->clientData = clientData;
254
#if NOTUSED
255
    /* remaining junk is left over from select implementation - DEL */
256
 
257
    filePtr->mask = mask;
258
 
259
    /*
260
     * Update the check masks for this file.
261
     */
262
 
263
    index = fd/(NBBY*sizeof(fd_mask));
264
    bit = 1 << (fd%(NBBY*sizeof(fd_mask)));
265
    if (mask & TCL_READABLE) {
266
        notifier.checkMasks[index] |= bit;
267
    } else {
268
        notifier.checkMasks[index] &= ~bit;
269
    }
270
    if (mask & TCL_WRITABLE) {
271
        (notifier.checkMasks+MASK_SIZE)[index] |= bit;
272
    } else {
273
        (notifier.checkMasks+MASK_SIZE)[index] &= ~bit;
274
    }
275
    if (mask & TCL_EXCEPTION) {
276
        (notifier.checkMasks+2*(MASK_SIZE))[index] |= bit;
277
    } else {
278
        (notifier.checkMasks+2*(MASK_SIZE))[index] &= ~bit;
279
    }
280
    if (notifier.numFdBits <= fd) {
281
        notifier.numFdBits = fd+1;
282
    }
283
#endif /* notused */
284
 
285
    filePtr->pollArrayIndex = fdsInUse;
286
    cur_fd_index = fdsInUse;
287
 
288
    fdsInUse++;
289
    if (fdsInUse > fdsMaxSpace) {
290
        if (fdArray != &initialFdArray) ckfree((char *)fdArray);
291
        fdArray = (struct pollfd *)ckalloc(fdsInUse*sizeof(struct pollfd));
292
        fdsMaxSpace = fdsInUse;
293
    }
294
 
295
    fdArray[cur_fd_index].fd = fd;
296
 
297
    /* I know that POLLIN/OUT is right.  But I have no idea if POLLPRI
298
     * corresponds well to TCL_EXCEPTION.
299
     */
300
 
301
    if (mask & TCL_READABLE) {
302
        fdArray[cur_fd_index].events = POLLIN;
303
    }
304
    if (mask & TCL_WRITABLE) {
305
        fdArray[cur_fd_index].events = POLLOUT;
306
    }
307
    if (mask & TCL_EXCEPTION) {
308
        fdArray[cur_fd_index].events = POLLPRI;
309
    }
310
}
311
 
312
/*
313
 *----------------------------------------------------------------------
314
 *
315
 * Tcl_DeleteFileHandler --
316
 *
317
 *      Cancel a previously-arranged callback arrangement for
318
 *      a file.
319
 *
320
 * Results:
321
 *      None.
322
 *
323
 * Side effects:
324
 *      If a callback was previously registered on file, remove it.
325
 *
326
 *----------------------------------------------------------------------
327
 */
328
 
329
void
330
Tcl_DeleteFileHandler(fd)
331
    int fd;             /* Stream id for which to remove callback procedure. */
332
{
333
    FileHandler *filePtr, *prevPtr, *lastPtr;
334
    int index, bit, mask, i;
335
    int cur_fd_index;
336
 
337
    if (!initialized) {
338
        InitNotifier();
339
    }
340
 
341
    /*
342
     * Find the entry for the given file (and return if there
343
     * isn't one).
344
     */
345
 
346
    for (prevPtr = NULL, filePtr = notifier.firstFileHandlerPtr; ;
347
            prevPtr = filePtr, filePtr = filePtr->nextPtr) {
348
        if (filePtr == NULL) {
349
            return;
350
        }
351
        if (filePtr->fd == fd) {
352
            break;
353
        }
354
    }
355
 
356
#if NOTUSED
357
    /* remaining junk is left over from select implementation - DEL */
358
 
359
    /*
360
     * Update the check masks for this file.
361
     */
362
 
363
    index = fd/(NBBY*sizeof(fd_mask));
364
    bit = 1 << (fd%(NBBY*sizeof(fd_mask)));
365
 
366
    if (filePtr->mask & TCL_READABLE) {
367
        notifier.checkMasks[index] &= ~bit;
368
    }
369
    if (filePtr->mask & TCL_WRITABLE) {
370
        (notifier.checkMasks+MASK_SIZE)[index] &= ~bit;
371
    }
372
    if (filePtr->mask & TCL_EXCEPTION) {
373
        (notifier.checkMasks+2*(MASK_SIZE))[index] &= ~bit;
374
    }
375
 
376
    /*
377
     * Find current max fd.
378
     */
379
 
380
    if (fd+1 == notifier.numFdBits) {
381
        for (notifier.numFdBits = 0; index >= 0; index--) {
382
            mask = notifier.checkMasks[index]
383
                | (notifier.checkMasks+MASK_SIZE)[index]
384
                | (notifier.checkMasks+2*(MASK_SIZE))[index];
385
            if (mask) {
386
                for (i = (NBBY*sizeof(fd_mask)); i > 0; i--) {
387
                    if (mask & (1 << (i-1))) {
388
                        break;
389
                    }
390
                }
391
                notifier.numFdBits = index * (NBBY*sizeof(fd_mask)) + i;
392
                break;
393
            }
394
        }
395
    }
396
#endif /* notused */
397
 
398
    /*
399
     * Clean up information in the callback record.
400
     */
401
 
402
    if (prevPtr == NULL) {
403
        notifier.firstFileHandlerPtr = filePtr->nextPtr;
404
    } else {
405
        prevPtr->nextPtr = filePtr->nextPtr;
406
    }
407
 
408
    /* back to poll-specific code - DEL */
409
 
410
    cur_fd_index = filePtr->pollArrayIndex;
411
    fdsInUse--;
412
 
413
    /* if this one is last, do nothing special */
414
    /* else swap with one at end of array */
415
 
416
    if (cur_fd_index != fdsInUse) {
417
        int lastfd_in_array = fdArray[fdsInUse].fd;
418
        memcpy(&fdArray[cur_fd_index],&fdArray[fdsInUse],sizeof(struct pollfd));
419
 
420
        /* update index to reflect new location in array */
421
        /* first find link corresponding to last element in array */
422
 
423
        for (lastPtr = notifier.firstFileHandlerPtr; filePtr; lastPtr = lastPtr->nextPtr) {
424
            if (lastPtr->fd == lastfd_in_array) {
425
                lastPtr->pollArrayIndex = cur_fd_index;
426
                break;
427
            }
428
        }
429
    }
430
 
431
    fdsInUse--;
432
 
433
    ckfree((char *) filePtr);
434
}
435
 
436
/*
437
 *----------------------------------------------------------------------
438
 *
439
 * FileHandlerEventProc --
440
 *
441
 *      This procedure is called by Tcl_ServiceEvent when a file event
442
 *      reaches the front of the event queue.  This procedure is
443
 *      responsible for actually handling the event by invoking the
444
 *      callback for the file handler.
445
 *
446
 * Results:
447
 *      Returns 1 if the event was handled, meaning it should be removed
448
 *      from the queue.  Returns 0 if the event was not handled, meaning
449
 *      it should stay on the queue.  The only time the event isn't
450
 *      handled is if the TCL_FILE_EVENTS flag bit isn't set.
451
 *
452
 * Side effects:
453
 *      Whatever the file handler's callback procedure does.
454
 *
455
 *----------------------------------------------------------------------
456
 */
457
 
458
static int
459
FileHandlerEventProc(evPtr, flags)
460
    Tcl_Event *evPtr;           /* Event to service. */
461
    int flags;                  /* Flags that indicate what events to
462
                                 * handle, such as TCL_FILE_EVENTS. */
463
{
464
    FileHandler *filePtr;
465
    FileHandlerEvent *fileEvPtr = (FileHandlerEvent *) evPtr;
466
    int mask;
467
 
468
    if (!(flags & TCL_FILE_EVENTS)) {
469
        return 0;
470
    }
471
 
472
    /*
473
     * Search through the file handlers to find the one whose handle matches
474
     * the event.  We do this rather than keeping a pointer to the file
475
     * handler directly in the event, so that the handler can be deleted
476
     * while the event is queued without leaving a dangling pointer.
477
     */
478
 
479
    for (filePtr = notifier.firstFileHandlerPtr; filePtr != NULL;
480
            filePtr = filePtr->nextPtr) {
481
        if (filePtr->fd != fileEvPtr->fd) {
482
            continue;
483
        }
484
 
485
        /*
486
         * The code is tricky for two reasons:
487
         * 1. The file handler's desired events could have changed
488
         *    since the time when the event was queued, so AND the
489
         *    ready mask with the desired mask.
490
         * 2. The file could have been closed and re-opened since
491
         *    the time when the event was queued.  This is why the
492
         *    ready mask is stored in the file handler rather than
493
         *    the queued event:  it will be zeroed when a new
494
         *    file handler is created for the newly opened file.
495
         */
496
 
497
        mask = filePtr->readyMask & filePtr->mask;
498
        filePtr->readyMask = 0;
499
        if (mask != 0) {
500
            (*filePtr->proc)(filePtr->clientData, mask);
501
        }
502
        break;
503
    }
504
    return 1;
505
}
506
 
507
/*
508
 *----------------------------------------------------------------------
509
 *
510
 * Tcl_WaitForEvent --
511
 *
512
 *      This function is called by Tcl_DoOneEvent to wait for new
513
 *      events on the message queue.  If the block time is 0, then
514
 *      Tcl_WaitForEvent just polls without blocking.
515
 *
516
 * Results:
517
 *      Returns -1 if the select would block forever, otherwise
518
 *      returns 0.
519
 *
520
 * Side effects:
521
 *      Queues file events that are detected by the select.
522
 *
523
 *----------------------------------------------------------------------
524
 */
525
 
526
int
527
Tcl_WaitForEvent(timePtr)
528
    Tcl_Time *timePtr;          /* Maximum block time, or NULL. */
529
{
530
    FileHandler *filePtr;
531
    FileHandlerEvent *fileEvPtr;
532
#if 0
533
    struct timeval timeout, *timeoutPtr;
534
#endif
535
    int timeout;
536
    struct timeval *timeoutPtr;
537
 
538
    int bit, index, mask, numFound;
539
 
540
    if (!initialized) {
541
        InitNotifier();
542
    }
543
 
544
    /*
545
     * Set up the timeout structure.  Note that if there are no events to
546
     * check for, we return with a negative result rather than blocking
547
     * forever.
548
     */
549
 
550
    if (timePtr) {
551
#if 0
552
        timeout.tv_sec = timePtr->sec;
553
        timeout.tv_usec = timePtr->usec;
554
        timeoutPtr = &timeout;
555
#endif
556
        timeout = timePtr->sec*1000 + timePtr->usec/1000;
557
 
558
    } else if (notifier.numFdBits == 0) {
559
        return -1;
560
    } else {
561
        timeoutPtr = NULL;
562
    }
563
 
564
    numFound = poll(fdArray,fdsInUse,timeout);
565
#if 0
566
    memcpy((VOID *) notifier.readyMasks, (VOID *) notifier.checkMasks,
567
            3*MASK_SIZE*sizeof(fd_mask));
568
    numFound = select(notifier.numFdBits,
569
            (SELECT_MASK *) &notifier.readyMasks[0],
570
            (SELECT_MASK *) &notifier.readyMasks[MASK_SIZE],
571
            (SELECT_MASK *) &notifier.readyMasks[2*MASK_SIZE], timeoutPtr);
572
 
573
    /*
574
     * Some systems don't clear the masks after an error, so
575
     * we have to do it here.
576
     */
577
 
578
    if (numFound == -1) {
579
        memset((VOID *) notifier.readyMasks, 0, 3*MASK_SIZE*sizeof(fd_mask));
580
    }
581
#endif
582
 
583
    /*
584
     * Queue all detected file events before returning.
585
     */
586
 
587
    for (filePtr = notifier.firstFileHandlerPtr;
588
            (filePtr != NULL) && (numFound > 0);
589
            filePtr = filePtr->nextPtr) {
590
        index = filePtr->pollArrayIndex;
591
        mask = 0;
592
 
593
        if (fdArray[index].revents & POLLIN) {
594
            mask |= TCL_READABLE;
595
        }
596
        if (fdArray[index].revents & POLLOUT) {
597
            mask |= TCL_WRITABLE;
598
        }
599
        /* I have no idea if this is right ... */
600
        if (fdArray[index].revents & (POLLPRI|POLLERR|POLLHUP|POLLNVAL)) {
601
            mask |= TCL_EXCEPTION;
602
        }
603
 
604
#if 0
605
        index = filePtr->fd / (NBBY*sizeof(fd_mask));
606
        bit = 1 << (filePtr->fd % (NBBY*sizeof(fd_mask)));
607
        mask = 0;
608
 
609
        if (notifier.readyMasks[index] & bit) {
610
            mask |= TCL_READABLE;
611
        }
612
        if ((notifier.readyMasks+MASK_SIZE)[index] & bit) {
613
            mask |= TCL_WRITABLE;
614
        }
615
        if ((notifier.readyMasks+2*(MASK_SIZE))[index] & bit) {
616
            mask |= TCL_EXCEPTION;
617
        }
618
#endif
619
 
620
        if (!mask) {
621
            continue;
622
        } else {
623
            numFound--;
624
        }
625
 
626
        /*
627
         * Don't bother to queue an event if the mask was previously
628
         * non-zero since an event must still be on the queue.
629
         */
630
 
631
        if (filePtr->readyMask == 0) {
632
            fileEvPtr = (FileHandlerEvent *) ckalloc(
633
                sizeof(FileHandlerEvent));
634
            fileEvPtr->header.proc = FileHandlerEventProc;
635
            fileEvPtr->fd = filePtr->fd;
636
            Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
637
        }
638
        filePtr->readyMask = mask;
639
    }
640
    return 0;
641
}
642
 
643
#else /* TCL_MAJOR_VERSION < 8 */
644
 
645
/*
646
 *----------------------------------------------------------------------
647
 *
648
 * Tcl_WatchFile --
649
 *
650
 *      Arrange for Tcl_DoOneEvent to include this file in the masks
651
 *      for the next call to select.  This procedure is invoked by
652
 *      event sources, which are in turn invoked by Tcl_DoOneEvent
653
 *      before it invokes select.
654
 *
655
 * Results:
656
 *      None.
657
 *
658
 * Side effects:
659
 *
660
 *      The notifier will generate a file event when the I/O channel
661
 *      given by fd next becomes ready in the way indicated by mask.
662
 *      If fd is already registered then the old mask will be replaced
663
 *      with the new one.  Once the event is sent, the notifier will
664
 *      not send any more events about the fd until the next call to
665
 *      Tcl_NotifyFile.
666
 *
667
 * Assumption for poll implementation: Tcl_WatchFile is presumed NOT
668
 * to be called on the same file descriptior without intervening calls
669
 * to Tcl_DoOneEvent.
670
 *
671
 *----------------------------------------------------------------------
672
 */
673
 
674
void
675
Tcl_WatchFile(file, mask)
676
    Tcl_File file;      /* Generic file handle for a stream. */
677
    int mask;                   /* OR'ed combination of TCL_READABLE,
678
                                 * TCL_WRITABLE, and TCL_EXCEPTION:
679
                                 * indicates conditions to wait for
680
                                 * in select. */
681
{
682
    int fd, type;
683
    int cur_fd_index = fdsInUse;
684
 
685
    fd = (int) Tcl_GetFileInfo(file, &type);
686
 
687
    if (type != TCL_UNIX_FD) {
688
        panic("Tcl_WatchFile: unexpected file type");
689
    }
690
 
691
    fdsInUse++;
692
    if (fdsInUse > fdsMaxSpace) {
693
        if (fdArray != &initialFdArray) ckfree((char *)fdArray);
694
        fdArray = (struct pollfd *)ckalloc(fdsInUse*sizeof(struct pollfd));
695
        fdsMaxSpace = fdsInUse;
696
    }
697
 
698
    fdArray[cur_fd_index].fd = fd;
699
 
700
    /* I know that POLLIN/OUT is right.  But I have no idea if POLLPRI
701
     * corresponds well to TCL_EXCEPTION.
702
     */
703
 
704
    if (mask & TCL_READABLE) {
705
        fdArray[cur_fd_index].events = POLLIN;
706
    }
707
    if (mask & TCL_WRITABLE) {
708
        fdArray[cur_fd_index].events = POLLOUT;
709
    }
710
    if (mask & TCL_EXCEPTION) {
711
        fdArray[cur_fd_index].events = POLLPRI;
712
    }
713
}
714
 
715
 
716
/*
717
 *----------------------------------------------------------------------
718
 *
719
 * Tcl_FileReady --
720
 *
721
 *      Indicates what conditions (readable, writable, etc.) were
722
 *      present on a file the last time the notifier invoked select.
723
 *      This procedure is typically invoked by event sources to see
724
 *      if they should queue events.
725
 *
726
 * Results:
727
 *      The return value is 0 if none of the conditions specified by mask
728
 *      was true for fd the last time the system checked.  If any of the
729
 *      conditions were true, then the return value is a mask of those
730
 *      that were true.
731
 *
732
 * Side effects:
733
 *      None.
734
 *
735
 *----------------------------------------------------------------------
736
 */
737
 
738
int
739
Tcl_FileReady(file, mask)
740
    Tcl_File file;      /* Generic file handle for a stream. */
741
    int mask;                   /* OR'ed combination of TCL_READABLE,
742
                                 * TCL_WRITABLE, and TCL_EXCEPTION:
743
                                 * indicates conditions caller cares about. */
744
{
745
    int index, result, type, fd;
746
    fd_mask bit;
747
 
748
    fd = (int) Tcl_GetFileInfo(file, &type);
749
    if (type != TCL_UNIX_FD) {
750
        panic("Tcl_FileReady: unexpected file type");
751
    }
752
 
753
    result = 0;
754
    if ((mask & TCL_READABLE) && (fdArray[fd].revents & POLLIN)) {
755
        result |= TCL_READABLE;
756
    }
757
    if ((mask & TCL_WRITABLE) && (fdArray[fd].revents & POLLOUT)) {
758
        result |= TCL_WRITABLE;
759
    }
760
    /* I have no idea if this is right ... */
761
    if ((mask & TCL_EXCEPTION) &&
762
                (fdArray[fd].revents & (POLLPRI|POLLERR|POLLHUP|POLLNVAL))) {
763
        result |= TCL_EXCEPTION;
764
    }
765
    return result;
766
}
767
 
768
/*
769
 *----------------------------------------------------------------------
770
 *
771
 * Tcl_WaitForEvent --
772
 *
773
 *      This procedure does the lowest level wait for events in a
774
 *      platform-specific manner.  It uses information provided by
775
 *      previous calls to Tcl_WatchFile, plus the timePtr argument,
776
 *      to determine what to wait for and how long to wait.
777
 *
778
 * Results:
779
 * 7.6  The return value is normally TCL_OK.  However, if there are
780
 *      no events to wait for (e.g. no files and no timers) so that
781
 *      the procedure would block forever, then it returns TCL_ERROR.
782
 *
783
 * Side effects:
784
 *      May put the process to sleep for a while, depending on timePtr.
785
 *      When this procedure returns, an event of interest to the application
786
 *      has probably, but not necessarily, occurred.
787
 *
788
 *----------------------------------------------------------------------
789
 */
790
 
791
int
792
Tcl_WaitForEvent(timePtr)
793
    Tcl_Time *timePtr;          /* Specifies the maximum amount of time
794
                                 * that this procedure should block before
795
                                 * returning.  The time is given as an
796
                                 * interval, not an absolute wakeup time.
797
                                 * NULL means block forever. */
798
{
799
    int timeout;
800
    struct timeval *timeoutPtr;
801
 
802
    /* no need to clear revents */
803
    if (timePtr == NULL) {
804
        if (!fdsInUse) return (TCL_ERROR);
805
        timeout = -1;
806
    } else {
807
        timeout = timePtr->sec*1000 + timePtr->usec/1000;
808
    }
809
 
810
    poll(fdArray,fdsInUse,timeout);
811
 
812
    fdsInUse = 0;
813
 
814
    return TCL_OK;
815
}
816
 
817
/*
818
 *----------------------------------------------------------------------
819
 *
820
 * Tcl_Sleep --
821
 *
822
 *      Delay execution for the specified number of milliseconds.
823
 *
824
 * Results:
825
 *      None.
826
 *
827
 * Side effects:
828
 *      Time passes.
829
 *
830
 *----------------------------------------------------------------------
831
 */
832
 
833
void
834
Tcl_Sleep(ms)
835
    int ms;                     /* Number of milliseconds to sleep. */
836
{
837
    static struct timeval delay;
838
    Tcl_Time before, after;
839
 
840
    /*
841
     * The only trick here is that select appears to return early
842
     * under some conditions, so we have to check to make sure that
843
     * the right amount of time really has elapsed.  If it's too
844
     * early, go back to sleep again.
845
     */
846
 
847
    TclGetTime(&before);
848
    after = before;
849
    after.sec += ms/1000;
850
    after.usec += (ms%1000)*1000;
851
    if (after.usec > 1000000) {
852
        after.usec -= 1000000;
853
        after.sec += 1;
854
    }
855
    while (1) {
856
        delay.tv_sec = after.sec - before.sec;
857
        delay.tv_usec = after.usec - before.usec;
858
        if (delay.tv_usec < 0) {
859
            delay.tv_usec += 1000000;
860
            delay.tv_sec -= 1;
861
        }
862
 
863
        /*
864
         * Special note:  must convert delay.tv_sec to int before comparing
865
         * to zero, since delay.tv_usec is unsigned on some platforms.
866
         */
867
 
868
        if ((((int) delay.tv_sec) < 0)
869
                || ((delay.tv_usec == 0) && (delay.tv_sec == 0))) {
870
            break;
871
        }
872
 
873
        /* poll understands milliseconds, sigh */
874
        poll(fdArray,0,delay.tv_sec*1000 + delay.tv_usec/1000);
875
        TclGetTime(&before);
876
    }
877
}
878
 
879
#endif /* TCL_MAJOR_VERSION < 8 */
880
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.