Attachment "tclNotify.patch" to
ticket [9e69e2c602]
added by
chw
2024-12-06 08:21:26.
Index: generic/tclNotify.c
==================================================================
--- generic/tclNotify.c
+++ generic/tclNotify.c
@@ -55,12 +55,14 @@
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. */
+ int eventCount; /* Number of entries, but refer to comments in
+ * Tcl_ServiceEvent(). */
Tcl_Mutex queueMutex; /* Mutex to protect access to the previous
- * three fields. */
+ * 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
@@ -184,10 +186,11 @@
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);
@@ -484,14 +487,13 @@
* 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 (tsdPtr->firstEventPtr != NULL) {
- position &= ~TCL_QUEUE_ALERT_IF_EMPTY;
- }
if ((position & 3) == TCL_QUEUE_TAIL) {
/*
* Append the event on the end of the queue.
*/
@@ -528,12 +530,16 @@
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 position & TCL_QUEUE_ALERT_IF_EMPTY;
+ return wasEmpty;
}
/*
*----------------------------------------------------------------------
*
@@ -602,10 +608,11 @@
*/
hold = evPtr;
evPtr = evPtr->nextPtr;
Tcl_Free(hold);
+ tsdPtr->eventCount--;
} else {
/*
* Event is to be retained.
*/
@@ -645,11 +652,11 @@
* matching this will be skipped for
* processing later. */
{
Tcl_Event *evPtr, *prevPtr;
Tcl_EventProc *proc;
- int result;
+ int result, eventCount;
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
@@ -702,15 +709,23 @@
/*
* 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.
*/
@@ -741,10 +756,11 @@
evPtr = NULL;
}
}
if (evPtr) {
Tcl_Free(evPtr);
+ tsdPtr->eventCount--;
}
Tcl_MutexUnlock(&(tsdPtr->queueMutex));
return 1;
} else {
/*