⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tclunixnotfy.c

📁 tcl是工具命令语言
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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.11 2002/08/31 06:09:46 das Exp $ */#include "tclInt.h"#include "tclPort.h"#include <signal.h> extern TclStubs tclStubs;/* * This structure is used to keep track of the notifier info for a  * a registered file. */typedef struct FileHandler {    int fd;    int mask;			/* Mask of desired events: TCL_READABLE,				 * etc. */    int readyMask;		/* Mask of events that have been seen since the				 * last time file handlers were invoked for				 * this file. */    Tcl_FileProc *proc;		/* Procedure to call, in the style of				 * Tcl_CreateFileHandler. */    ClientData clientData;	/* Argument to pass to proc. */    struct FileHandler *nextPtr;/* Next in list of all files we care about. */} FileHandler;/* * The following structure is what is added to the Tcl event queue when * file handlers are ready to fire. */typedef struct FileHandlerEvent {    Tcl_Event header;		/* Information that is standard for				 * all events. */    int fd;			/* File descriptor that is ready.  Used				 * to find the FileHandler structure for				 * the file (can't point directly to the				 * FileHandler structure because it could				 * go away while the event is queued). */} FileHandlerEvent;/* * The following static structure contains the state information for the * select based implementation of the Tcl notifier.  One of these structures * is created for each thread that is using the notifier.   */typedef struct ThreadSpecificData {    FileHandler *firstFileHandlerPtr;				/* Pointer to head of file handler list. */    fd_mask checkMasks[3*MASK_SIZE];				/* This array is used to build up the masks				 * to be used in the next call to select.				 * Bits are set in response to calls to				 * Tcl_CreateFileHandler. */    fd_mask readyMasks[3*MASK_SIZE];				/* This array reflects the readable/writable				 * conditions that were found to exist by the				 * last call to select. */    int numFdBits;		/* Number of valid bits in checkMasks				 * (one more than highest fd for which				 * Tcl_WatchFile has been called). */#ifdef TCL_THREADS    int onList;			/* True if it is in this list */    unsigned int pollState;	/* pollState is used to implement a polling 				 * handshake between each thread and the				 * notifier thread. Bits defined below. */    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/* * The following static indicates the number of threads that have * initialized notifiers. * * You must hold the notifierMutex lock before accessing this variable. */static int notifierCount = 0;/* * The following variable points to the head of a doubly-linked list of  * of ThreadSpecificData structures for all threads that are currently * waiting on an event. * * You must hold the notifierMutex lock before accessing this list. */static ThreadSpecificData *waitingListPtr = NULL;/* * The notifier thread spends all its time in select() waiting for a * file descriptor associated with one of the threads on the waitingListPtr * list to do something interesting.  But if the contents of the * waitingListPtr list ever changes, we need to wake up and restart * the select() system call.  You can wake up the notifier thread by * writing a single byte to the file descriptor defined below.  This * file descriptor is the input-end of a pipe and the notifier thread is * listening for data on the output-end of the same pipe.  Hence writing * to this file descriptor will cause the select() system call to return * and wake up the notifier thread. * * You must hold the notifierMutex lock before accessing this list. */static int triggerPipe = -1;/* * The notifierMutex locks access to all of the global notifier state.  */TCL_DECLARE_MUTEX(notifierMutex)/* * The notifier thread signals the notifierCV when it has finished * initializing the triggerPipe and right before the notifier * thread terminates. */static Tcl_Condition notifierCV;/* * The pollState bits *	POLL_WANT is set by each thread before it waits on its condition *		variable.  It is checked by the notifier before it does *		select. *	POLL_DONE is set by the notifier if it goes into select after *		seeing POLL_WANT.  The idea is to ensure it tries a select *		with the same bits the initial thread had set. */#define POLL_WANT	0x1#define POLL_DONE	0x2/* * This is the thread ID of the notifier thread that does select. */static Tcl_ThreadId notifierThread;#endif/* * Static routines defined in this file. */#ifdef TCL_THREADSstatic void	NotifierThreadProc _ANSI_ARGS_((ClientData clientData));#endifstatic int	FileHandlerEventProc _ANSI_ARGS_((Tcl_Event *evPtr,		    int flags));/* *---------------------------------------------------------------------- * * Tcl_InitNotifier -- * *	Initializes the platform specific notifier state. * * Results: *	Returns a handle to the notifier state for this thread.. * * Side effects: *	None. * *---------------------------------------------------------------------- */ClientDataTcl_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 (Tcl_CreateThread(&notifierThread, NotifierThreadProc, NULL,		     TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS) != TCL_OK) {	    panic("Tcl_InitNotifier: unable to start notifier thread");	}    }    notifierCount++;    /*     * Wait for the notifier pipe to be created.     */    while (triggerPipe < 0) {	Tcl_ConditionWait(&notifierCV, &notifierMutex, NULL);    }    Tcl_MutexUnlock(&notifierMutex);#endif    return (ClientData) tsdPtr;}/* *---------------------------------------------------------------------- * * Tcl_FinalizeNotifier -- * *	This function is called to cleanup the notifier state before *	a thread is terminated. * * Results: *	None. * * Side effects: *	May terminate the background notifier thread if this is the *	last notifier instance. * *---------------------------------------------------------------------- */voidTcl_FinalizeNotifier(clientData)    ClientData clientData;		/* Not used. */{#ifdef TCL_THREADS    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);    Tcl_MutexLock(&notifierMutex);    notifierCount--;    /*     * 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) {	if (triggerPipe < 0) {	    panic("Tcl_FinalizeNotifier: notifier pipe not initialized");	}        /*	 * Send "q" message to the notifier thread so that it will	 * terminate.  The notifier will return from its call to select()	 * and notice that a "q" message has arrived, it will then close	 * its side of the pipe and terminate its thread.  Note the we can	 * not just close the pipe and check for EOF in the notifier	 * thread because if a background child process was created with	 * exec, select() would not register the EOF on the pipe until the	 * child processes had terminated. [Bug: 4139]	 */	write(triggerPipe, "q", 1);	close(triggerPipe);	Tcl_ConditionWait(&notifierCV, &notifierMutex, NULL);    }    /*     * Clean up any synchronization objects in the thread local storage.     */    Tcl_ConditionFinalize(&(tsdPtr->waitCV));    Tcl_MutexUnlock(&notifierMutex);#endif}/* *---------------------------------------------------------------------- * * Tcl_AlertNotifier -- * *	Wake up the specified notifier from any thread. This routine *	is called by the platform independent notifier code whenever *	the Tcl_ThreadAlert routine is called.  This routine is *	guaranteed not to be called on a given notifier after *	Tcl_FinalizeNotifier is called for that notifier. * * Results: *	None. * * Side effects: *	Signals the notifier condition variable for the specified *	notifier. * *---------------------------------------------------------------------- */voidTcl_AlertNotifier(clientData)    ClientData clientData;{#ifdef TCL_THREADS    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;    Tcl_MutexLock(&notifierMutex);    tsdPtr->eventReady = 1;    Tcl_ConditionNotify(&tsdPtr->waitCV);    Tcl_MutexUnlock(&notifierMutex);#endif}/* *---------------------------------------------------------------------- * * Tcl_SetTimer -- * *	This procedure sets the current notifier timer value.  This *	interface is not implemented in this notifier because we are *	always running inside of Tcl_DoOneEvent. * * Results: *	None. * * Side effects: *	None. * *---------------------------------------------------------------------- */voidTcl_SetTimer(timePtr)    Tcl_Time *timePtr;		/* Timeout value, may be NULL. */{    /*     * The interval timer doesn't do anything in this implementation,     * because the only event loop is via Tcl_DoOneEvent, which passes     * timeout values to Tcl_WaitForEvent.     */    if (tclStubs.tcl_SetTimer != Tcl_SetTimer) {	tclStubs.tcl_SetTimer(timePtr);    }}/* *---------------------------------------------------------------------- * * Tcl_ServiceModeHook -- * *	This function is invoked whenever the service mode changes. * * Results: *	None. * * Side effects: *	None. * *---------------------------------------------------------------------- */voidTcl_ServiceModeHook(mode)    int mode;			/* Either TCL_SERVICE_ALL, or				 * TCL_SERVICE_NONE. */{}/* *---------------------------------------------------------------------- * * Tcl_CreateFileHandler -- * *	This procedure registers a file handler with the select notifier. * * Results: *	None. * * Side effects: *	Creates a new file handler structure. * *---------------------------------------------------------------------- */voidTcl_CreateFileHandler(fd, mask, proc, clientData)    int fd;			/* Handle of stream to watch. */    int mask;			/* OR'ed combination of TCL_READABLE,				 * TCL_WRITABLE, and TCL_EXCEPTION:				 * indicates conditions under which				 * proc should be called. */    Tcl_FileProc *proc;		/* Procedure to call for each				 * selected event. */    ClientData clientData;	/* Arbitrary data to pass to proc. */{    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);    FileHandler *filePtr;    int index, bit;    if (tclStubs.tcl_CreateFileHandler != Tcl_CreateFileHandler) {	tclStubs.tcl_CreateFileHandler(fd, mask, proc, clientData);	return;    }    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;	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.     */    index = fd/(NBBY*sizeof(fd_mask));    bit = 1 << (fd%(NBBY*sizeof(fd_mask)));    if (mask & TCL_READABLE) {	tsdPtr->checkMasks[index] |= bit;    } else {	tsdPtr->checkMasks[index] &= ~bit;    }     if (mask & TCL_WRITABLE) {	(tsdPtr->checkMasks+MASK_SIZE)[index] |= bit;    } else {	(tsdPtr->checkMasks+MASK_SIZE)[index] &= ~bit;    }    if (mask & TCL_EXCEPTION) {	(tsdPtr->checkMasks+2*(MASK_SIZE))[index] |= bit;    } else {	(tsdPtr->checkMasks+2*(MASK_SIZE))[index] &= ~bit;    }    if (tsdPtr->numFdBits <= fd) {	tsdPtr->numFdBits = fd+1;    }}/* *---------------------------------------------------------------------- * * Tcl_DeleteFileHandler -- * *	Cancel a previously-arranged callback arrangement for *	a file. * * Results: *	None. * * Side effects: *	If a callback was previously registered on file, remove it. * *---------------------------------------------------------------------- */voidTcl_DeleteFileHandler(fd)    int fd;		/* Stream id for which to remove callback procedure. */{    FileHandler *filePtr, *prevPtr;    int index, bit, i;    unsigned long flags;    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);    if (tclStubs.tcl_DeleteFileHandler != Tcl_DeleteFileHandler) {	tclStubs.tcl_DeleteFileHandler(fd);	return;    }    /*     * 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;	}    }    /*     * Update the check masks for this file.     */    index = fd/(NBBY*sizeof(fd_mask));    bit = 1 << (fd%(NBBY*sizeof(fd_mask)));    if (filePtr->mask & TCL_READABLE) {	tsdPtr->checkMasks[index] &= ~bit;    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -