Diff
Not logged in

Differences From Artifact [759bf6b7b5]:

To Artifact [f1d9ca8d06]:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * tclUnixNotify.c --
 *
 *	This file contains the implementation of the select-based
 *	Unix-specific notifier, which is the lowest-level part of the
 *	Tcl event loop.  This file works together with
 *	../generic/tclNotify.c.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclUnixNotfy.c,v 1.1.2.3 1998/11/11 04:54:22 stanton Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include <signal.h> 

/*













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * tclUnixNotify.c --
 *
 *	This file contains the implementation of the select-based
 *	Unix-specific notifier, which is the lowest-level part of the
 *	Tcl event loop.  This file works together with
 *	../generic/tclNotify.c.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclUnixNotfy.c,v 1.1.2.4 1998/12/01 05:01:03 stanton Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include <signal.h> 

/*
80
81
82
83
84
85
86
87
88
89



90
91
92
93
94
95
96
    struct ThreadSpecificData *nextPtr, *prevPtr;
                                /* All threads that are currently waiting on 
                                 * an event have their ThreadSpecificData
                                 * structure on a doubly-linked listed formed
                                 * from these pointers.  You must hold the
                                 * notifierMutex lock before accessing these
                                 * fields. */
    Tcl_Condition waitCV;	/* The notifier thread alerts a notifier
				 * that an event is ready to be processed
				 * by signaling this condition variable. */



#endif
} ThreadSpecificData;

static Tcl_ThreadDataKey dataKey;

#ifdef TCL_THREADS
/*







|


>
>
>







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
    struct ThreadSpecificData *nextPtr, *prevPtr;
                                /* All threads that are currently waiting on 
                                 * an event have their ThreadSpecificData
                                 * structure on a doubly-linked listed formed
                                 * from these pointers.  You must hold the
                                 * notifierMutex lock before accessing these
                                 * fields. */
    Tcl_Condition waitCV;     /* Any other thread alerts a notifier
				 * that an event is ready to be processed
				 * by signaling this condition variable. */
    int eventReady;           /* True if an event is ready to be processed.
                               * Used as condition flag together with
                               * waitCV above. */
#endif
} ThreadSpecificData;

static Tcl_ThreadDataKey dataKey;

