Skip to content

Instantly share code, notes, and snippets.

@hadley
Created May 31, 2018 14:59
Show Gist options
  • Save hadley/4278d0a6d3a10e42533d59905fbed0ac to your computer and use it in GitHub Desktop.
Save hadley/4278d0a6d3a10e42533d59905fbed0ac to your computer and use it in GitHub Desktop.
Walk through of R's condition handler C code

Registering handlers

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 with ENTRY_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 with ENTRY_HANDLER(e). This is the function called with the condition object. It can also be R_RestartToken, used as part of the restarts system.

  • The parentenv, accessed with ENTRY_CALLING_ENVIR(e). This does not appear to be used.

  • The target environment, accessed with ENTRY_TARGET_ENVIR(e), is only set by tryCatch(). This is used to find the frame that the handler will return to.

  • The calling flag, accessed with IS_CALLING_ENTRY(e) determines if this is a calling/in-place handler (TRUE) or an exiting handler (FALSE).

Signalling conditions

There are four ways for a condition to be signalled:

  • With stop() which calls vsignalError().

  • With an interrupt, which triggers signalInterrupt()

  • With warning(), which calls vsignalWarning(), which then calls vwarningcall_dflt(). (This is particularly complicated because warnings are usually cached and only shown after the top level execution completes.)

  • With signalCondition(), which calls do_signalCondition() (message() calls signalCondition() with a default handler that cat()s the message to stderr().)

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment