#lang scribble/doc
@(require "mz.rkt")

@title[#:tag "plumbers"]{Plumbers}

A @deftech{plumber} supports @deftech{flush callbacks}, which are
normally triggered just before a Racket process or @tech{place} exits.
For example, a @tech{flush callback} might flush an output port's
buffer.@margin-note{@tech{Flush callbacks} are roughly analogous to the standard C
library's @as-index{@tt{atexit}}, but flush callback can also be used in other,
similar scenarios.}

There is no guarantee that a flush callback will be called before a
process terminates---either because the plumber is not the original
plumber that is flushed by the default @tech{exit handler}, or because
the process is terminated forcibly (e.g., through a custodian
shutdown).


@defproc[(plumber? [v any/c]) boolean?]{

Returns @racket[#t] if @racket[v] is a @tech{plumber} value,
@racket[#f] otherwise.

@history[#:added "6.0.1.8"]}


@defproc[(make-plumber) plumber?]{

Creates a new @tech{plumber}.

Plumbers have no hierarchy (unlike @tech{custodians} or
@tech{inspectors}), but a @tech{flush callback} can be registered in
one plumber to call @racket[plumber-flush-all] with another plumber.

@history[#:added "6.0.1.8"]}


@defparam[current-plumber plumber plumber?]{

A @tech{parameter} that determines a @deftech{current plumber} for
@tech{flush callbacks}. For example, creating an output @tech{file
stream port} registers a @tech{flush callback} with the @tech{current
plumber} to flush the port as long as the port is opened.

@history[#:added "6.0.1.8"]}


@defproc[(plumber-flush-all [plumber plumber?]) void?]{

Calls all @tech{flush callbacks} that are registered with @racket[plumber].

The @tech{flush callbacks} to call are collected from @racket[plumber]
before the first one is called. If a @tech{flush callback} registers a
new @tech{flush callback}, the new one is @emph{not} called. If a
@tech{flush callback} raises an exception or otherwise escapes, then
the remaining @tech{flush callbacks} are not called.

@history[#:added "6.0.1.8"]}


@defproc[(plumber-flush-handle? [v any/c]) boolean?]{

Returns @racket[#t] if @racket[v] is a @deftech{flush handle}
represents the registration of a @tech{flush callback}, @racket[#f]
otherwise.

@history[#:added "6.0.1.8"]}


@defproc[(plumber-add-flush! [plumber plumber?]
                             [proc (plumber-flush-handle? . -> . any)]
                             [weak? any/c #f])
         plumber-flush-handle?]{

Registers @racket[proc] as a @tech{flush callback} with @racket[plumber], so
that @racket[proc] is called when @racket[plumber-flush-all] is
applied to @racket[plumber].

The result @tech{flush handle} represents the registration of the
callback, and it can be used with @racket[plumber-flush-handle-remove!] to
unregister the callback.

The given @racket[proc] is reachable from the @tech{flush handle}, but
if @racket[weak?] is true, then @racket[plumber] retains only a
@tech{weak reference} to the result @tech{flush handle} (and
thus @racket[proc]).

When @racket[proc] is called as a @tech{flush callback}, it is passed
the same value that is returned by @racket[plumber-add-flush!] so
that @racket[proc] can conveniently unregister itself. The call of
@racket[proc] is within a @tech{continuation barrier}.

@history[#:added "6.0.1.8"]}


@defproc[(plumber-flush-handle-remove! [handle plumber-flush-handle?]) void?]{

Unregisters the @tech{flush callback} that was registered by the
@racket[plumber-add-flush!] call that produced @racket[handle].

If the registration represented by @racket[handle] has been removed already,
then @racket[plumber-flush-handle-remove!] has no effect.

@history[#:added "6.0.1.8"]}
