Table of Contents
The continuation interface is Traffic Server’s basic callback
mechanism. Continuations are instances of the opaque data type INKCont
. In
its basic form, a continuation represents a handler function and a mutex.
This chapter covers the following topics:
A continuation must be created with a mutex if your continuation does one of the following:
is registered globally (INKHttpHookAdd
or
INKHttpSsnHookAdd
) to an HTTP hook and uses
INKContDataSet/Get
is registered locally (INKHttpTxnHookAdd
),
but for multiple transactions uses
INKContDataSet/Get
uses INKCacheXXX
,
INKNetXXX
, INKHostLookup
, or INKContSchedule
APIs
Before being activated, a caller must grab the continuation’s
mutex. This requirement makes it possible for a continuation’s handler
function to safely access its data and to prevent multiple callers from running it at the same time (see the sample Protocol plugin for
usage). The data protected by the mutex is any global or continuation
data associated to the continuation by
INKContDataSet
. This does not include the local
data created by the continuation handler function. A typical example of
continuations created with associated data structures and mutexes is the
transaction state machine created in the sample Protocol plugin (see
One Way to Implement a Transaction State Machine).
A reentrant call occurs when the continuation passed as an
argument to the API can be called in the same stack trace as the
function calling the API. For example, if you call INKCacheRead
(contp, mykey
), it is possible that contp
’s handler will be
called directly and then INKCacheRead
returns.
Caveats that could cause issues include the following:
a continuation has data associated with it
(INKContDataGet
).
the reentrant call passes itself as a continuation to the reentrant API. In this case, the continuation should not try to access its data after calling the reentrant API. The reason for this is that data may be modified by the section of code in the continuation’s handler that handles the event sent by the API. It is recommended that you always return after a reentrant call to avoid accessing something that has been deallocated.
Below is an example, followed by an explanation.
continuation_handler (INKCont contp, INKEvent event, void *edata) { switch (event) { case event1: INKReentrantCall (contp); /* Return right away after this call */ break; case event2: INKContDestroy (contp); break; } }
The above example first assumes that the continuation is called
back with event1
; it then does the first reentrant call that
schedules the continuation to receive event2
. Because the
call is reentrant, the processor calls back the continuation right away
with event2
and the continuation is destroyed. If you try
to access the continuation or one of its members after the reentrant
call, then you might access something that has been deallocated. To avoid
accessing something that has been deallocated, never access the
continuation or any of its members after a reentrant call - just exit the
handler.
Note: Most HTTP transaction plugin continuations do not need non-null mutexes because they're called within the processing of an HTTP transaction, and therefore have the transaction’s mutex.
It is also possible to specify a continuation’s mutex as
NULL
. This should be done only when registering a
continuation to a global hook, by a call to
INKHttpHookAdd
. In this case, the continuation can
be called simultaneously by different instances of HTTP SM running on
different threads. Having a mutex here would slow and/or hinder Traffic Server
performance, since all the threads will try to lock the same mutex. The
drawback of not having a mutex is that such a continuation cannot have
data associated with it (i.e., INKContDataGet/Set
cannot
be used).
When using a NULL
mutex it is dangerous to access
the continuation’s data, but usually continuations
with NULL
mutexes have no data associated with them anyway. An
example of such a continuation is one that gets called back every
time an HTTP request is read, and then determines from the request alone
if the request should go through or be rejected. An HTTP
transaction gives its continuation data to the
contp
.