Tcl Source Code

Check-in [90712c8996]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Proposed fix for 9e69e2c602: Problem with TIP#609
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | bug-9e69e2c602
Files: files | file ages | folders
SHA3-256: 90712c8996dbf0e445e3580024266e037f105b64a887e7063cf91d3d7ca037a8
User & Date: jan.nijtmans 2024-12-06 10:39:21.051
Context
2024-12-07
13:15
Fix 9e69e2c602: Problem with TIP#609 check-in: 81c759724b user: jan.nijtmans tags: core-8-branch
2024-12-06
10:39
Proposed fix for 9e69e2c602: Problem with TIP#... Closed-Leaf check-in: 90712c8996 user: jan.nijtmans tags: bug-9e69e2c602
10:04
Fix "make dist". $(DISTDIR) part was missing check-in: f92b9869f4 user: jan.nijtmans tags: trunk, main
Changes
Unified Diff Ignore Whitespace Patch
Changes to generic/tclNotify.c.
53
54
55
56
57
58
59


60
61
62
63
64
65
66
67
68
69

70
71
72
73
74
75
76
77
78
79
80
81
82
83
 */

typedef struct ThreadSpecificData {
    Tcl_Event *firstEventPtr;	/* First pending event, or NULL if none. */
    Tcl_Event *lastEventPtr;	/* Last pending event, or NULL if none. */
    Tcl_Event *markerEventPtr;	/* Last high-priority event in queue, or NULL
				 * if none. */


    Tcl_Mutex queueMutex;	/* Mutex to protect access to the previous
				 * three fields. */
    int serviceMode;		/* One of TCL_SERVICE_NONE or
				 * TCL_SERVICE_ALL. */
    int blockTimeSet;		/* 0 means there is no maximum block time:
				 * block forever. */
    Tcl_Time blockTime;		/* If blockTimeSet is 1, gives the maximum
				 * elapsed time for the next block. */
    int inTraversal;		/* 1 if Tcl_SetMaxBlockTime is being called
				 * during an event source traversal. */

    EventSource *firstEventSourcePtr;
				/* Pointer to first event source in list of
				 * event sources for this thread. */
    Tcl_ThreadId threadId;	/* Thread that owns this notifier instance. */
    void *clientData;	/* Opaque handle for platform specific
				 * notifier. */
    int initialized;		/* 1 if notifier has been initialized. */
    struct ThreadSpecificData *nextPtr;
				/* Next notifier in global list of notifiers.
				 * Access is controlled by the listLock global
				 * mutex. */
} ThreadSpecificData;

static Tcl_ThreadDataKey dataKey;







>
>

|








>






<







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

79
80
81
82
83
84
85
 */

typedef struct ThreadSpecificData {
    Tcl_Event *firstEventPtr;	/* First pending event, or NULL if none. */
    Tcl_Event *lastEventPtr;	/* Last pending event, or NULL if none. */
    Tcl_Event *markerEventPtr;	/* Last high-priority event in queue, or NULL
				 * if none. */
    Tcl_Size eventCount;		/* Number of entries, but refer to comments in
				 * Tcl_ServiceEvent(). */
    Tcl_Mutex queueMutex;	/* Mutex to protect access to the previous
				 * four fields. */
    int serviceMode;		/* One of TCL_SERVICE_NONE or
				 * TCL_SERVICE_ALL. */
    int blockTimeSet;		/* 0 means there is no maximum block time:
				 * block forever. */
    Tcl_Time blockTime;		/* If blockTimeSet is 1, gives the maximum
				 * elapsed time for the next block. */
    int inTraversal;		/* 1 if Tcl_SetMaxBlockTime is being called
				 * during an event source traversal. */
    int initialized;		/* 1 if notifier has been initialized. */
    EventSource *firstEventSourcePtr;
				/* Pointer to first event source in list of
				 * event sources for this thread. */
    Tcl_ThreadId threadId;	/* Thread that owns this notifier instance. */
    void *clientData;	/* Opaque handle for platform specific
				 * notifier. */

    struct ThreadSpecificData *nextPtr;
				/* Next notifier in global list of notifiers.
				 * Access is controlled by the listLock global
				 * mutex. */
} ThreadSpecificData;

static Tcl_ThreadDataKey dataKey;
182
183
184
185
186
187
188

