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

📄 tclnotify.c

📁 tcl是工具命令语言
💻 C
📖 第 1 页 / 共 3 页
字号:
/*  * tclNotify.c -- * *	This file implements the generic portion of the Tcl notifier. *	The notifier is lowest-level part of the event system.  It *	manages an event queue that holds Tcl_Event structures.  The *	platform specific portion of the notifier is defined in the *	tcl*Notify.c files in each platform directory. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * Copyright (c) 1998 by Scriptics Corporation. * Copyright (c) 2003 by Kevin B. Kenny.  All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: tclNotify.c,v 1.11 2003/02/15 20:24:10 kennykb Exp $ */#include "tclInt.h"#include "tclPort.h"extern TclStubs tclStubs;/* * For each event source (created with Tcl_CreateEventSource) there * is a structure of the following type: */typedef struct EventSource {    Tcl_EventSetupProc *setupProc;    Tcl_EventCheckProc *checkProc;    ClientData clientData;    struct EventSource *nextPtr;} EventSource;/* * The following structure keeps track of the state of the notifier on a * per-thread basis. The first three elements keep track of the event queue. * In addition to the first (next to be serviced) and last events in the queue, * we keep track of a "marker" event.  This provides a simple priority * mechanism whereby events can be inserted at the front of the queue but * behind all other high-priority events already in the queue (this is used for * things like a sequence of Enter and Leave events generated during a grab in * Tk).  These elements are protected by the queueMutex so that any thread * can queue an event on any notifier.  Note that all of the values in this * structure will be initialized to 0. */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. */    ClientData 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;/* * Global list of notifiers.  Access to this list is controlled by the * listLock mutex.  If this becomes a performance bottleneck, this could * be replaced with a hashtable. */static ThreadSpecificData *firstNotifierPtr;TCL_DECLARE_MUTEX(listLock)/* * Declarations for routines used only in this file. */static void		QueueEvent _ANSI_ARGS_((ThreadSpecificData *tsdPtr,			    Tcl_Event* evPtr, Tcl_QueuePosition position));/* *---------------------------------------------------------------------- * * TclInitNotifier -- * *	Initialize the thread local data structures for the notifier *	subsystem. * * Results: *	None. * * Side effects: *	Adds the current thread to the global list of notifiers. * *---------------------------------------------------------------------- */voidTclInitNotifier(){    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);    Tcl_MutexLock(&listLock);    tsdPtr->threadId = Tcl_GetCurrentThread();    tsdPtr->clientData = tclStubs.tcl_InitNotifier();    tsdPtr->nextPtr = firstNotifierPtr;    firstNotifierPtr = tsdPtr;    Tcl_MutexUnlock(&listLock);}/* *---------------------------------------------------------------------- * * TclFinalizeNotifier -- * *	Finalize the thread local data structures for the notifier *	subsystem. * * Results: *	None.	 * * Side effects: *	Removes the notifier associated with the current thread from *	the global notifier list. * *---------------------------------------------------------------------- */voidTclFinalizeNotifier(){    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);    ThreadSpecificData **prevPtrPtr;    Tcl_Event *evPtr, *hold;    Tcl_MutexLock(&(tsdPtr->queueMutex));    for (evPtr = tsdPtr->firstEventPtr; evPtr != (Tcl_Event *) NULL; ) {	hold = evPtr;	evPtr = evPtr->nextPtr;	ckfree((char *) hold);    }    tsdPtr->firstEventPtr = NULL;    tsdPtr->lastEventPtr = NULL;    Tcl_MutexUnlock(&(tsdPtr->queueMutex));    Tcl_MutexLock(&listLock);    if (tclStubs.tcl_FinalizeNotifier) {	tclStubs.tcl_FinalizeNotifier(tsdPtr->clientData);    }    Tcl_MutexFinalize(&(tsdPtr->queueMutex));    for (prevPtrPtr = &firstNotifierPtr; *prevPtrPtr != NULL;	 prevPtrPtr = &((*prevPtrPtr)->nextPtr)) {	if (*prevPtrPtr == tsdPtr) {	    *prevPtrPtr = tsdPtr->nextPtr;	    break;	}    }    Tcl_MutexUnlock(&listLock);}/* *---------------------------------------------------------------------- * * Tcl_SetNotifier -- * *	Install a set of alternate functions for use with the notifier. #	In particular, this can be used to install the Xt-based *	notifier for use with the Browser plugin. * * Results: *	None. * * Side effects: *	Overstomps part of the stub vector.  This relies on hooks *	added to the default procedures in case those are called *	directly (i.e., not through the stub table.) * *---------------------------------------------------------------------- */voidTcl_SetNotifier(notifierProcPtr)    Tcl_NotifierProcs *notifierProcPtr;{#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */    tclStubs.tcl_CreateFileHandler = notifierProcPtr->createFileHandlerProc;    tclStubs.tcl_DeleteFileHandler = notifierProcPtr->deleteFileHandlerProc;#endif    tclStubs.tcl_SetTimer = notifierProcPtr->setTimerProc;    tclStubs.tcl_WaitForEvent = notifierProcPtr->waitForEventProc;    tclStubs.tcl_InitNotifier = notifierProcPtr->initNotifierProc;    tclStubs.tcl_FinalizeNotifier = notifierProcPtr->finalizeNotifierProc;    tclStubs.tcl_AlertNotifier = notifierProcPtr->alertNotifierProc;    tclStubs.tcl_ServiceModeHook = notifierProcPtr->serviceModeHookProc;}/* *---------------------------------------------------------------------- * * Tcl_CreateEventSource -- * *	This procedure is invoked to create a new source of events. *	The source is identified by a procedure that gets invoked *	during Tcl_DoOneEvent to check for events on that source *	and queue them. * * * Results: *	None. * * Side effects: *	SetupProc and checkProc will be invoked each time that Tcl_DoOneEvent *	runs out of things to do.  SetupProc will be invoked before *	Tcl_DoOneEvent calls select or whatever else it uses to wait *	for events.  SetupProc typically calls functions like *	Tcl_SetMaxBlockTime to indicate what to wait for. * *	CheckProc is called after select or whatever operation was actually *	used to wait.  It figures out whether anything interesting actually *	happened (e.g. by calling Tcl_AsyncReady), and then calls *	Tcl_QueueEvent to queue any events that are ready. * *	Each of these procedures is passed two arguments, e.g. *		(*checkProc)(ClientData clientData, int flags)); *	ClientData is the same as the clientData argument here, and flags *	is a combination of things like TCL_FILE_EVENTS that indicates *	what events are of interest:  setupProc and checkProc use flags *	to figure out whether their events are relevant or not. * *---------------------------------------------------------------------- */voidTcl_CreateEventSource(setupProc, checkProc, clientData)    Tcl_EventSetupProc *setupProc;	/* Procedure to invoke to figure out					 * what to wait for. */    Tcl_EventCheckProc *checkProc;	/* Procedure to call after waiting					 * to see what happened. */    ClientData clientData;		/* One-word argument to pass to					 * setupProc and checkProc. */{    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);    EventSource *sourcePtr = (EventSource *) ckalloc(sizeof(EventSource));    sourcePtr->setupProc = setupProc;    sourcePtr->checkProc = checkProc;    sourcePtr->clientData = clientData;    sourcePtr->nextPtr = tsdPtr->firstEventSourcePtr;    tsdPtr->firstEventSourcePtr = sourcePtr;}/* *---------------------------------------------------------------------- * * Tcl_DeleteEventSource -- * *	This procedure is invoked to delete the source of events *	given by proc and clientData. * * Results: *	None. * * Side effects: *	The given event source is cancelled, so its procedure will *	never again be called.  If no such source exists, nothing *	happens. * *---------------------------------------------------------------------- */voidTcl_DeleteEventSource(setupProc, checkProc, clientData)    Tcl_EventSetupProc *setupProc;	/* Procedure to invoke to figure out					 * what to wait for. */    Tcl_EventCheckProc *checkProc;	/* Procedure to call after waiting					 * to see what happened. */    ClientData clientData;		/* One-word argument to pass to					 * setupProc and checkProc. */{    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);    EventSource *sourcePtr, *prevPtr;    for (sourcePtr = tsdPtr->firstEventSourcePtr, prevPtr = NULL;	    sourcePtr != NULL;	    prevPtr = sourcePtr, sourcePtr = sourcePtr->nextPtr) {	if ((sourcePtr->setupProc != setupProc)		|| (sourcePtr->checkProc != checkProc)		|| (sourcePtr->clientData != clientData)) {	    continue;	}	if (prevPtr == NULL) {	    tsdPtr->firstEventSourcePtr = sourcePtr->nextPtr;	} else {	    prevPtr->nextPtr = sourcePtr->nextPtr;	}	ckfree((char *) sourcePtr);	return;    }}/* *---------------------------------------------------------------------- * * Tcl_QueueEvent -- * *	Queue an event on the event queue associated with the *	current thread. * * Results: *	None. * * Side effects: *	None. * *---------------------------------------------------------------------- */voidTcl_QueueEvent(evPtr, position)    Tcl_Event* evPtr;		/* Event to add to queue.  The storage				 * space must have been allocated the caller				 * with malloc (ckalloc), and it becomes				 * the property of the event queue.  It				 * will be freed after the event has been				 * handled. */    Tcl_QueuePosition position;	/* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD,				 * TCL_QUEUE_MARK. */{    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);    QueueEvent(tsdPtr, evPtr, position);}/* *---------------------------------------------------------------------- * * Tcl_ThreadQueueEvent -- * *	Queue an event on the specified thread's event queue. * * Results: *	None. * * Side effects: *	None. * *---------------------------------------------------------------------- */voidTcl_ThreadQueueEvent(threadId, evPtr, position)

⌨️ 快捷键说明

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