The key C function that powers both tryCatch() and withCallingHandlers() is do_addCondHands(). It creates handler object with mkHandlerEntry() then stores in the handler stack for the current frame. (More precisely it writes to R_HandlerStack, a global variable that is an alias to c->handlerstack)
The five R arguments to do_addCondHands() are classes, handlers, parentenv, target, and calling. These are combined with a result object (a list of length 4, returned by the exiting handler to doTryCatch()) to create the handler objects which have five components:
-
The
class, accessed withENTRY_CLASS(e). A string given a class name; the handler will match all conditions that contain this component in their class vector. -
The
handler, accessed withENTRY_HANDLER(e). This is the function called with the condition object. It can also beR_RestartToken, used as part of the restarts system. -
The
parentenv, accessed withENTRY_CALLING_ENVIR(e). This does not appear to be used. -
The
targetenvironment, accessed withENTRY_TARGET_ENVIR(e), is only set bytryCatch(). This is used to find the frame that the handler will return to. -
The
callingflag, accessed withIS_CALLING_ENTRY(e)determines if this is a calling/in-place handler (TRUE) or an exiting handler (FALSE).
There are four ways for a condition to be signalled:
-
With
stop()which callsvsignalError(). -
With an interrupt, which triggers
signalInterrupt() -
With
warning(), which callsvsignalWarning(), which then callsvwarningcall_dflt(). (This is particularly complicated because warnings are usually cached and only shown after the top level execution completes.) -
With
signalCondition(), which callsdo_signalCondition()(message()callssignalCondition()with a default handler thatcat()s the message tostderr().)
Each of C signalling functions works similarly. It finds a matching handler in R_HandlerStack, using findConditionHandler() or similar, and then either calls it or calls gotoExitingHandler.