summaryrefslogtreecommitdiffstats
path: root/unix/tclSelectNotfy.c
diff options
context:
space:
mode:
authordkf <donal.k.fellows@manchester.ac.uk>2021-04-03 13:53:56 (GMT)
committerdkf <donal.k.fellows@manchester.ac.uk>2021-04-03 13:53:56 (GMT)
commit8b11f08b3cb7e5e92dd7812df02e8419e49be96d (patch)
tree87a42b23f924af5846a8c2999de5fd98db252a25 /unix/tclSelectNotfy.c
parent02855d5980f78e6e42b3a35274a26c978f9af694 (diff)
parent743881d3ce722dbba89ec98a6f5a9618e683bbf1 (diff)
downloadtcl-8b11f08b3cb7e5e92dd7812df02e8419e49be96d.zip
tcl-8b11f08b3cb7e5e92dd7812df02e8419e49be96d.tar.gz
tcl-8b11f08b3cb7e5e92dd7812df02e8419e49be96d.tar.bz2
Clean up the notifier code to not spread the hooks quite so widely
Diffstat (limited to 'unix/tclSelectNotfy.c')
-rw-r--r--unix/tclSelectNotfy.c777
1 files changed, 375 insertions, 402 deletions
diff --git a/unix/tclSelectNotfy.c b/unix/tclSelectNotfy.c
index 2c63575..e1d577f 100644
--- a/unix/tclSelectNotfy.c
+++ b/unix/tclSelectNotfy.c
@@ -216,8 +216,8 @@ extern "C" {
typedef struct {
void *hwnd; /* Messaging window. */
unsigned int *message; /* Message payload. */
- size_t wParam; /* Event-specific "word" parameter. */
- size_t lParam; /* Event-specific "long" parameter. */
+ size_t wParam; /* Event-specific "word" parameter. */
+ size_t lParam; /* Event-specific "long" parameter. */
int time; /* Event timestamp. */
int x; /* Event location (where meaningful). */
int y;
@@ -244,8 +244,8 @@ extern void __stdcall CloseHandle(void *);
extern void *__stdcall CreateEventW(void *, unsigned char, unsigned char,
void *);
extern void *__stdcall CreateWindowExW(void *, const void *, const void *,
- unsigned int, int, int, int, int, void *, void *, void *,
- void *);
+ unsigned int, int, int, int, int, void *, void *,
+ void *, void *);
extern unsigned int __stdcall DefWindowProcW(void *, int, void *, void *);
extern unsigned char __stdcall DestroyWindow(void *);
extern int __stdcall DispatchMessageW(const MSG *);
@@ -271,14 +271,17 @@ static unsigned int __stdcall NotifierProc(void *hwnd, unsigned int message,
}
#endif
#endif /* TCL_THREADS && __CYGWIN__ */
-
+/*
+ * Incorporate the base notifier implementation.
+ */
+
#include "tclUnixNotfy.c"
/*
*----------------------------------------------------------------------
*
- * Tcl_InitNotifier --
+ * TclpInitNotifier --
*
* Initializes the platform specific notifier state.
*
@@ -292,75 +295,72 @@ static unsigned int __stdcall NotifierProc(void *hwnd, unsigned int message,
*/
ClientData
-Tcl_InitNotifier(void)
+TclpInitNotifier(void)
{
- if (tclNotifierHooks.initNotifierProc) {
- return tclNotifierHooks.initNotifierProc();
- } else {
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
#if TCL_THREADS
- tsdPtr->eventReady = 0;
+ tsdPtr->eventReady = 0;
- /*
- * Initialize thread specific condition variable for this thread.
- */
- if (tsdPtr->waitCVinitialized == 0) {
+ /*
+ * Initialize thread specific condition variable for this thread.
+ */
+
+ if (tsdPtr->waitCVinitialized == 0) {
#ifdef __CYGWIN__
- WNDCLASSW clazz;
-
- clazz.style = 0;
- clazz.cbClsExtra = 0;
- clazz.cbWndExtra = 0;
- clazz.hInstance = TclWinGetTclInstance();
- clazz.hbrBackground = NULL;
- clazz.lpszMenuName = NULL;
- clazz.lpszClassName = className;
- clazz.lpfnWndProc = (void *)NotifierProc;
- clazz.hIcon = NULL;
- clazz.hCursor = NULL;
-
- RegisterClassW(&clazz);
- tsdPtr->hwnd = CreateWindowExW(NULL, clazz.lpszClassName,
- clazz.lpszClassName, 0, 0, 0, 0, 0, NULL, NULL,
- clazz.hInstance, NULL);
- tsdPtr->event = CreateEventW(NULL, 1 /* manual */,
- 0 /* !signaled */, NULL);
-#else
- pthread_cond_init(&tsdPtr->waitCV, NULL);
+ WNDCLASSW clazz;
+
+ clazz.style = 0;
+ clazz.cbClsExtra = 0;
+ clazz.cbWndExtra = 0;
+ clazz.hInstance = TclWinGetTclInstance();
+ clazz.hbrBackground = NULL;
+ clazz.lpszMenuName = NULL;
+ clazz.lpszClassName = className;
+ clazz.lpfnWndProc = (void *) NotifierProc;
+ clazz.hIcon = NULL;
+ clazz.hCursor = NULL;
+
+ RegisterClassW(&clazz);
+ tsdPtr->hwnd = CreateWindowExW(NULL, clazz.lpszClassName,
+ clazz.lpszClassName, 0, 0, 0, 0, 0, NULL, NULL,
+ clazz.hInstance, NULL);
+ tsdPtr->event = CreateEventW(NULL, 1 /* manual */,
+ 0 /* !signaled */, NULL);
+#else /* !__CYGWIN__ */
+ pthread_cond_init(&tsdPtr->waitCV, NULL);
#endif /* __CYGWIN__ */
- tsdPtr->waitCVinitialized = 1;
- }
+ tsdPtr->waitCVinitialized = 1;
+ }
- pthread_mutex_lock(&notifierInitMutex);
+ pthread_mutex_lock(&notifierInitMutex);
#if defined(HAVE_PTHREAD_ATFORK)
- /*
- * Install pthread_atfork handlers to clean up the notifier in the
- * child of a fork.
- */
+ /*
+ * Install pthread_atfork handlers to clean up the notifier in the child
+ * of a fork.
+ */
- if (!atForkInit) {
- int result = pthread_atfork(NULL, NULL, AtForkChild);
+ if (!atForkInit) {
+ int result = pthread_atfork(NULL, NULL, AtForkChild);
- if (result) {
- Tcl_Panic("Tcl_InitNotifier: pthread_atfork failed");
- }
- atForkInit = 1;
+ if (result) {
+ Tcl_Panic("Tcl_InitNotifier: %s", "pthread_atfork failed");
}
+ atForkInit = 1;
+ }
#endif /* HAVE_PTHREAD_ATFORK */
- notifierCount++;
- pthread_mutex_unlock(&notifierInitMutex);
-
+ notifierCount++;
+ pthread_mutex_unlock(&notifierInitMutex);
#endif /* TCL_THREADS */
- return tsdPtr;
- }
+
+ return tsdPtr;
}
/*
*----------------------------------------------------------------------
*
- * Tcl_FinalizeNotifier --
+ * TclpFinalizeNotifier --
*
* This function is called to cleanup the notifier state before a thread
* is terminated.
@@ -376,67 +376,62 @@ Tcl_InitNotifier(void)
*/
void
-Tcl_FinalizeNotifier(
+TclpFinalizeNotifier(
ClientData clientData)
{
- if (tclNotifierHooks.finalizeNotifierProc) {
- tclNotifierHooks.finalizeNotifierProc(clientData);
- return;
- } else {
#if TCL_THREADS
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- pthread_mutex_lock(&notifierInitMutex);
- notifierCount--;
+ pthread_mutex_lock(&notifierInitMutex);
+ notifierCount--;
- /*
- * If this is the last thread to use the notifier, close the notifier
- * pipe and wait for the background thread to terminate.
- */
+ /*
+ * If this is the last thread to use the notifier, close the notifier pipe
+ * and wait for the background thread to terminate.
+ */
- if (notifierCount == 0 && triggerPipe != -1) {
- if (write(triggerPipe, "q", 1) != 1) {
- Tcl_Panic("Tcl_FinalizeNotifier: %s",
- "unable to write 'q' to triggerPipe");
- }
- close(triggerPipe);
- pthread_mutex_lock(&notifierMutex);
- while(triggerPipe != -1) {
- pthread_cond_wait(&notifierCV, &notifierMutex);
- }
- pthread_mutex_unlock(&notifierMutex);
- if (notifierThreadRunning) {
- int result = pthread_join((pthread_t) notifierThread, NULL);
+ if (notifierCount == 0 && triggerPipe != -1) {
+ if (write(triggerPipe, "q", 1) != 1) {
+ Tcl_Panic("Tcl_FinalizeNotifier: %s",
+ "unable to write 'q' to triggerPipe");
+ }
+ close(triggerPipe);
+ pthread_mutex_lock(&notifierMutex);
+ while(triggerPipe != -1) {
+ pthread_cond_wait(&notifierCV, &notifierMutex);
+ }
+ pthread_mutex_unlock(&notifierMutex);
+ if (notifierThreadRunning) {
+ int result = pthread_join((pthread_t) notifierThread, NULL);
- if (result) {
- Tcl_Panic("Tcl_FinalizeNotifier: %s",
- "unable to join notifier thread");
- }
- notifierThreadRunning = 0;
+ if (result) {
+ Tcl_Panic("Tcl_FinalizeNotifier: %s",
+ "unable to join notifier thread");
}
+ notifierThreadRunning = 0;
}
+ }
- /*
- * Clean up any synchronization objects in the thread local storage.
- */
+ /*
+ * Clean up any synchronization objects in the thread local storage.
+ */
#ifdef __CYGWIN__
- DestroyWindow(tsdPtr->hwnd);
- CloseHandle(tsdPtr->event);
-#else /* __CYGWIN__ */
- pthread_cond_destroy(&tsdPtr->waitCV);
+ DestroyWindow(tsdPtr->hwnd);
+ CloseHandle(tsdPtr->event);
+#else /* !__CYGWIN__ */
+ pthread_cond_destroy(&tsdPtr->waitCV);
#endif /* __CYGWIN__ */
- tsdPtr->waitCVinitialized = 0;
+ tsdPtr->waitCVinitialized = 0;
- pthread_mutex_unlock(&notifierInitMutex);
+ pthread_mutex_unlock(&notifierInitMutex);
#endif /* TCL_THREADS */
- }
}
/*
*----------------------------------------------------------------------
*
- * Tcl_CreateFileHandler --
+ * TclpCreateFileHandler --
*
* This function registers a file handler with the select notifier.
*
@@ -450,7 +445,7 @@ Tcl_FinalizeNotifier(
*/
void
-Tcl_CreateFileHandler(
+TclpCreateFileHandler(
int fd, /* Handle of stream to watch. */
int mask, /* OR'ed combination of TCL_READABLE,
* TCL_WRITABLE, and TCL_EXCEPTION: indicates
@@ -460,59 +455,48 @@ Tcl_CreateFileHandler(
* event. */
ClientData clientData) /* Arbitrary data to pass to proc. */
{
- if (tclNotifierHooks.createFileHandlerProc) {
- tclNotifierHooks.createFileHandlerProc(fd, mask, proc, clientData);
- return;
- } else {
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- FileHandler *filePtr;
-
- for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL;
- filePtr = filePtr->nextPtr) {
- if (filePtr->fd == fd) {
- break;
- }
- }
- if (filePtr == NULL) {
- filePtr = (FileHandler *)Tcl_Alloc(sizeof(FileHandler));
- filePtr->fd = fd;
- filePtr->readyMask = 0;
- filePtr->nextPtr = tsdPtr->firstFileHandlerPtr;
- tsdPtr->firstFileHandlerPtr = filePtr;
- }
- filePtr->proc = proc;
- filePtr->clientData = clientData;
- filePtr->mask = mask;
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ FileHandler *filePtr = LookUpFileHandler(tsdPtr, fd, NULL);
+
+ if (filePtr == NULL) {
+ filePtr = (FileHandler *) Tcl_Alloc(sizeof(FileHandler));
+ filePtr->fd = fd;
+ filePtr->readyMask = 0;
+ filePtr->nextPtr = tsdPtr->firstFileHandlerPtr;
+ tsdPtr->firstFileHandlerPtr = filePtr;
+ }
+ filePtr->proc = proc;
+ filePtr->clientData = clientData;
+ filePtr->mask = mask;
- /*
- * Update the check masks for this file.
- */
+ /*
+ * Update the check masks for this file.
+ */
- if (mask & TCL_READABLE) {
- FD_SET(fd, &tsdPtr->checkMasks.readable);
- } else {
- FD_CLR(fd, &tsdPtr->checkMasks.readable);
- }
- if (mask & TCL_WRITABLE) {
- FD_SET(fd, &tsdPtr->checkMasks.writable);
- } else {
- FD_CLR(fd, &tsdPtr->checkMasks.writable);
- }
- if (mask & TCL_EXCEPTION) {
- FD_SET(fd, &tsdPtr->checkMasks.exception);
- } else {
- FD_CLR(fd, &tsdPtr->checkMasks.exception);
- }
- if (tsdPtr->numFdBits <= fd) {
- tsdPtr->numFdBits = fd+1;
- }
+ if (mask & TCL_READABLE) {
+ FD_SET(fd, &tsdPtr->checkMasks.readable);
+ } else {
+ FD_CLR(fd, &tsdPtr->checkMasks.readable);
+ }
+ if (mask & TCL_WRITABLE) {
+ FD_SET(fd, &tsdPtr->checkMasks.writable);
+ } else {
+ FD_CLR(fd, &tsdPtr->checkMasks.writable);
+ }
+ if (mask & TCL_EXCEPTION) {
+ FD_SET(fd, &tsdPtr->checkMasks.exception);
+ } else {
+ FD_CLR(fd, &tsdPtr->checkMasks.exception);
+ }
+ if (tsdPtr->numFdBits <= fd) {
+ tsdPtr->numFdBits = fd + 1;
}
}
/*
*----------------------------------------------------------------------
*
- * Tcl_DeleteFileHandler --
+ * TclpDeleteFileHandler --
*
* Cancel a previously-arranged callback arrangement for a file.
*
@@ -526,75 +510,65 @@ Tcl_CreateFileHandler(
*/
void
-Tcl_DeleteFileHandler(
+TclpDeleteFileHandler(
int fd) /* Stream id for which to remove callback
* function. */
{
- if (tclNotifierHooks.deleteFileHandlerProc) {
- tclNotifierHooks.deleteFileHandlerProc(fd);
- return;
- } else {
- FileHandler *filePtr, *prevPtr;
- int i;
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ FileHandler *filePtr, *prevPtr;
+ int i;
- /*
- * Find the entry for the given file (and return if there isn't one).
- */
+ /*
+ * 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;
- }
- }
+ filePtr = LookUpFileHandler(tsdPtr, fd, &prevPtr);
+ if (filePtr == NULL) {
+ return;
+ }
- /*
- * Update the check masks for this file.
- */
+ /*
+ * Update the check masks for this file.
+ */
- if (filePtr->mask & TCL_READABLE) {
- FD_CLR(fd, &tsdPtr->checkMasks.readable);
- }
- if (filePtr->mask & TCL_WRITABLE) {
- FD_CLR(fd, &tsdPtr->checkMasks.writable);
- }
- if (filePtr->mask & TCL_EXCEPTION) {
- FD_CLR(fd, &tsdPtr->checkMasks.exception);
- }
+ if (filePtr->mask & TCL_READABLE) {
+ FD_CLR(fd, &tsdPtr->checkMasks.readable);
+ }
+ if (filePtr->mask & TCL_WRITABLE) {
+ FD_CLR(fd, &tsdPtr->checkMasks.writable);
+ }
+ if (filePtr->mask & TCL_EXCEPTION) {
+ FD_CLR(fd, &tsdPtr->checkMasks.exception);
+ }
- /*
- * Find current max fd.
- */
+ /*
+ * Find current max fd.
+ */
- if (fd+1 == tsdPtr->numFdBits) {
- int numFdBits = 0;
+ if (fd + 1 == tsdPtr->numFdBits) {
+ int numFdBits = 0;
- for (i = fd-1; i >= 0; i--) {
- if (FD_ISSET(i, &tsdPtr->checkMasks.readable)
- || FD_ISSET(i, &tsdPtr->checkMasks.writable)
- || FD_ISSET(i, &tsdPtr->checkMasks.exception)) {
- numFdBits = i+1;
- break;
- }
+ for (i = fd - 1; i >= 0; i--) {
+ if (FD_ISSET(i, &tsdPtr->checkMasks.readable)
+ || FD_ISSET(i, &tsdPtr->checkMasks.writable)
+ || FD_ISSET(i, &tsdPtr->checkMasks.exception)) {
+ numFdBits = i + 1;
+ break;
}
- tsdPtr->numFdBits = numFdBits;
}
+ tsdPtr->numFdBits = numFdBits;
+ }
- /*
- * Clean up information in the callback record.
- */
+ /*
+ * Clean up information in the callback record.
+ */
- if (prevPtr == NULL) {
- tsdPtr->firstFileHandlerPtr = filePtr->nextPtr;
- } else {
- prevPtr->nextPtr = filePtr->nextPtr;
- }
- Tcl_Free(filePtr);
+ if (prevPtr == NULL) {
+ tsdPtr->firstFileHandlerPtr = filePtr->nextPtr;
+ } else {
+ prevPtr->nextPtr = filePtr->nextPtr;
}
+ Tcl_Free(filePtr);
}
#if defined(__CYGWIN__)
@@ -625,7 +599,7 @@ NotifierProc(
/*
*----------------------------------------------------------------------
*
- * Tcl_WaitForEvent --
+ * TclpWaitForEvent --
*
* This function is called by Tcl_DoOneEvent to wait for new events on
* the message queue. If the block time is 0, then Tcl_WaitForEvent just
@@ -641,265 +615,261 @@ NotifierProc(
*/
int
-Tcl_WaitForEvent(
+TclpWaitForEvent(
const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
{
- if (tclNotifierHooks.waitForEventProc) {
- return tclNotifierHooks.waitForEventProc(timePtr);
- } else {
- FileHandler *filePtr;
- int mask;
- Tcl_Time vTime;
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ FileHandler *filePtr;
+ int mask;
+ Tcl_Time vTime;
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
#if TCL_THREADS
- int waitForFiles;
+ int waitForFiles;
# ifdef __CYGWIN__
- MSG msg;
+ MSG msg;
# endif /* __CYGWIN__ */
#else /* !TCL_THREADS */
- /*
- * Impl. notes: timeout & timeoutPtr are used if, and only if threads
- * are not enabled. They are the arguments for the regular select()
- * used when the core is not thread-enabled.
- */
+ /*
+ * Impl. notes: timeout & timeoutPtr are used if, and only if threads are
+ * not enabled. They are the arguments for the regular select() used when
+ * the core is not thread-enabled.
+ */
- struct timeval timeout, *timeoutPtr;
- int numFound;
+ struct timeval timeout, *timeoutPtr;
+ int numFound;
#endif /* TCL_THREADS */
+ /*
+ * Set up the timeout structure. Note that if there are no events to check
+ * for, we return with a negative result rather than blocking forever.
+ */
+
+ if (timePtr != NULL) {
/*
- * Set up the timeout structure. Note that if there are no events to
- * check for, we return with a negative result rather than blocking
- * forever.
+ * TIP #233 (Virtualized Time). Is virtual time in effect? And do we
+ * actually have something to scale? If yes to both then we call the
+ * handler to do this scaling.
*/
- if (timePtr != NULL) {
- /*
- * TIP #233 (Virtualized Time). Is virtual time in effect? And do
- * we actually have something to scale? If yes to both then we
- * call the handler to do this scaling.
- */
-
- if (timePtr->sec != 0 || timePtr->usec != 0) {
- vTime = *timePtr;
- tclScaleTimeProcPtr(&vTime, tclTimeClientData);
- timePtr = &vTime;
- }
+ if (timePtr->sec != 0 || timePtr->usec != 0) {
+ vTime = *timePtr;
+ TclScaleTime(&vTime);
+ timePtr = &vTime;
+ }
#if !TCL_THREADS
- timeout.tv_sec = timePtr->sec;
- timeout.tv_usec = timePtr->usec;
- timeoutPtr = &timeout;
- } else if (tsdPtr->numFdBits == 0) {
- /*
- * If there are no threads, no timeout, and no fds registered,
- * then there are no events possible and we must avoid deadlock.
- * Note that this is not entirely correct because there might be a
- * signal that could interrupt the select call, but we don't
- * handle that case if we aren't using threads.
- */
+ timeout.tv_sec = timePtr->sec;
+ timeout.tv_usec = timePtr->usec;
+ timeoutPtr = &timeout;
+ } else if (tsdPtr->numFdBits == 0) {
+ /*
+ * If there are no threads, no timeout, and no fds registered, then
+ * there are no events possible and we must avoid deadlock. Note that
+ * this is not entirely correct because there might be a signal that
+ * could interrupt the select call, but we don't handle that case if
+ * we aren't using threads.
+ */
- return -1;
- } else {
- timeoutPtr = NULL;
+ return -1;
+ } else {
+ timeoutPtr = NULL;
#endif /* !TCL_THREADS */
- }
+ }
#if TCL_THREADS
- /*
- * Start notifier thread and place this thread on the list of
- * interested threads, signal the notifier thread, and wait for a
- * response or a timeout.
- */
- StartNotifierThread("Tcl_WaitForEvent");
+ /*
+ * Start notifier thread and place this thread on the list of interested
+ * threads, signal the notifier thread, and wait for a response or a
+ * timeout.
+ */
- pthread_mutex_lock(&notifierMutex);
+ StartNotifierThread("Tcl_WaitForEvent");
+
+ pthread_mutex_lock(&notifierMutex);
- if (timePtr != NULL && timePtr->sec == 0 && (timePtr->usec == 0
+ if (timePtr != NULL && timePtr->sec == 0 && (timePtr->usec == 0
#if defined(__APPLE__) && defined(__LP64__)
- /*
- * On 64-bit Darwin, pthread_cond_timedwait() appears to have
- * a bug that causes it to wait forever when passed an
- * absolute time which has already been exceeded by the system
- * time; as a workaround, when given a very brief timeout,
- * just do a poll. [Bug 1457797]
- */
- || timePtr->usec < 10
-#endif /* __APPLE__ && __LP64__ */
- )) {
/*
- * Cannot emulate a polling select with a polling condition
- * variable. Instead, pretend to wait for files and tell the
- * notifier thread what we are doing. The notifier thread makes
- * sure it goes through select with its select mask in the same
- * state as ours currently is. We block until that happens.
+ * On 64-bit Darwin, pthread_cond_timedwait() appears to have a
+ * bug that causes it to wait forever when passed an absolute time
+ * which has already been exceeded by the system time; as a
+ * workaround, when given a very brief timeout, just do a poll.
+ * [Bug 1457797]
*/
+ || timePtr->usec < 10
+#endif /* __APPLE__ && __LP64__ */
+ )) {
+ /*
+ * Cannot emulate a polling select with a polling condition variable.
+ * Instead, pretend to wait for files and tell the notifier thread
+ * what we are doing. The notifier thread makes sure it goes through
+ * select with its select mask in the same state as ours currently is.
+ * We block until that happens.
+ */
- waitForFiles = 1;
- tsdPtr->pollState = POLL_WANT;
- timePtr = NULL;
- } else {
- waitForFiles = (tsdPtr->numFdBits > 0);
- tsdPtr->pollState = 0;
- }
+ waitForFiles = 1;
+ tsdPtr->pollState = POLL_WANT;
+ timePtr = NULL;
+ } else {
+ waitForFiles = (tsdPtr->numFdBits > 0);
+ tsdPtr->pollState = 0;
+ }
- if (waitForFiles) {
- /*
- * Add the ThreadSpecificData structure of this thread to the list
- * of ThreadSpecificData structures of all threads that are
- * waiting on file events.
- */
+ if (waitForFiles) {
+ /*
+ * Add the ThreadSpecificData structure of this thread to the list of
+ * ThreadSpecificData structures of all threads that are waiting on
+ * file events.
+ */
- tsdPtr->nextPtr = waitingListPtr;
- if (waitingListPtr) {
- waitingListPtr->prevPtr = tsdPtr;
- }
- tsdPtr->prevPtr = 0;
- waitingListPtr = tsdPtr;
- tsdPtr->onList = 1;
+ tsdPtr->nextPtr = waitingListPtr;
+ if (waitingListPtr) {
+ waitingListPtr->prevPtr = tsdPtr;
+ }
+ tsdPtr->prevPtr = 0;
+ waitingListPtr = tsdPtr;
+ tsdPtr->onList = 1;
- if ((write(triggerPipe, "", 1) == -1) && (errno != EAGAIN)) {
- Tcl_Panic("Tcl_WaitForEvent: %s",
- "unable to write to triggerPipe");
- }
+ if ((write(triggerPipe, "", 1) == -1) && (errno != EAGAIN)) {
+ Tcl_Panic("Tcl_WaitForEvent: %s",
+ "unable to write to triggerPipe");
}
+ }
- FD_ZERO(&tsdPtr->readyMasks.readable);
- FD_ZERO(&tsdPtr->readyMasks.writable);
- FD_ZERO(&tsdPtr->readyMasks.exception);
+ FD_ZERO(&tsdPtr->readyMasks.readable);
+ FD_ZERO(&tsdPtr->readyMasks.writable);
+ FD_ZERO(&tsdPtr->readyMasks.exception);
- if (!tsdPtr->eventReady) {
+ if (!tsdPtr->eventReady) {
#ifdef __CYGWIN__
- if (!PeekMessageW(&msg, NULL, 0, 0, 0)) {
- unsigned int timeout;
+ if (!PeekMessageW(&msg, NULL, 0, 0, 0)) {
+ unsigned int timeout;
- if (timePtr) {
- timeout = timePtr->sec * 1000 + timePtr->usec / 1000;
- } else {
- timeout = 0xFFFFFFFF;
- }
- pthread_mutex_unlock(&notifierMutex);
- MsgWaitForMultipleObjects(1, &tsdPtr->event, 0, timeout, 1279);
- pthread_mutex_lock(&notifierMutex);
+ if (timePtr) {
+ timeout = timePtr->sec * 1000 + timePtr->usec / 1000;
+ } else {
+ timeout = 0xFFFFFFFF;
}
+ pthread_mutex_unlock(&notifierMutex);
+ MsgWaitForMultipleObjects(1, &tsdPtr->event, 0, timeout, 1279);
+ pthread_mutex_lock(&notifierMutex);
+ }
#else /* !__CYGWIN__ */
- if (timePtr != NULL) {
- Tcl_Time now;
- struct timespec ptime;
+ if (timePtr != NULL) {
+ Tcl_Time now;
+ struct timespec ptime;
- Tcl_GetTime(&now);
- ptime.tv_sec = timePtr->sec + now.sec +
- (timePtr->usec + now.usec) / 1000000;
- ptime.tv_nsec = 1000 * ((timePtr->usec + now.usec) % 1000000);
+ Tcl_GetTime(&now);
+ ptime.tv_sec = timePtr->sec + now.sec +
+ (timePtr->usec + now.usec) / 1000000;
+ ptime.tv_nsec = 1000 * ((timePtr->usec + now.usec) % 1000000);
- pthread_cond_timedwait(&tsdPtr->waitCV, &notifierMutex, &ptime);
- } else {
- pthread_cond_wait(&tsdPtr->waitCV, &notifierMutex);
- }
-#endif /* __CYGWIN__ */
+ pthread_cond_timedwait(&tsdPtr->waitCV, &notifierMutex, &ptime);
+ } else {
+ pthread_cond_wait(&tsdPtr->waitCV, &notifierMutex);
}
- tsdPtr->eventReady = 0;
+#endif /* __CYGWIN__ */
+ }
+ tsdPtr->eventReady = 0;
#ifdef __CYGWIN__
- while (PeekMessageW(&msg, NULL, 0, 0, 0)) {
- /*
- * Retrieve and dispatch the message.
- */
+ while (PeekMessageW(&msg, NULL, 0, 0, 0)) {
+ /*
+ * Retrieve and dispatch the message.
+ */
- unsigned int result = GetMessageW(&msg, NULL, 0, 0);
+ unsigned int result = GetMessageW(&msg, NULL, 0, 0);
- if (result == 0) {
- PostQuitMessage(msg.wParam);
- /* What to do here? */
- } else if (result != (unsigned int) -1) {
- TranslateMessage(&msg);
- DispatchMessageW(&msg);
- }
+ if (result == 0) {
+ PostQuitMessage(msg.wParam);
+ /* What to do here? */
+ } else if (result != (unsigned int) -1) {
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
}
- ResetEvent(tsdPtr->event);
+ }
+ ResetEvent(tsdPtr->event);
#endif /* __CYGWIN__ */
- 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 (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;
- if ((write(triggerPipe, "", 1) == -1) && (errno != EAGAIN)) {
- Tcl_Panic("Tcl_WaitForEvent: %s",
- "unable to write to triggerPipe");
- }
+ 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;
+ if ((write(triggerPipe, "", 1) == -1) && (errno != EAGAIN)) {
+ Tcl_Panic("Tcl_WaitForEvent: %s",
+ "unable to write to triggerPipe");
+ }
+ }
#else /* !TCL_THREADS */
- tsdPtr->readyMasks = tsdPtr->checkMasks;
- numFound = select(tsdPtr->numFdBits, &tsdPtr->readyMasks.readable,
- &tsdPtr->readyMasks.writable, &tsdPtr->readyMasks.exception,
- timeoutPtr);
+ tsdPtr->readyMasks = tsdPtr->checkMasks;
+ numFound = select(tsdPtr->numFdBits, &tsdPtr->readyMasks.readable,
+ &tsdPtr->readyMasks.writable, &tsdPtr->readyMasks.exception,
+ timeoutPtr);
- /*
- * Some systems don't clear the masks after an error, so we have to do
- * it here.
- */
+ /*
+ * Some systems don't clear the masks after an error, so we have to do it
+ * here.
+ */
- if (numFound == -1) {
- FD_ZERO(&tsdPtr->readyMasks.readable);
- FD_ZERO(&tsdPtr->readyMasks.writable);
- FD_ZERO(&tsdPtr->readyMasks.exception);
- }
+ if (numFound == -1) {
+ FD_ZERO(&tsdPtr->readyMasks.readable);
+ FD_ZERO(&tsdPtr->readyMasks.writable);
+ FD_ZERO(&tsdPtr->readyMasks.exception);
+ }
#endif /* TCL_THREADS */
- /*
- * Queue all detected file events before returning.
- */
+ /*
+ * Queue all detected file events before returning.
+ */
- for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL);
- filePtr = filePtr->nextPtr) {
- mask = 0;
- if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.readable)) {
- mask |= TCL_READABLE;
- }
- if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.writable)) {
- mask |= TCL_WRITABLE;
- }
- if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.exception)) {
- mask |= TCL_EXCEPTION;
- }
+ for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL);
+ filePtr = filePtr->nextPtr) {
+ mask = 0;
+ if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.readable)) {
+ mask |= TCL_READABLE;
+ }
+ if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.writable)) {
+ mask |= TCL_WRITABLE;
+ }
+ if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.exception)) {
+ mask |= TCL_EXCEPTION;
+ }
- if (!mask) {
- continue;
- }
+ if (!mask) {
+ continue;
+ }
- /*
- * Don't bother to queue an event if the mask was previously
- * non-zero since an event must still be on the queue.
- */
+ /*
+ * Don't bother to queue an event if the mask was previously non-zero
+ * since an event must still be on the queue.
+ */
- if (filePtr->readyMask == 0) {
- FileHandlerEvent *fileEvPtr =
- (FileHandlerEvent *)Tcl_Alloc(sizeof(FileHandlerEvent));
+ if (filePtr->readyMask == 0) {
+ FileHandlerEvent *fileEvPtr =
+ (FileHandlerEvent *) Tcl_Alloc(sizeof(FileHandlerEvent));
- fileEvPtr->header.proc = FileHandlerEventProc;
- fileEvPtr->fd = filePtr->fd;
- Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
- }
- filePtr->readyMask = mask;
+ fileEvPtr->header.proc = FileHandlerEventProc;
+ fileEvPtr->fd = filePtr->fd;
+ Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
}
+ filePtr->readyMask = mask;
+ }
#if TCL_THREADS
- pthread_mutex_unlock(&notifierMutex);
+ pthread_mutex_unlock(&notifierMutex);
#endif /* TCL_THREADS */
- return 0;
- }
+ return 0;
}
/*
@@ -916,8 +886,9 @@ Tcl_WaitForEvent(
* byte to a special pipe that the notifier thread is monitoring.
*
* Result:
- * None. Once started, this routine never exits. It dies with the overall
- * process.
+ * None. Once started, this routine normally never exits and usually dies
+ * with the overall process, but it can be shut down if the Tcl library
+ * is finalized.
*
* Side effects:
* The trigger pipe used to signal the notifier thread is created when
@@ -1048,7 +1019,7 @@ NotifierThreadProc(
for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) {
found = 0;
- for (i = tsdPtr->numFdBits-1; i >= 0; --i) {
+ for (i = tsdPtr->numFdBits - 1; i >= 0; --i) {
if (FD_ISSET(i, &tsdPtr->checkMasks.readable)
&& FD_ISSET(i, &readableMask)) {
FD_SET(i, &tsdPtr->readyMasks.readable);
@@ -1113,6 +1084,8 @@ NotifierThreadProc(
#endif /* TCL_THREADS */
#endif /* (!NOTIFIER_EPOLL && !NOTIFIER_KQUEUE) || !TCL_THREADS */
+#else
+TCL_MAC_EMPTY_FILE(unix_tclSelectNotfy_c)
#endif /* !HAVE_COREFOUNDATION */
/*