'\" '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" '\" SCCS: @(#) Notifier.3 1.11 96/06/05 18:00:17 '\" .so man.macros .TH Tcl_CreateEventSource 3 7.5 Tcl "Tcl Library Procedures" .BS .SH NAME Tcl_CreateEventSource, Tcl_DeleteEventSource, Tcl_WatchFile, Tcl_FileReady, Tcl_SetMaxBlockTime, Tcl_QueueEvent, Tcl_WaitForEvent \- Event sources, the event notifier, and the event queue .SH SYNOPSIS .nf \fB#include \fR .sp \fBTcl_CreateEventSource(\fIsetupProc, checkProc, clientData\fB)\fR .sp \fBTcl_DeleteEventSource(\fIsetupProc, checkProc, clientData\fB)\fR .sp \fBTcl_WatchFile(\fIfile, mask\fB)\fR .sp \fBTcl_SetMaxBlockTime(\fItimePtr\fB)\fR .sp int \fBTcl_FileReady(\fIfile, mask\fB)\fR .sp \fBTcl_QueueEvent(\fIevPtr, position\fB)\fR .sp int \fBTcl_WaitForEvent(\fItimePtr\fB)\fR .SH ARGUMENTS .AS Tcl_EventSetupProc *setupProc .AP Tcl_EventSetupProc *setupProc in Procedure to invoke to prepare for event wait in \fBTcl_DoWhenIdle\fR. .AP Tcl_EventCheckProc *checkProc in Procedure for \fBTcl_DoWhenIdle\fR to invoke after waiting for events. Checks to see if any events have occurred and, if so, queues them. .AP ClientData clientData in Arbitrary one-word value to pass to \fIsetupProc\fR and \fIcheckProc\fR. .AP Tcl_File file in Generic file handle as returned by \fBTcl_GetFile\fR. .AP int mask in Indicates the events of interest on \fIfile\fR: an OR'ed combination of \fBTCL_READABLE\fR, \fBTCL_WRITABLE\fR, and \fBTCL_EXCEPTION\fR. .AP Tcl_Time *timePtr in Indicates the maximum amount of time to wait for an event. This is specified as an interval (how long to wait), not an absolute time (when to wakeup). If the pointer passed to \fBTcl_WaitForEvent\fR is NULL, it means there is no maximum wait time: wait forever if necessary. .AP Tcl_Event *evPtr in An event to add to the event queue. The storage for the event must .VS have been allocated by the caller using \fBTcl_Alloc\fR or \fBckalloc\fR. .VE .AP Tcl_QueuePosition position in Where to add the new event in the queue: \fBTCL_QUEUE_TAIL\fR, \fBTCL_QUEUE_HEAD\fR, or \fBTCL_QUEUE_MARK\fR. .AP int flags in A copy of the \fIflags\fR argument passed to \fBTcl_DoOneEvent\fR. .BE .SH INTRODUCTION .PP The procedures described here are the building blocks out of which the Tcl event notifier is constructed. The event notifier is the lowest layer in the Tcl event mechanism. It consists of three things: .IP [1] Event sources: these represent the ways in which events can be generated. For example, there is a timer event source that implements the \fBTcl_CreateTimerHandler\fR procedure and the \fBafter\fR command, and there is a file event source that implements the \fBTcl_CreateFileHandler\fR procedure. An event source must work with the notifier to detect events at the right times, record them on the event queue, and eventually notify higher-level software that they have occurred. .IP [2] The event queue: there is a single queue for the whole application, containing events that have been detected but not yet serviced. The event queue guarantees a fair discipline of event handling, so that no event source can starve the others. It also allows events to be saved for servicing at a future time. .IP [3] The procedure \fBTcl_DoOneEvent\fR: this is procedure that is invoked by the application to service events. It works with the event sources and the event queue to detect and handle events, and calls \fBTcl_WaitForEvent\fR to actually wait for an event to occur. .PP The easiest way to understand how the notifier works is to consider what happens when \fBTcl_DoOneEvent\fR is called. \fBTcl_DoOneEvent\fR is passed a \fIflags\fR argument that indicates what sort of events it is OK to process and also whether or not to block if no events are ready. \fBTcl_DoOneEvent\fR does the following things: .IP [1] Check the event queue to see if it contains any events that can be serviced. If so, service the first possible event, remove it from the queue, and return. .IP [2] Prepare to block for an event. To do this, \fBTcl_DoOneEvent\fR invokes a \fIsetup procedure\fR in each event source. The event source will call procedures like \fBTcl_WatchFile\fR and \fBTcl_SetMaxBlockTime\fR to indicate what low-level events to look for in \fBTcl_WaitForEvent\fR. .IP [3] Call \fBTcl_WaitForEvent\fR. This procedure is implemented differently on different platforms; it waits for an event to occur, based on the information provided by the event sources. It may cause the application to block if \fItimePtr\fR specifies an interval other than 0. \fBTcl_WaitForEvent\fR returns when something has happened, such as a file becoming readable or the interval given by \fItimePtr\fR expiring. If there are no events for \fBTcl_WaitForEvent\fR to wait for, so that it would block forever, then it returns immediately and \fBTcl_DoOneEvent\fR returns 0. .IP [4] Call a \fIcheck procedure\fR in each event source. The check procedure determines whether any events of interest to this source occurred (e.g. by calling \fBTcl_FileReady\fR). If so, the events are added to the event queue. .IP [5] Check the event queue to see if it contains any events that can be serviced. If so, service the first possible event, remove it from the queue, and return. .IP [6] See if there are idle callbacks pending. If so, invoke all of them and return. .IP [7] Either return 0 to indicate that no events were ready, or go back to step [2] if blocking was requested by the caller. .PP The procedures in this file allow you to do two things. First, they allow you to create new event sources, such as one for UNIX signals or one to notify when subprocesses have exited. Second, the procedures can be used to build a new version of \fBTcl_DoOneEvent\fR. This might be necessary to support a new operating system with different low-level event reporting mechanisms, or it might be necessary to merge Tcl's event loop with that of some other toolkit like Xt. .SH "CREATING A NEW EVENT SOURCE" .PP An event source consists of three procedures invoked by the notifier, plus additional C procedures that are invoked by higher-level code to arrange for event-driven callbacks. The three procedures called by the notifier consist of the setup and check procedures described above, plus an additional procedure that is invoked when an event is removed from the event queue for servicing. .PP The procedure \fBTcl_CreateEventSource\fR creates a new event source. Its arguments specify the setup procedure and check procedure for the event source. \fISetupProc\fR should match the following prototype: .CS typedef void Tcl_EventSetupProc( ClientData \fIclientData\fR, int \fIflags\fR); .CE The \fIclientData\fR argument will be the same as the \fIclientData\fR argument to \fBTcl_CreateEventSource\fR; it is typically used to point to private information managed by the event source. The \fIflags\fR argument will be the same as the \fIflags\fR argument passed to \fBTcl_DoOneEvent\fR except that it will never by 0 (\fBTcl_DoOneEvent\fR replaces 0 with \fBTCL_ALL_EVENTS\fR). \fIFlags\fR indicates what kinds of events should be considered; if the bit corresponding to this event source isn't set, the event source should return immediately without doing anything. For example, the file event source checks for the \fBTCL_FILE_EVENTS\fR bit. .PP \fISetupProc\fR's job is to provide information to \fBTcl_WaitForEvent\fR about how to wait for events. It usually does this by calling \fBTcl_WatchFile\fR or \fBTcl_SetMaxBlockTime\fR. For example, \fIsetupProc\fR can call \fBTcl_WatchFile\fR to indicate that \fBTcl_WaitForEvent\fR should return when the conditions given by the \fImask\fR argument become true for the file given by \fIfile\fR. The UNIX version of \fBTcl_WaitForEvent\fR uses the information passed to \fBTcl_WatchFile\fR to set the file masks for \fBselect\fR, which it uses to wait for events. If \fBTcl_WatchFile\fR isn't called by any event sources then \fBTcl_WaitForEvent\fR will ignore files while waiting. .PP \fISetupProc\fR can also invoke \fBTcl_SetMaxBlockTime\fR to set an upper bound on how long \fBTcl_WaitForEvent\fR will block. If no event source calls \fBTcl_SetMaxBlockTime\fR then \fBTcl_WaitForEvent\fR will wait as long as necessary for an event to occur; otherwise, it will only wait as long as the shortest interval passed to \fBTcl_SetMaxBlockTime\fR by one of the event sources. For example, the timer event source uses this procedure to limit the wait time to the interval before the next timer event is ready. If an event source knows that it already has events ready to report, it can request a zero maximum block time. The \fItimePtr\fR argument to \fBTcl_WaitForEvent\fR points to a structure that describes a time interval in seconds and microseconds: .CS typedef struct Tcl_Time { long \fIsec\fR; long \fIusec\fR; } Tcl_Time; .CE The \fIusec\fR field should be less than 1000000. .PP Information provided to \fBTcl_WatchFile\fR and \fBTcl_SetMaxBlockTime\fR is only used for the next call to \fBTcl_WaitForEvent\fR; it is discarded after \fBTcl_WaitForEvent\fR returns. The next time an event wait is done each of the event sources' setup procedures will be called again, and they can specify new information for that event wait. .PP In addition to the generic procedures \fBTcl_WatchFile\fR and \fBTcl_SetMaxBlockTime\fR, other platform-specific procedures may also be available for \fIsetupProc\fR, if there is additional information needed by \fBTcl_WaitForEvent\fR on that platform. .PP The second procedure provided by each event source is its check procedure, indicated by the \fIcheckProc\fR argument to \fBTcl_CreateEventSource\fR. \fICheckProc\fR must match the following prototype: .CS typedef void Tcl_EventCheckProc( ClientData \fIclientData\fR, int \fIflags\fR); .CE The arguments to this procedure are the same as those for \fIsetupProc\fR. \fBCheckProc\fR is invoked by \fBTcl_DoOneEvent\fR after it has waited for events. Presumably at least one event source is now prepared to queue an event. \fBTcl_DoOneEvent\fR calls each of the event sources in turn, so they all have a chance to queue any events that are ready. The check procedure does two things. First, it must see if any events have triggered. Different event sources do this in different ways, but the procedure \fBTcl_FileReady\fR may be useful for some event sources. It takes as arguments a file identifier \fIfile\fR and a mask of interesting conditions; it returns another mask indicating which of those conditions were found to be present on the file during the most recent call to \fBTcl_WaitForEvent\fR. \fBTcl_WaitForEvent\fR only checks a file if \fBTcl_WatchFile\fR was called by at least one event source, so it is possible for \fBTcl_FileReady\fR to return 0 even if the file is ready. .PP If an event source's check procedure detects that an interesting event has occurred, then it must add the event to Tcl's event queue. To do this, the event source calls \fBTcl_QueueEvent\fR. The \fIevPtr\fR argument is a pointer to a dynamically allocated structure containing the event (see below for more information on memory management issues). Each event source can define its own event structure with whatever information is relevant to that event source. However, the first element of the structure must be a structure of type \fBTcl_Event\fR, and the address of this structure is used when communicating between the event source and the rest of the notifier. A \fBTcl_Event\fR has the following definition: .CS typedef struct Tcl_Event { Tcl_EventProc *\fIproc\fR; struct Tcl_Event *\fInextPtr\fR; }; .CE The event source must fill in the \fIproc\fR field of the event before calling \fBTcl_QueueEvent\fR. The \fInextPtr\fR is used to link together the events in the queue and should not be modified by the event source. .PP An event may be added to the queue at any of three positions, depending on the \fIposition\fR argument to \fBTcl_QueueEvent\fR: .IP \fBTCL_QUEUE_TAIL\fR 24 Add the event at the back of the queue, so that all other pending events will be serviced first. This is almost always the right place for new events. .IP \fBTCL_QUEUE_HEAD\fR 24 Add the event at the front of the queue, so that it will be serviced before all other queued events. .IP \fBTCL_QUEUE_MARK\fR 24 Add the event at the front of the queue, unless there are other events at the front whose position is \fBTCL_QUEUE_MARK\fR; if so, add the new event just after all other \fBTCL_QUEUE_MARK\fR events. This value of \fIposition\fR is used to insert an ordered sequence of events at the front of the queue, such as a series of Enter and Leave events synthesized during a grab or ungrab operation in Tk. .PP When it is time to handle an event from the queue (steps 1 and 5 above) \fBTcl_DoOneEvent\fR will invoke the \fIproc\fR specified in the first queued \fBTcl_Event\fR structure. \fIProc\fR must match the following prototype: .CS typedef int Tcl_EventProc( Tcl_Event *\fIevPtr\fR, int \fIflags\fR); .CE The first argument to \fIproc\fR is a pointer to the event, which will be the same as the first argument to the \fBTcl_QueueEvent\fR call that added the event to the queue. The second argument to \fIproc\fR is the \fIflags\fR argument for the current call to \fBTcl_DoOneEvent\fR; this is used by the event source to return immediately if its events are not relevant. .PP It is up to \fIproc\fR to handle the event, typically by invoking one or more Tcl commands or C-level callbacks. Once the event source has finished handling the event it returns 1 to indicate that the event can be removed from the queue. If for some reason the event source decides that the event cannot be handled at this time, it may return 0 to indicate that the event should be deferred for processing later; in this case \fBTcl_DoOneEvent\fR will go on to the next event in the queue and attempt to service it. There are several reasons why an event source might defer an event. One possibility is that events of this type are excluded by the \fIflags\fR argument. For example, the file event source will always return 0 if the \fBTCL_FILE_EVENTS\fR bit isn't set in \fIflags\fR. Another example of deferring events happens in Tk if \fBTk_RestrictEvents\fR has been invoked to defer certain kinds of window events. .PP When \fIproc\fR returns 1, \fBTcl_DoOneEvent\fR will remove the event from the event queue and free its storage. Note that the storage for an event must be allocated by .VS the event source (using \fBTcl_Alloc\fR or the Tcl macro \fBckalloc\fR) .VE before calling \fBTcl_QueueEvent\fR, but it will be freed by \fBTcl_DoOneEvent\fR, not by the event source. .SH "CREATING A NEW NOTIFIER" .PP The notifier consists of all the procedures described in this manual entry, plus \fBTcl_DoOneEvent\fR and \fBTcl_Sleep\fR. Most of these procedures are generic, in that they are the same for all platforms. However, four of the procedures are platform-dependent: \fBTcl_WatchFile\fR, \fBTcl_FileReady\fR, \fBTcl_WaitForEvent\fR, and \fBTcl_Sleep\fR. To support a new platform, you must write new versions of these procedures. \fBTcl_WatchFile\fR and \fBTcl_FileReady\fR have already been described previously in this document, and \fBTcl_Sleep\fR is described in its own manual entry. .PP \fBTcl_WaitForEvent\fR is the lowest-level procedure in the notifier; it is responsible for waiting for an ``interesting'' event to occur or for a given time to elapse. Before \fBTcl_WaitForEvent\fR is invoked, each of the event sources' setup procedure will have been invoked; the setup procedures will have provided information about what to wait for by invoking procedures like \fBTcl_WatchFile\fR. The \fItimePtr\fR argument to \fBTcl_WaitForEvent\fR gives the maximum time to block for an event, based on calls to \fBTcl_SetMaxBlockTime\fR made by setup procedures and on other information (such as the \fBTCL_DONT_WAIT\fR bit in \fIflags\fR). \fBTcl_WaitForEvent\fR uses information saved by \fBTcl_WatchFile\fR, plus the \fItimePtr\fR argument to decide what to wait for and how long to block. It returns TCL_OK as soon as one of the specified events has occurred or the given amount of time has elapsed. However, if there are no event handlers (neither \fBTcl_WatchFile\fR nor \fBTcl_SetMaxBlockTime\fR has been called since the last call to \fBTcl_WaitForEvent\fR), so that the procedure would block forever, then it returns immediately with a result of TCL_ERROR. .PP The easiest way to create a new notifier is to look at the code for an existing notifier, such as the files \fBgeneric/tclNotify.c\fR and \fBunix/tclUnixNotfy.c\fR. .SH KEYWORDS block time, event notifier, event queue, event sources, file events