tcl7.6 C API - Notifier
NAME
Tcl_CreateEventSource, Tcl_DeleteEventSource, Tcl_WatchFile,
Tcl_FileReady, Tcl_SetMaxBlockTime, Tcl_QueueEvent,
Tcl_WaitForEvent - Event sources, the event notifier, and
the event queue
SYNOPSIS
#include <tcl.h>
Tcl_CreateEventSource(setupProc, checkProc, clientData)
Tcl_DeleteEventSource(setupProc, checkProc, clientData)
Tcl_WatchFile(file, mask)
Tcl_SetMaxBlockTime(timePtr)
int
Tcl_FileReady(file, mask)
Tcl_QueueEvent(evPtr, position)
int
Tcl_WaitForEvent(timePtr)
ARGUMENTS
Tcl_EventSetupProc *setupProc (in) Procedure to
invoke to
prepare for
event wait in
Tcl_DoWhenIdle.
Tcl_EventCheckProc *checkProc (in) Procedure for
Tcl_DoWhenIdle
to invoke after
waiting for
events. Checks
to see if any
events have
occurred and, if
so, queues them.
ClientData clientData (in) Arbitrary one-
word value to
pass to
setupProc and
checkProc.
Tcl_File file (in) Generic file
handle as
returned by
Tcl_GetFile.
int mask (in) Indicates the
events of
interest on
file: an OR'ed
combination of
TCL_READABLE,
TCL_WRITABLE,
and
TCL_EXCEPTION.
Tcl_Time *timePtr (in) Indicates the
maximum amount
of time to wait
for an event.
This is speci-
fied as an
interval (how
long to wait),
not an absolute
time (when to
wakeup). If the
pointer passed
to
Tcl_WaitForEvent
is NULL, it
means there is
no maximum wait
time: wait for-
ever if neces-
sary.
Tcl_Event *evPtr (in) An event to add
to the event
queue. The
storage for the
event must have |
been allocated |
by the caller |
using Tcl_Alloc |
or ckalloc.
Tcl_QueuePosition position (in) Where to add the
new event in the
queue:
TCL_QUEUE_TAIL,
TCL_QUEUE_HEAD,
or
TCL_QUEUE_MARK.
int flags (in) A copy of the
flags argument
passed to
Tcl_DoOneEvent.
INTRODUCTION
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:
[1] Event sources: these represent the ways in which
events can be generated. For example, there is a timer
event source that implements the Tcl_CreateTimerHandler
procedure and the after command, and there is a file
event source that implements the Tcl_CreateFileHandler
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.
[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.
[3] The procedure Tcl_DoOneEvent: 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 Tcl_WaitForEvent to
actually wait for an event to occur.
The easiest way to understand how the notifier works is to
consider what happens when Tcl_DoOneEvent is called.
Tcl_DoOneEvent is passed a flags argument that indicates
what sort of events it is OK to process and also whether or
not to block if no events are ready. Tcl_DoOneEvent does
the following things:
[1] Check the event queue to see if it contains any events
that can be serviced. If so, service the first possi-
ble event, remove it from the queue, and return.
[2] Prepare to block for an event. To do this,
Tcl_DoOneEvent invokes a setup procedure in each event
source. The event source will call procedures like
Tcl_WatchFile and Tcl_SetMaxBlockTime to indicate what
low-level events to look for in Tcl_WaitForEvent.
[3] Call Tcl_WaitForEvent. 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 timePtr specifies an interval other than 0.
Tcl_WaitForEvent returns when something has happened,
such as a file becoming readable or the interval given
by timePtr expiring. If there are no events for
Tcl_WaitForEvent to wait for, so that it would block
forever, then it returns immediately and Tcl_DoOneEvent
returns 0.
[4] Call a check procedure in each event source. The check
procedure determines whether any events of interest to
this source occurred (e.g. by calling Tcl_FileReady).
If so, the events are added to the event queue.
[5] Check the event queue to see if it contains any events
that can be serviced. If so, service the first possi-
ble event, remove it from the queue, and return.
[6] See if there are idle callbacks pending. If so, invoke
all of them and return.
[7] Either return 0 to indicate that no events were ready,
or go back to step [2] if blocking was requested by the
caller.
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 Tcl_DoOneEvent. This might be necessary to sup-
port 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.
CREATING A NEW EVENT SOURCE
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 addi-
tional procedure that is invoked when an event is removed
from the event queue for servicing.
The procedure Tcl_CreateEventSource creates a new event
source. Its arguments specify the setup procedure and check
procedure for the event source. SetupProc should match the
following prototype:
typedef void Tcl_EventSetupProc(
ClientData clientData,
int flags);
The clientData argument will be the same as the clientData
argument to Tcl_CreateEventSource; it is typically used to
point to private information managed by the event source.
The flags argument will be the same as the flags argument
passed to Tcl_DoOneEvent except that it will never by 0
(Tcl_DoOneEvent replaces 0 with TCL_ALL_EVENTS). Flags
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
TCL_FILE_EVENTS bit.
SetupProc's job is to provide information to
Tcl_WaitForEvent about how to wait for events. It usually
does this by calling Tcl_WatchFile or Tcl_SetMaxBlockTime.
For example, setupProc can call Tcl_WatchFile to indicate
that Tcl_WaitForEvent should return when the conditions
given by the mask argument become true for the file given by
file. The UNIX version of Tcl_WaitForEvent uses the infor-
mation passed to Tcl_WatchFile to set the file masks for
select, which it uses to wait for events. If Tcl_WatchFile
isn't called by any event sources then Tcl_WaitForEvent will
ignore files while waiting.
SetupProc can also invoke Tcl_SetMaxBlockTime to set an
upper bound on how long Tcl_WaitForEvent will block. If no
event source calls Tcl_SetMaxBlockTime then Tcl_WaitForEvent
will wait as long as necessary for an event to occur; oth-
erwise, it will only wait as long as the shortest interval
passed to Tcl_SetMaxBlockTime 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 timePtr argument to Tcl_WaitForEvent points
to a structure that describes a time interval in seconds and
microseconds:
typedef struct Tcl_Time {
long sec;
long usec;
} Tcl_Time;
The usec field should be less than 1000000.
Information provided to Tcl_WatchFile and
Tcl_SetMaxBlockTime is only used for the next call to
Tcl_WaitForEvent; it is discarded after Tcl_WaitForEvent
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.
In addition to the generic procedures Tcl_WatchFile and
Tcl_SetMaxBlockTime, other platform-specific procedures may
also be available for setupProc, if there is additional
information needed by Tcl_WaitForEvent on that platform.
The second procedure provided by each event source is its
check procedure, indicated by the checkProc argument to
Tcl_CreateEventSource. CheckProc must match the following
prototype:
typedef void Tcl_EventCheckProc(
ClientData clientData,
int flags);
The arguments to this procedure are the same as those for
setupProc. CheckProc is invoked by Tcl_DoOneEvent after it
has waited for events. Presumably at least one event source
is now prepared to queue an event. Tcl_DoOneEvent 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 Tcl_FileReady may be useful for some
event sources. It takes as arguments a file identifier file
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
Tcl_WaitForEvent. Tcl_WaitForEvent only checks a file if
Tcl_WatchFile was called by at least one event source, so it
is possible for Tcl_FileReady to return 0 even if the file
is ready.
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
Tcl_QueueEvent. The evPtr argument is a pointer to a dynam-
ically allocated structure containing the event (see below
for more information on memory management issues). Each
event source can define its own event structure with what-
ever information is relevant to that event source. However,
the first element of the structure must be a structure of
type Tcl_Event, and the address of this structure is used
when communicating between the event source and the rest of
the notifier. A Tcl_Event has the following definition:
typedef struct Tcl_Event {
Tcl_EventProc *proc;
struct Tcl_Event *nextPtr;
};
The event source must fill in the proc field of the event
before calling Tcl_QueueEvent. The nextPtr is used to link
together the events in the queue and should not be modified
by the event source.
An event may be added to the queue at any of three posi-
tions, depending on the position argument to Tcl_QueueEvent:
TCL_QUEUE_TAIL 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.
TCL_QUEUE_HEAD Add the event at the front of the
queue, so that it will be serviced
before all other queued events.
TCL_QUEUE_MARK Add the event at the front of the
queue, unless there are other events
at the front whose position is
TCL_QUEUE_MARK; if so, add the new
event just after all other
TCL_QUEUE_MARK events. This value
of position is used to insert an
ordered sequence of events at the
front of the queue, such as a series
of Enter and Leave events syn-
thesized during a grab or ungrab
operation in Tk.
When it is time to handle an event from the queue (steps 1
and 5 above) Tcl_DoOneEvent will invoke the proc specified
in the first queued Tcl_Event structure. Proc must match
the following prototype:
typedef int Tcl_EventProc(
Tcl_Event *evPtr,
int flags);
The first argument to proc is a pointer to the event, which
will be the same as the first argument to the Tcl_QueueEvent
call that added the event to the queue. The second argument
to proc is the flags argument for the current call to
Tcl_DoOneEvent; this is used by the event source to return
immediately if its events are not relevant.
It is up to proc 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 can-
not be handled at this time, it may return 0 to indicate
that the event should be deferred for processing later; in
this case Tcl_DoOneEvent 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 flags argu-
ment. For example, the file event source will always return
0 if the TCL_FILE_EVENTS bit isn't set in flags. Another
example of deferring events happens in Tk if
Tk_RestrictEvents has been invoked to defer certain kinds of
window events.
When proc returns 1, Tcl_DoOneEvent will remove the event
from the event queue and free its storage. Note that the
storage for an event must be allocated by the event source |
(using Tcl_Alloc or the Tcl macro ckalloc) before calling
Tcl_QueueEvent, but it will be freed by Tcl_DoOneEvent, not
by the event source.
CREATING A NEW NOTIFIER
The notifier consists of all the procedures described in
this manual entry, plus Tcl_DoOneEvent and Tcl_Sleep. Most
of these procedures are generic, in that they are the same
for all platforms. However, four of the procedures are
platform-dependent: Tcl_WatchFile, Tcl_FileReady,
Tcl_WaitForEvent, and Tcl_Sleep. To support a new platform,
you must write new versions of these procedures.
Tcl_WatchFile and Tcl_FileReady have already been described
previously in this document, and Tcl_Sleep is described in
its own manual entry.
Tcl_WaitForEvent is the lowest-level procedure in the notif-
ier; it is responsible for waiting for an ``interesting''
event to occur or for a given time to elapse. Before
Tcl_WaitForEvent is invoked, each of the event sources'
setup procedure will have been invoked; the setup pro-
cedures will have provided information about what to wait
for by invoking procedures like Tcl_WatchFile. The timePtr
argument to Tcl_WaitForEvent gives the maximum time to block
for an event, based on calls to Tcl_SetMaxBlockTime made by
setup procedures and on other information (such as the
TCL_DONT_WAIT bit in flags). Tcl_WaitForEvent uses informa-
tion saved by Tcl_WatchFile, plus the timePtr 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 Tcl_WatchFile nor
Tcl_SetMaxBlockTime has been called since the last call to
Tcl_WaitForEvent), so that the procedure would block for-
ever, then it returns immediately with a result of
TCL_ERROR.
The easiest way to create a new notifier is to look at the
code for an existing notifier, such as the files
generic/tclNotify.c and unix/tclUnixNotfy.c.
KEYWORDS
block time, event notifier, event queue, event sources, file
events