Skip to content

Commit

Permalink
support procedural process-trap-exit handler
Browse files Browse the repository at this point in the history
Support a procedural handler as the value for process-trap-exit
so that a process blocked in a gen-server call can perform some
clean-up if killed.

This commit also fixes an obscure bug in the case where a receive
form has a guard that calls receive.

Rework the interactive console so that:
 - we can interrupt the REPL via ^C on Windows again,
 - we can wait until interrupts are enabled before invoking the
   keyboard-interrupt-handler, and
 - a script can start an interactive REPL that handles ^C as Swish does

User visible changes to the behavior of the interactive console include:
 - trying to read from the console in a spawned process returns #!eof,
  • Loading branch information
owaddell-beckman committed Mar 8, 2024
1 parent a2ba260 commit da9ff8d
Show file tree
Hide file tree
Showing 8 changed files with 1,160 additions and 169 deletions.
51 changes: 48 additions & 3 deletions doc/swish/erlang.tex
Original file line number Diff line number Diff line change
Expand Up @@ -973,11 +973,41 @@
\begin{parameter}
\code{process-trap-exit}
\end{parameter}
\hasvalue{} boolean
\hasvalue{} boolean or a procedure

The \code{process-trap-exit} parameter specifies whether or not the
calling process traps exit signals as messages. Processes start with
this parameter set to \code{\#f}.
calling process traps exit signals as messages.
Processes do not trap exit signals by default; therefore,
processes start with this parameter set to \code{\#f}.
To trap exit signals as messages, a process sets this parameter
to \code{\#t} or a procedure.
A gen-server can set the parameter to \code{\#t} and handle exit messages
via its \code{handle-info} callback; see Section~\ref{sec:gen-server-callback} for details.
Other processes can handle these messages via \code{receive}.

A process may set the \code{process-trap-exit} parameter to a \var{handler}
procedure that accepts one argument, \var{msg}.
When the scheduler resumes that process, it checks whether \code{kill} or
\code{link} has delivered an exit signal as a message.
If so, it retrieves the first exit message, invokes \var{handler} on that
message, and repeats this until it has consumed the available exit messages.\footnote{An exit message delivered via \code{send} will not trigger \var{handler} on its own, but \var{handler} may consume that message if
the scheduler invokes \var{handler}.}
A \var{handler} procedure may be useful, for example, to perform some cleanup
in case an exit signal arrives while a process is blocked awaiting a reply in
\code{gen-server:call}.

% ----------------------------------------------------------------------------
\defineentry{raise-on-exit}
\begin{procedure}
\code{(raise-on-exit \var{msg})}
\end{procedure}
\returns{} see below

The \code{raise-on-exit} procedure expects an exit message \var{msg}
matching \code{`(EXIT \var{pid} \var{reason})}.
If \var{reason} is \code{normal}, \code{raise-on-exit} returns
an unspecified value.
Otherwise, it raises an exception involving \var{reason}.

% ----------------------------------------------------------------------------
\defineentry{self}
Expand All @@ -991,6 +1021,21 @@
global variable cannot be used directly because library bindings are
immutable.

% ----------------------------------------------------------------------------
\defineentry{with-interrupts-disabled-for-io}
\begin{syntax}
\code{(with-interrupts-disabled-for-io \var{body$_1$} \var{body$_2$} \etc)}
\end{syntax}
\expandsto{} see below

The \code{with-interrupts-disabled-for-io} macro is like
\code{with-interrupts-disabled} except that, just before returning, it checks
for trapped exit messages.
The system handles trapped exit messages at this time only if
\code{process-trap-exit} is set to a procedure.
This macro is intended for use in code that calls \code{wait-for-io} and
\code{complete-io} with interrupts disabled.

% ----------------------------------------------------------------------------
\subsection{Miscellaneous}

Expand Down
2 changes: 1 addition & 1 deletion doc/swish/gen-server.tex
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@
\argrow{reply}{the server's reply or \code{\#f}}
\end{pubevent}

\section {Callback Interface}
\section {Callback Interface}\label{sec:gen-server-callback}

A programmer implements the callback interface to define a particular
server's behavior. All callback functions are called from within the
Expand Down
2 changes: 1 addition & 1 deletion src/swish/app-core.ss
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@
(set! started? #t)
(base-exception-handler app-exception-handler)
(random-seed (+ (remainder (erlang:now) (- (ash 1 32) 1)) 1))
(trap-signals handle-signal)
(hook-console-input)
(call/cc
(lambda (bail)
Expand All @@ -211,7 +212,6 @@
(when stand-alone?
(app:name who)
(app:path who))
(trap-signals handle-signal)
(set! Charon
(spawn
(let ([me self])
Expand Down
11 changes: 0 additions & 11 deletions src/swish/app.ss
Original file line number Diff line number Diff line change
Expand Up @@ -180,17 +180,6 @@
(try-import)
(parameterize ([waiter-prompt-string (if (opt 'quiet) "" ">")]
[repl-level (+ (repl-level) 1)])
(define (trap-CTRL-C handler)
(meta-cond
[windows?
(signal-handler SIGBREAK handler)
(signal-handler SIGINT handler)]
[else
(signal-handler SIGINT handler)]))
(when (interactive?)
(trap-CTRL-C
(let ([p self])
(lambda (n) (keyboard-interrupt p)))))
(for-each load filenames)
(new-cafe)))]
[else ; script
Expand Down
Loading

0 comments on commit da9ff8d

Please sign in to comment.