diff options
Diffstat (limited to 'unix/tclUnixNotfy.c')
| -rw-r--r-- | unix/tclUnixNotfy.c | 455 | 
1 files changed, 367 insertions, 88 deletions
| diff --git a/unix/tclUnixNotfy.c b/unix/tclUnixNotfy.c index e8860df..b234667 100644 --- a/unix/tclUnixNotfy.c +++ b/unix/tclUnixNotfy.c @@ -7,10 +7,8 @@   *   * 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.41 2009/12/17 00:06:21 nijtmans Exp $ + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES.   */  #include "tclInt.h" @@ -53,13 +51,13 @@ typedef struct FileHandlerEvent {  /*   * The following structure contains a set of select() masks to track readable, - * writable, and exceptional conditions. + * writable, and exception conditions.   */  typedef struct SelectMasks {      fd_set readable;      fd_set writable; -    fd_set exceptional; +    fd_set exception;  } SelectMasks;  /* @@ -93,13 +91,20 @@ typedef struct ThreadSpecificData {  				 * from these pointers. You must hold the  				 * notifierMutex lock before accessing these  				 * fields. */ +#ifdef __CYGWIN__ +    void *event;     /* Any other thread alerts a notifier +	 * that an event is ready to be processed +	 * by sending this event. */ +    void *hwnd;			/* Messaging window. */ +#else /* !__CYGWIN__ */      Tcl_Condition waitCV;	/* Any other thread alerts a notifier that an  				 * event is ready to be processed by signaling  				 * this condition variable. */ +#endif /* __CYGWIN__ */      int eventReady;		/* True if an event is ready to be processed.  				 * Used as condition flag together with waitCV  				 * above. */ -#endif +#endif /* TCL_THREADS */  } ThreadSpecificData;  static Tcl_ThreadDataKey dataKey; @@ -115,6 +120,15 @@ static Tcl_ThreadDataKey dataKey;  static int notifierCount = 0;  /* + * The following static stores the process ID of the initialized notifier + * thread. If it changes, we have passed a fork and we should start a new + * notifier thread. + * + * You must hold the notifierMutex lock before accessing this variable. + */ +static pid_t processIDInitialized = 0; + +/*   * The following variable points to the head of a doubly-linked list of   * ThreadSpecificData structures for all threads that are currently waiting on   * an event. @@ -172,7 +186,7 @@ static Tcl_Condition notifierCV;  static Tcl_ThreadId notifierThread; -#endif +#endif /* TCL_THREADS */  /*   * Static routines defined in this file. @@ -180,8 +194,69 @@ static Tcl_ThreadId notifierThread;  #ifdef TCL_THREADS  static void	NotifierThreadProc(ClientData clientData); -#endif +#if defined(HAVE_PTHREAD_ATFORK) && !defined(__APPLE__) && !defined(__hpux) +static int	atForkInit = 0; +static void	AtForkPrepare(void); +static void	AtForkParent(void); +static void	AtForkChild(void); +#endif /* HAVE_PTHREAD_ATFORK */ +#endif /* TCL_THREADS */  static int	FileHandlerEventProc(Tcl_Event *evPtr, int flags); + +/* + * Import of Windows API when building threaded with Cygwin. + */ + +#if defined(TCL_THREADS) && defined(__CYGWIN__) +typedef struct { +    void *hwnd; +    unsigned int *message; +    int wParam; +    int lParam; +    int time; +    int x; +    int y; +} MSG; + +typedef struct { +    unsigned int style; +    void *lpfnWndProc; +    int cbClsExtra; +    int cbWndExtra; +    void *hInstance; +    void *hIcon; +    void *hCursor; +    void *hbrBackground; +    void *lpszMenuName; +    const void *lpszClassName; +} WNDCLASS; + +extern void __stdcall	CloseHandle(void *); +extern void *__stdcall	CreateEventW(void *, unsigned char, unsigned char, +			    void *); +extern void * __stdcall	CreateWindowExW(void *, const void *, const void *, +			    DWORD, int, int, int, int, void *, void *, void *, void *); +extern DWORD __stdcall	DefWindowProcW(void *, int, void *, void *); +extern unsigned char __stdcall	DestroyWindow(void *); +extern int __stdcall	DispatchMessageW(const MSG *); +extern unsigned char __stdcall	GetMessageW(MSG *, void *, int, int); +extern void __stdcall	MsgWaitForMultipleObjects(DWORD, void *, +			    unsigned char, DWORD, DWORD); +extern unsigned char __stdcall	PeekMessageW(MSG *, void *, int, int, int); +extern unsigned char __stdcall	PostMessageW(void *, unsigned int, void *, +				    void *); +extern void __stdcall	PostQuitMessage(int); +extern void *__stdcall	RegisterClassW(const WNDCLASS *); +extern unsigned char __stdcall	ResetEvent(void *); +extern unsigned char __stdcall	TranslateMessage(const MSG *); + +/* + * Threaded-cygwin specific functions in this file: + */ + +static DWORD __stdcall	NotifierProc(void *hwnd, unsigned int message, +			    void *wParam, void *lParam); +#endif /* TCL_THREADS && __CYGWIN__ */  /*   *---------------------------------------------------------------------- @@ -206,6 +281,7 @@ Tcl_InitNotifier(void)  	return tclNotifierHooks.initNotifierProc();      } else {  	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); +  #ifdef TCL_THREADS  	tsdPtr->eventReady = 0; @@ -214,11 +290,38 @@ Tcl_InitNotifier(void)  	 */  	Tcl_MutexLock(¬ifierMutex); +#if defined(HAVE_PTHREAD_ATFORK) && !defined(__APPLE__) && !defined(__hpux) +	/* +	 * Install pthread_atfork handlers to reinitialize the notifier in the +	 * child of a fork. +	 */ + +	if (!atForkInit) { +	    int result = pthread_atfork(AtForkPrepare, AtForkParent, AtForkChild); + +	    if (result) { +		Tcl_Panic("Tcl_InitNotifier: pthread_atfork failed"); +	    } +	    atForkInit = 1; +	} +#endif /* HAVE_PTHREAD_ATFORK */ +	/* +	 * Check if my process id changed, e.g. I was forked +	 * In this case, restart the notifier thread and close the +	 * pipe to the original notifier thread +	 */ +	if (notifierCount > 0 && processIDInitialized != getpid()) { +	    notifierCount = 0; +	    processIDInitialized = 0; +	    close(triggerPipe); +	    triggerPipe = -1; +	}  	if (notifierCount == 0) {  	    if (TclpThreadCreate(¬ifierThread, NotifierThreadProc, NULL,  		    TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE) != TCL_OK) {  		Tcl_Panic("Tcl_InitNotifier: unable to start notifier thread");  	    } +	    processIDInitialized = getpid();  	}  	notifierCount++; @@ -231,8 +334,8 @@ Tcl_InitNotifier(void)  	}  	Tcl_MutexUnlock(¬ifierMutex); -#endif -	return (ClientData) tsdPtr; +#endif /* TCL_THREADS */ +	return tsdPtr;      }  } @@ -277,7 +380,8 @@ Tcl_FinalizeNotifier(  	    int result;  	    if (triggerPipe < 0) { -		Tcl_Panic("Tcl_FinalizeNotifier: notifier pipe not initialized"); +		Tcl_Panic("Tcl_FinalizeNotifier: %s", +			"notifier pipe not initialized");  	    }  	    /* @@ -292,7 +396,8 @@ Tcl_FinalizeNotifier(  	     */  	    if (write(triggerPipe, "q", 1) != 1) { -			Tcl_Panic("Tcl_FinalizeNotifier: unable to write q to triggerPipe"); +		Tcl_Panic("Tcl_FinalizeNotifier: %s", +			"unable to write q to triggerPipe");  	    }  	    close(triggerPipe);  	    while(triggerPipe >= 0) { @@ -301,7 +406,8 @@ Tcl_FinalizeNotifier(  	    result = Tcl_JoinThread(notifierThread, NULL);  	    if (result) { -		Tcl_Panic("Tcl_FinalizeNotifier: unable to join notifier thread"); +		Tcl_Panic("Tcl_FinalizeNotifier: %s", +			"unable to join notifier thread");  	    }  	} @@ -309,10 +415,14 @@ Tcl_FinalizeNotifier(  	 * Clean up any synchronization objects in the thread local storage.  	 */ +#ifdef __CYGWIN__ +	CloseHandle(tsdPtr->event); +#else /* __CYGWIN__ */  	Tcl_ConditionFinalize(&(tsdPtr->waitCV)); +#endif /* __CYGWIN__ */  	Tcl_MutexUnlock(¬ifierMutex); -#endif +#endif /* TCL_THREADS */      }  } @@ -344,12 +454,17 @@ Tcl_AlertNotifier(  	return;      } else {  #ifdef TCL_THREADS -	ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData; +	ThreadSpecificData *tsdPtr = clientData; +  	Tcl_MutexLock(¬ifierMutex);  	tsdPtr->eventReady = 1; +#   ifdef __CYGWIN__ +	PostMessageW(tsdPtr->hwnd, 1024, 0, 0); +#   else  	Tcl_ConditionNotify(&tsdPtr->waitCV); +#   endif /* __CYGWIN__ */  	Tcl_MutexUnlock(¬ifierMutex); -#endif +#endif /* TCL_THREADS */      }  } @@ -457,7 +572,7 @@ Tcl_CreateFileHandler(  	    }  	}  	if (filePtr == NULL) { -	    filePtr = (FileHandler*) ckalloc(sizeof(FileHandler)); +	    filePtr = ckalloc(sizeof(FileHandler));  	    filePtr->fd = fd;  	    filePtr->readyMask = 0;  	    filePtr->nextPtr = tsdPtr->firstFileHandlerPtr; @@ -472,19 +587,19 @@ Tcl_CreateFileHandler(  	 */  	if (mask & TCL_READABLE) { -	    FD_SET(fd, &(tsdPtr->checkMasks.readable)); +	    FD_SET(fd, &tsdPtr->checkMasks.readable);  	} else { -	    FD_CLR(fd, &(tsdPtr->checkMasks.readable)); +	    FD_CLR(fd, &tsdPtr->checkMasks.readable);  	}  	if (mask & TCL_WRITABLE) { -	    FD_SET(fd, &(tsdPtr->checkMasks.writable)); +	    FD_SET(fd, &tsdPtr->checkMasks.writable);  	} else { -	    FD_CLR(fd, &(tsdPtr->checkMasks.writable)); +	    FD_CLR(fd, &tsdPtr->checkMasks.writable);  	}  	if (mask & TCL_EXCEPTION) { -	    FD_SET(fd, &(tsdPtr->checkMasks.exceptional)); +	    FD_SET(fd, &tsdPtr->checkMasks.exception);  	} else { -	    FD_CLR(fd, &(tsdPtr->checkMasks.exceptional)); +	    FD_CLR(fd, &tsdPtr->checkMasks.exception);  	}  	if (tsdPtr->numFdBits <= fd) {  	    tsdPtr->numFdBits = fd+1; @@ -526,7 +641,7 @@ Tcl_DeleteFileHandler(  	 */  	for (prevPtr = NULL, filePtr = tsdPtr->firstFileHandlerPtr; ; -	     prevPtr = filePtr, filePtr = filePtr->nextPtr) { +		prevPtr = filePtr, filePtr = filePtr->nextPtr) {  	    if (filePtr == NULL) {  		return;  	    } @@ -540,13 +655,13 @@ Tcl_DeleteFileHandler(  	 */  	if (filePtr->mask & TCL_READABLE) { -	    FD_CLR(fd, &(tsdPtr->checkMasks.readable)); +	    FD_CLR(fd, &tsdPtr->checkMasks.readable);  	}  	if (filePtr->mask & TCL_WRITABLE) { -	    FD_CLR(fd, &(tsdPtr->checkMasks.writable)); +	    FD_CLR(fd, &tsdPtr->checkMasks.writable);  	}  	if (filePtr->mask & TCL_EXCEPTION) { -	    FD_CLR(fd, &(tsdPtr->checkMasks.exceptional)); +	    FD_CLR(fd, &tsdPtr->checkMasks.exception);  	}  	/* @@ -557,9 +672,9 @@ Tcl_DeleteFileHandler(  	    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.exceptional))) { +		if (FD_ISSET(i, &tsdPtr->checkMasks.readable) +			|| FD_ISSET(i, &tsdPtr->checkMasks.writable) +			|| FD_ISSET(i, &tsdPtr->checkMasks.exception)) {  		    numFdBits = i+1;  		    break;  		} @@ -576,7 +691,7 @@ Tcl_DeleteFileHandler(  	} else {  	    prevPtr->nextPtr = filePtr->nextPtr;  	} -	ckfree((char *) filePtr); +	ckfree(filePtr);      }  } @@ -653,6 +768,31 @@ FileHandlerEventProc(      return 1;  } +#if defined(TCL_THREADS) && defined(__CYGWIN__) + +static DWORD __stdcall +NotifierProc( +    void *hwnd, +    unsigned int message, +    void *wParam, +    void *lParam) +{ +    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + +    if (message != 1024) { +	return DefWindowProcW(hwnd, message, wParam, lParam); +    } + +    /* +     * Process all of the runnable events. +     */ + +    tsdPtr->eventReady = 1; +    Tcl_ServiceAll(); +    return 0; +} +#endif /* TCL_THREADS && __CYGWIN__ */ +  /*   *----------------------------------------------------------------------   * @@ -679,11 +819,13 @@ Tcl_WaitForEvent(  	return tclNotifierHooks.waitForEventProc(timePtr);      } else {  	FileHandler *filePtr; -	FileHandlerEvent *fileEvPtr;  	int mask;  	Tcl_Time vTime;  #ifdef TCL_THREADS  	int waitForFiles; +#   ifdef __CYGWIN__ +	MSG msg; +#   endif /* __CYGWIN__ */  #else  	/*  	 * Impl. notes: timeout & timeoutPtr are used if, and only if threads @@ -705,8 +847,8 @@ Tcl_WaitForEvent(  	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. +	     * 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) { @@ -720,17 +862,17 @@ Tcl_WaitForEvent(  	    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. +	     * 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; -#endif /* TCL_THREADS */ +#endif /* !TCL_THREADS */  	}  #ifdef TCL_THREADS @@ -739,19 +881,43 @@ Tcl_WaitForEvent(  	 * notifier thread, and wait for a response or a timeout.  	 */ +#ifdef __CYGWIN__ +	if (!tsdPtr->hwnd) { +	    WNDCLASS class; + +	    class.style = 0; +	    class.cbClsExtra = 0; +	    class.cbWndExtra = 0; +	    class.hInstance = TclWinGetTclInstance(); +	    class.hbrBackground = NULL; +	    class.lpszMenuName = NULL; +	    class.lpszClassName = L"TclNotifier"; +	    class.lpfnWndProc = NotifierProc; +	    class.hIcon = NULL; +	    class.hCursor = NULL; + +	    RegisterClassW(&class); +	    tsdPtr->hwnd = CreateWindowExW(NULL, class.lpszClassName, +		    class.lpszClassName, 0, 0, 0, 0, 0, NULL, NULL, +		    TclWinGetTclInstance(), NULL); +	    tsdPtr->event = CreateEventW(NULL, 1 /* manual */, +		    0 /* !signaled */, NULL); +	} +#endif /* __CYGWIN */ +  	Tcl_MutexLock(¬ifierMutex);  	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] +		 * 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 +#endif /* __APPLE__ && __LP64__ */  		)) {  	    /*  	     * Cannot emulate a polling select with a polling condition @@ -772,8 +938,8 @@ Tcl_WaitForEvent(  	if (waitForFiles) {  	    /*  	     * Add the ThreadSpecificData structure of this thread to the list -	     * of ThreadSpecificData structures of all threads that are waiting -	     * on file events. +	     * of ThreadSpecificData structures of all threads that are +	     * waiting on file events.  	     */  	    tsdPtr->nextPtr = waitingListPtr; @@ -784,20 +950,55 @@ Tcl_WaitForEvent(  	    waitingListPtr = tsdPtr;  	    tsdPtr->onList = 1; -	    if (write(triggerPipe, "", 1) != 1) { -			Tcl_Panic("Tcl_WaitForEvent: 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.exceptional)); +	FD_ZERO(&tsdPtr->readyMasks.readable); +	FD_ZERO(&tsdPtr->readyMasks.writable); +	FD_ZERO(&tsdPtr->readyMasks.exception);  	if (!tsdPtr->eventReady) { +#ifdef __CYGWIN__ +	    if (!PeekMessageW(&msg, NULL, 0, 0, 0)) { +		DWORD timeout; + +		if (timePtr) { +		    timeout = timePtr->sec * 1000 + timePtr->usec / 1000; +		} else { +		    timeout = 0xFFFFFFFF; +		} +		Tcl_MutexUnlock(¬ifierMutex); +		MsgWaitForMultipleObjects(1, &tsdPtr->event, 0, timeout, 1279); +		Tcl_MutexLock(¬ifierMutex); +	    } +#else  	    Tcl_ConditionWait(&tsdPtr->waitCV, ¬ifierMutex, timePtr); +#endif /* __CYGWIN__ */  	}  	tsdPtr->eventReady = 0; +#ifdef __CYGWIN__ +	while (PeekMessageW(&msg, NULL, 0, 0, 0)) { +	    /* +	     * Retrieve and dispatch the message. +	     */ + +	    DWORD result = GetMessageW(&msg, NULL, 0, 0); + +	    if (result == 0) { +		PostQuitMessage(msg.wParam); +		/* What to do here? */ +	    } else if (result != (DWORD) -1) { +		TranslateMessage(&msg); +		DispatchMessageW(&msg); +	    } +	} +	ResetEvent(tsdPtr->event); +#endif /* __CYGWIN__ */ +  	if (waitForFiles && tsdPtr->onList) {  	    /*  	     * Remove the ThreadSpecificData structure of this thread from the @@ -816,16 +1017,17 @@ Tcl_WaitForEvent(  	    }  	    tsdPtr->nextPtr = tsdPtr->prevPtr = NULL;  	    tsdPtr->onList = 0; -	    if (write(triggerPipe, "", 1) != 1) { -			Tcl_Panic("Tcl_WaitForEvent: unable to write to triggerPipe"); +	    if ((write(triggerPipe, "", 1) == -1) && (errno != EAGAIN)) { +		Tcl_Panic("Tcl_WaitForEvent: %s", +			"unable to write to triggerPipe");  	    }  	}  #else  	tsdPtr->readyMasks = tsdPtr->checkMasks; -	numFound = select(tsdPtr->numFdBits, &(tsdPtr->readyMasks.readable), -		&(tsdPtr->readyMasks.writable), -		&(tsdPtr->readyMasks.exceptional), timeoutPtr); +	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 @@ -833,9 +1035,9 @@ Tcl_WaitForEvent(  	 */  	if (numFound == -1) { -	    FD_ZERO(&(tsdPtr->readyMasks.readable)); -	    FD_ZERO(&(tsdPtr->readyMasks.writable)); -	    FD_ZERO(&(tsdPtr->readyMasks.exceptional)); +	    FD_ZERO(&tsdPtr->readyMasks.readable); +	    FD_ZERO(&tsdPtr->readyMasks.writable); +	    FD_ZERO(&tsdPtr->readyMasks.exception);  	}  #endif /* TCL_THREADS */ @@ -845,15 +1047,14 @@ Tcl_WaitForEvent(  	for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL);  		filePtr = filePtr->nextPtr) { -  	    mask = 0; -	    if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.readable))) { +	    if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.readable)) {  		mask |= TCL_READABLE;  	    } -	    if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.writable))) { +	    if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.writable)) {  		mask |= TCL_WRITABLE;  	    } -	    if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.exceptional))) { +	    if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.exception)) {  		mask |= TCL_EXCEPTION;  	    } @@ -867,8 +1068,9 @@ Tcl_WaitForEvent(  	     */  	    if (filePtr->readyMask == 0) { -		fileEvPtr = (FileHandlerEvent *) +		FileHandlerEvent *fileEvPtr =  			ckalloc(sizeof(FileHandlerEvent)); +  		fileEvPtr->header.proc = FileHandlerEventProc;  		fileEvPtr->fd = filePtr->fd;  		Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL); @@ -914,7 +1116,7 @@ NotifierThreadProc(      ThreadSpecificData *tsdPtr;      fd_set readableMask;      fd_set writableMask; -    fd_set exceptionalMask; +    fd_set exceptionMask;      int fds[2];      int i, numFdBits = 0, receivePipe;      long found; @@ -922,22 +1124,26 @@ NotifierThreadProc(      char buf[2];      if (pipe(fds) != 0) { -	Tcl_Panic("NotifierThreadProc: could not create trigger pipe"); +	Tcl_Panic("NotifierThreadProc: %s", "could not create trigger pipe");      }      receivePipe = fds[0];      if (TclUnixSetBlockingMode(receivePipe, TCL_MODE_NONBLOCKING) < 0) { -	Tcl_Panic("NotifierThreadProc: could not make receive pipe non blocking"); +	Tcl_Panic("NotifierThreadProc: %s", +		"could not make receive pipe non blocking");      }      if (TclUnixSetBlockingMode(fds[1], TCL_MODE_NONBLOCKING) < 0) { -	Tcl_Panic("NotifierThreadProc: could not make trigger pipe non blocking"); +	Tcl_Panic("NotifierThreadProc: %s", +		"could not make trigger pipe non blocking");      }      if (fcntl(receivePipe, F_SETFD, FD_CLOEXEC) < 0) { -	Tcl_Panic("NotifierThreadProc: could not make receive pipe close-on-exec"); +	Tcl_Panic("NotifierThreadProc: %s", +		"could not make receive pipe close-on-exec");      }      if (fcntl(fds[1], F_SETFD, FD_CLOEXEC) < 0) { -	Tcl_Panic("NotifierThreadProc: could not make trigger pipe close-on-exec"); +	Tcl_Panic("NotifierThreadProc: %s", +		"could not make trigger pipe close-on-exec");      }      /* @@ -961,7 +1167,7 @@ NotifierThreadProc(      while (1) {  	FD_ZERO(&readableMask);  	FD_ZERO(&writableMask); -	FD_ZERO(&exceptionalMask); +	FD_ZERO(&exceptionMask);  	/*  	 * Compute the logical OR of the select masks from all the waiting @@ -972,14 +1178,14 @@ NotifierThreadProc(  	timePtr = NULL;  	for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) {  	    for (i = tsdPtr->numFdBits-1; i >= 0; --i) { -		if (FD_ISSET(i, &(tsdPtr->checkMasks.readable))) { +		if (FD_ISSET(i, &tsdPtr->checkMasks.readable)) {  		    FD_SET(i, &readableMask);  		} -		if (FD_ISSET(i, &(tsdPtr->checkMasks.writable))) { +		if (FD_ISSET(i, &tsdPtr->checkMasks.writable)) {  		    FD_SET(i, &writableMask);  		} -		if (FD_ISSET(i, &(tsdPtr->checkMasks.exceptional))) { -		    FD_SET(i, &exceptionalMask); +		if (FD_ISSET(i, &tsdPtr->checkMasks.exception)) { +		    FD_SET(i, &exceptionMask);  		}  	    }  	    if (tsdPtr->numFdBits > numFdBits) { @@ -1006,7 +1212,7 @@ NotifierThreadProc(  	}  	FD_SET(receivePipe, &readableMask); -	if (select(numFdBits, &readableMask, &writableMask, &exceptionalMask, +	if (select(numFdBits, &readableMask, &writableMask, &exceptionMask,  		timePtr) == -1) {  	    /*  	     * Try again immediately on an error. @@ -1024,19 +1230,19 @@ NotifierThreadProc(  	    found = 0;  	    for (i = tsdPtr->numFdBits-1; i >= 0; --i) { -		if (FD_ISSET(i, &(tsdPtr->checkMasks.readable)) +		if (FD_ISSET(i, &tsdPtr->checkMasks.readable)  			&& FD_ISSET(i, &readableMask)) { -		    FD_SET(i, &(tsdPtr->readyMasks.readable)); +		    FD_SET(i, &tsdPtr->readyMasks.readable);  		    found = 1;  		} -		if (FD_ISSET(i, &(tsdPtr->checkMasks.writable)) +		if (FD_ISSET(i, &tsdPtr->checkMasks.writable)  			&& FD_ISSET(i, &writableMask)) { -		    FD_SET(i, &(tsdPtr->readyMasks.writable)); +		    FD_SET(i, &tsdPtr->readyMasks.writable);  		    found = 1;  		} -		if (FD_ISSET(i, &(tsdPtr->checkMasks.exceptional)) -			&& FD_ISSET(i, &exceptionalMask)) { -		    FD_SET(i, &(tsdPtr->readyMasks.exceptional)); +		if (FD_ISSET(i, &tsdPtr->checkMasks.exception) +			&& FD_ISSET(i, &exceptionMask)) { +		    FD_SET(i, &tsdPtr->readyMasks.exception);  		    found = 1;  		}  	    } @@ -1063,7 +1269,11 @@ NotifierThreadProc(  		    tsdPtr->onList = 0;  		    tsdPtr->pollState = 0;  		} +#ifdef __CYGWIN__ +		PostMessageW(tsdPtr->hwnd, 1024, 0, 0); +#else  		Tcl_ConditionNotify(&tsdPtr->waitCV); +#endif /* __CYGWIN__ */  	    }  	}  	Tcl_MutexUnlock(¬ifierMutex); @@ -1100,11 +1310,80 @@ NotifierThreadProc(      Tcl_ConditionNotify(¬ifierCV);      Tcl_MutexUnlock(¬ifierMutex); -    TclpThreadExit (0); +    TclpThreadExit(0); +} + +#if defined(HAVE_PTHREAD_ATFORK) && !defined(__APPLE__) && !defined(__hpux) +/* + *---------------------------------------------------------------------- + * + * AtForkPrepare -- + * + *	Lock the notifier in preparation for a fork. + * + * Results: + *	None. + * + * Side effects: + *	None. + * + *---------------------------------------------------------------------- + */ + +static void +AtForkPrepare(void) +{ +} + +/* + *---------------------------------------------------------------------- + * + * AtForkParent -- + * + *	Unlock the notifier in the parent after a fork. + * + * Results: + *	None. + * + * Side effects: + *	None. + * + *---------------------------------------------------------------------- + */ + +static void +AtForkParent(void) +{ +} + +/* + *---------------------------------------------------------------------- + * + * AtForkChild -- + * + *	Unlock and reinstall the notifier in the child after a fork. + * + * Results: + *	None. + * + * Side effects: + *	None. + * + *---------------------------------------------------------------------- + */ + +static void +AtForkChild(void) +{ +    notifierMutex = NULL; +    notifierCV = NULL; +    Tcl_InitNotifier();  } +#endif /* HAVE_PTHREAD_ATFORK */ +  #endif /* TCL_THREADS */ -#endif /* HAVE_COREFOUNDATION */ +#endif /* !HAVE_COREFOUNDATION */  /*   * Local Variables: | 