189
190
191
192
193
194
195
    for (evPtr = tsdPtr->firstEventPtr; evPtr != NULL; ) {
	hold = evPtr;
	evPtr = evPtr->nextPtr;
	Tcl_Free(hold);
    }
    tsdPtr->firstEventPtr = NULL;
    tsdPtr->lastEventPtr = NULL;

    Tcl_MutexUnlock(&(tsdPtr->queueMutex));

    Tcl_MutexLock(&listLock);

    Tcl_FinalizeNotifier(tsdPtr->clientData);
    Tcl_MutexFinalize(&(tsdPtr->queueMutex));
    for (prevPtrPtr = &firstNotifierPtr; *prevPtrPtr != NULL;







>







184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
    for (evPtr = tsdPtr->firstEventPtr; evPtr != NULL; ) {
	hold = evPtr;
	evPtr = evPtr->nextPtr;
	Tcl_Free(hold);
    }
    tsdPtr->firstEventPtr = NULL;
    tsdPtr->lastEventPtr = NULL;
    tsdPtr->eventCount = 0;
    Tcl_MutexUnlock(&(tsdPtr->queueMutex));

    Tcl_MutexLock(&listLock);

    Tcl_FinalizeNotifier(tsdPtr->clientData);
    Tcl_MutexFinalize(&(tsdPtr->queueMutex));
    for (prevPtrPtr = &firstNotifierPtr; *prevPtrPtr != NULL;
482
483
484
485
486
487
488
489
490
491
492

493
494
495
496
497
498
499
				 * must have been allocated the caller with
				 * malloc (Tcl_Alloc), and it becomes the
				 * property of the event queue. It will be
				 * freed after the event has been handled. */
    int position) /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, TCL_QUEUE_MARK,
				 * possibly combined with TCL_QUEUE_ALERT_IF_EMPTY */
{
    Tcl_MutexLock(&(tsdPtr->queueMutex));
    if (tsdPtr->firstEventPtr != NULL) {
	position &= ~TCL_QUEUE_ALERT_IF_EMPTY;
    }

    if ((position & 3) == TCL_QUEUE_TAIL) {
	/*
	 * Append the event on the end of the queue.
	 */

	evPtr->nextPtr = NULL;
	if (tsdPtr->firstEventPtr == NULL) {







|
<
<
|
>







485
486
487
488
489
490
491
492


493
494
495
496
497
498
499
500
501
				 * must have been allocated the caller with
				 * malloc (Tcl_Alloc), and it becomes the
				 * property of the event queue. It will be
				 * freed after the event has been handled. */
    int position) /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, TCL_QUEUE_MARK,
				 * possibly combined with TCL_QUEUE_ALERT_IF_EMPTY */
{
    int wasEmpty = 0;



    Tcl_MutexLock(&(tsdPtr->queueMutex));
    if ((position & 3) == TCL_QUEUE_TAIL) {
	/*
	 * Append the event on the end of the queue.
	 */

	evPtr->nextPtr = NULL;
	if (tsdPtr->firstEventPtr == NULL) {
526
527
528
529
530
531
532




533
534
535
536
537
538
539
540
541
	    tsdPtr->markerEventPtr->nextPtr = evPtr;
	}
	tsdPtr->markerEventPtr = evPtr;
	if (evPtr->nextPtr == NULL) {
	    tsdPtr->lastEventPtr = evPtr;
	}
    }




    Tcl_MutexUnlock(&(tsdPtr->queueMutex));
    return position & TCL_QUEUE_ALERT_IF_EMPTY;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_DeleteEvents --
 *







>
>
>
>

|







528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
	    tsdPtr->markerEventPtr->nextPtr = evPtr;
	}
	tsdPtr->markerEventPtr = evPtr;
	if (evPtr->nextPtr == NULL) {
	    tsdPtr->lastEventPtr = evPtr;
	}
    }
    if (position & TCL_QUEUE_ALERT_IF_EMPTY) {
	wasEmpty = (tsdPtr->eventCount <= 0);
    }
    tsdPtr->eventCount++;
    Tcl_MutexUnlock(&(tsdPtr->queueMutex));
    return wasEmpty;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_DeleteEvents --
 *
600
601
602
603
604
605
606

607
608
609
610
611
612
613
	    /*
	     * Delete the event data structure.
	     */

	    hold = evPtr;
	    evPtr = evPtr->nextPtr;
	    Tcl_Free(hold);

	} else {
	    /*
	     * Event is to be retained.
	     */

	    prevPtr = evPtr;
	    evPtr = evPtr->nextPtr;







>







606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
	    /*
	     * Delete the event data structure.
	     */

	    hold = evPtr;
	    evPtr = evPtr->nextPtr;
	    Tcl_Free(hold);
	    tsdPtr->eventCount--;
	} else {
	    /*
	     * Event is to be retained.
	     */

	    prevPtr = evPtr;
	    evPtr = evPtr->nextPtr;
643
644
645
646
647
648
649
650
651

652
653
654
655
656
657
658
				 * TCL_FILE_EVENTS, TCL_TIMER_EVENTS, or other
				 * flags defined elsewhere. Events not
				 * matching this will be skipped for
				 * processing later. */
{
    Tcl_Event *evPtr, *prevPtr;
    Tcl_EventProc *proc;
    int result;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);


    /*
     * Asynchronous event handlers are considered to be the highest priority
     * events, and so must be invoked before we process events on the event
     * queue.
     */








|

>







650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
				 * TCL_FILE_EVENTS, TCL_TIMER_EVENTS, or other
				 * flags defined elsewhere. Events not
				 * matching this will be skipped for
				 * processing later. */
{
    Tcl_Event *evPtr, *prevPtr;
    Tcl_EventProc *proc;
    Tcl_Size eventCount;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
    int result;

    /*
     * Asynchronous event handlers are considered to be the highest priority
     * events, and so must be invoked before we process events on the event
     * queue.
     */

700
701
702
703
704
705
706





707
708


709
710
711

712
713
714
715
716
717
718
	evPtr->proc = NULL;

	/*
	 * Release the lock before calling the event function. This allows
	 * other threads to post events if we enter a recursive event loop in
	 * this thread. Note that we are making the assumption that if the
	 * proc returns 0, the event is still in the list.





	 */



	Tcl_MutexUnlock(&(tsdPtr->queueMutex));
	result = proc(evPtr, flags);
	Tcl_MutexLock(&(tsdPtr->queueMutex));


	if (result) {
	    /*
	     * The event was processed, so remove it from the queue.
	     */

	    if (tsdPtr->firstEventPtr == evPtr) {







>
>
>
>
>


>
>



>







708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
	evPtr->proc = NULL;

	/*
	 * Release the lock before calling the event function. This allows
	 * other threads to post events if we enter a recursive event loop in
	 * this thread. Note that we are making the assumption that if the
	 * proc returns 0, the event is still in the list.
	 *
	 * The eventCount is remembered and set to zero that the next
	 * level of Tcl_ServiceEvent() gets an empty condition for the
	 * Tcl_ThreadQueueEvent() to perform optional wakeups.
	 * On exit of the next level, the eventCount is readjusted.
	 */

	eventCount = tsdPtr->eventCount;
	tsdPtr->eventCount = 0;
	Tcl_MutexUnlock(&(tsdPtr->queueMutex));
	result = proc(evPtr, flags);
	Tcl_MutexLock(&(tsdPtr->queueMutex));
	tsdPtr->eventCount += eventCount;

	if (result) {
	    /*
	     * The event was processed, so remove it from the queue.
	     */

	    if (tsdPtr->firstEventPtr == evPtr) {
739
740
741
742
743
744
745

746
747
748
749
750
751
752
		    }
		} else {
		    evPtr = NULL;
		}
	    }
	    if (evPtr) {
		Tcl_Free(evPtr);

	    }
	    Tcl_MutexUnlock(&(tsdPtr->queueMutex));
	    return 1;
	} else {
	    /*
	     * The event wasn't actually handled, so we have to restore the
	     * proc field to allow the event to be attempted again.







>







755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
		    }
		} else {
		    evPtr = NULL;
		}
	    }
	    if (evPtr) {
		Tcl_Free(evPtr);
		tsdPtr->eventCount--;
	    }
	    Tcl_MutexUnlock(&(tsdPtr->queueMutex));
	    return 1;
	} else {
	    /*
	     * The event wasn't actually handled, so we have to restore the
	     * proc field to allow the event to be attempted again.