#ifdef TCL_THREADS
/*
190
191
192
193
194
195
196


197
198
199
200
201
202
203

ClientData
Tcl_InitNotifier()
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

#ifdef TCL_THREADS


    /*
     * Start the Notifier thread if necessary.
     */

    Tcl_MutexLock(&notifierMutex);
    if (notifierCount == 0) {
	if (TclpThreadCreate(&notifierThread, NotifierThreadProc, NULL) != TCL_OK) {







>
>







193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208

ClientData
Tcl_InitNotifier()
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

#ifdef TCL_THREADS
    tsdPtr->eventReady = 0;

    /*
     * Start the Notifier thread if necessary.
     */

    Tcl_MutexLock(&notifierMutex);
    if (notifierCount == 0) {
	if (TclpThreadCreate(&notifierThread, NotifierThreadProc, NULL) != TCL_OK) {
294
295
296
297
298
299
300

301
302
303
304
305
306
307
void
Tcl_AlertNotifier(clientData)
    ClientData clientData;
{
#ifdef TCL_THREADS
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
    Tcl_MutexLock(&notifierMutex);

    TclpConditionNotify(&tsdPtr->waitCV);
    Tcl_MutexUnlock(&notifierMutex);
#endif
}

/*
 *----------------------------------------------------------------------







>







299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
void
Tcl_AlertNotifier(clientData)
    ClientData clientData;
{
#ifdef TCL_THREADS
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
    Tcl_MutexLock(&notifierMutex);
    tsdPtr->eventReady = 1;
    TclpConditionNotify(&tsdPtr->waitCV);
    Tcl_MutexUnlock(&notifierMutex);
#endif
}

/*
 *----------------------------------------------------------------------
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
    ClientData clientData;	/* Arbitrary data to pass to proc. */
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
    FileHandler *filePtr;
    int index, bit;

    for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL;
	    filePtr = filePtr->nextPtr) {
	if (filePtr->fd == fd) {
	    break;
	}
    }
    if (filePtr == NULL) {
	filePtr = (FileHandler*) ckalloc(sizeof(FileHandler));
	filePtr->fd = fd;







|







367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
    ClientData clientData;	/* Arbitrary data to pass to proc. */
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
    FileHandler *filePtr;
    int index, bit;

    for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL;
	 filePtr = filePtr->nextPtr) {
	if (filePtr->fd == fd) {
	    break;
	}
    }
    if (filePtr == NULL) {
	filePtr = (FileHandler*) ckalloc(sizeof(FileHandler));
	filePtr->fd = fd;
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    /*
     * Find the entry for the given file (and return if there isn't one).
     */

    for (prevPtr = NULL, filePtr = tsdPtr->firstFileHandlerPtr; ;
	    prevPtr = filePtr, filePtr = filePtr->nextPtr) {
	if (filePtr == NULL) {
	    return;
	}
	if (filePtr->fd == fd) {
	    break;
	}
    }







|







440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    /*
     * Find the entry for the given file (and return if there isn't one).
     */

    for (prevPtr = NULL, filePtr = tsdPtr->firstFileHandlerPtr; ;
	 prevPtr = filePtr, filePtr = filePtr->nextPtr) {
	if (filePtr == NULL) {
	    return;
	}
	if (filePtr->fd == fd) {
	    break;
	}
    }
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
     * the event.  We do this rather than keeping a pointer to the file
     * handler directly in the event, so that the handler can be deleted
     * while the event is queued without leaving a dangling pointer.
     */

    tsdPtr = TCL_TSD_INIT(&dataKey);
    for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL;
	    filePtr = filePtr->nextPtr) {
	if (filePtr->fd != fileEvPtr->fd) {
	    continue;
	}

	/*
	 * The code is tricky for two reasons:
	 * 1. The file handler's desired events could have changed







|







545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
     * the event.  We do this rather than keeping a pointer to the file
     * handler directly in the event, so that the handler can be deleted
     * while the event is queued without leaving a dangling pointer.
     */

    tsdPtr = TCL_TSD_INIT(&dataKey);
    for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL;
	 filePtr = filePtr->nextPtr) {
	if (filePtr->fd != fileEvPtr->fd) {
	    continue;
	}

	/*
	 * The code is tricky for two reasons:
	 * 1. The file handler's desired events could have changed
671
672
673
674
675
676
677

678


679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697

698
699
700
701
702
703
704
        waitingListPtr = tsdPtr;
	tsdPtr->onList = 1;
	write(triggerPipe, "", 1);
    }

    memset((VOID *) tsdPtr->readyMasks, 0, 3*MASK_SIZE*sizeof(fd_mask));


    TclpConditionWait(&tsdPtr->waitCV, &notifierMutex, timePtr);



    if (waitForFiles && tsdPtr->onList) {
	/*
	 * Remove the ThreadSpecificData structure of this thread from the
	 * waiting list.  Don't bother to alert the notifier thread since
	 * we haven't added anything and it will notice the next time it
	 * wakes up.
	 */

        if (tsdPtr->prevPtr) {
            tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr;
        } else {
            waitingListPtr = tsdPtr->nextPtr;
        }
        if (tsdPtr->nextPtr) {
            tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
        }
        tsdPtr->nextPtr = tsdPtr->prevPtr = NULL;
	tsdPtr->onList = 0;

    }

    
#else
    memcpy((VOID *) tsdPtr->readyMasks, (VOID *) tsdPtr->checkMasks,
	    3*MASK_SIZE*sizeof(fd_mask));
    numFound = select(tsdPtr->numFdBits,







>
|
>
>




|
|
|












>







677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
        waitingListPtr = tsdPtr;
	tsdPtr->onList = 1;
	write(triggerPipe, "", 1);
    }

    memset((VOID *) tsdPtr->readyMasks, 0, 3*MASK_SIZE*sizeof(fd_mask));

    if (!tsdPtr->eventReady) {
        TclpConditionWait(&tsdPtr->waitCV, &notifierMutex, timePtr);
    }
    tsdPtr->eventReady = 0;

    if (waitForFiles && tsdPtr->onList) {
	/*
	 * Remove the ThreadSpecificData structure of this thread from the
	 * waiting list.  Alert the notifier thread to recompute its select
	 * masks - skipping this caused a hang when trying to close a pipe
	 * which the notifier thread was still doing a select on.
	 */

        if (tsdPtr->prevPtr) {
            tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr;
        } else {
            waitingListPtr = tsdPtr->nextPtr;
        }
        if (tsdPtr->nextPtr) {
            tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
        }
        tsdPtr->nextPtr = tsdPtr->prevPtr = NULL;
	tsdPtr->onList = 0;
	write(triggerPipe, "", 1);
    }

    
#else
    memcpy((VOID *) tsdPtr->readyMasks, (VOID *) tsdPtr->checkMasks,
	    3*MASK_SIZE*sizeof(fd_mask));
    numFound = select(tsdPtr->numFdBits,
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
#endif

    /*
     * Queue all detected file events before returning.
     */

    for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL);
	    filePtr = filePtr->nextPtr) {
	index = filePtr->fd / (NBBY*sizeof(fd_mask));
	bit = 1 << (filePtr->fd % (NBBY*sizeof(fd_mask)));
	mask = 0;

	if (tsdPtr->readyMasks[index] & bit) {
	    mask |= TCL_READABLE;
	}







|







727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
#endif

    /*
     * Queue all detected file events before returning.
     */

    for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL);
	 filePtr = filePtr->nextPtr) {
	index = filePtr->fd / (NBBY*sizeof(fd_mask));
	bit = 1 << (filePtr->fd % (NBBY*sizeof(fd_mask)));
	mask = 0;

	if (tsdPtr->readyMasks[index] & bit) {
	    mask |= TCL_READABLE;
	}
893
894
895
896
897
898
899

900
901
902
903
904
905
906

            for (i = 0; i < maskSize; i++) {
                word = maskPtr[i] & ((long*)tsdPtr->checkMasks)[i];
                found |= word;
                (((long*)(tsdPtr->readyMasks))[i]) = word;
	    }
            if (found || (tsdPtr->pollState & POLL_DONE)) {

		TclpConditionNotify(&tsdPtr->waitCV);
		if (tsdPtr->onList) {
		    /*
		     * Remove the ThreadSpecificData structure of this thread
		     * from the waiting list. This prevents us from continuously
		     * spining on select until the other threads runs and
		     * services the file event.







>







903
904
905
906
907
908
909
910
911
912
913
914
915
916
917

            for (i = 0; i < maskSize; i++) {
                word = maskPtr[i] & ((long*)tsdPtr->checkMasks)[i];
                found |= word;
                (((long*)(tsdPtr->readyMasks))[i]) = word;
	    }
            if (found || (tsdPtr->pollState & POLL_DONE)) {
                tsdPtr->eventReady = 1;
		TclpConditionNotify(&tsdPtr->waitCV);
		if (tsdPtr->onList) {
		    /*
		     * Remove the ThreadSpecificData structure of this thread
		     * from the waiting list. This prevents us from continuously
		     * spining on select until the other threads runs and
		     * services the file event.