mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-03 10:31:37 -08:00
357 lines
12 KiB
ReStructuredText
357 lines
12 KiB
ReStructuredText
.. Sources:
|
|
|
|
`<https://info.ravenbrook.com/project/mps/master/design/message/>`_
|
|
`<https://info.ravenbrook.com/mail/2005/04/05/13-33-11/0.txt>`_
|
|
|
|
.. index::
|
|
single: message; introduction
|
|
|
|
.. _topic-message:
|
|
|
|
Messages
|
|
========
|
|
|
|
The MPS sometimes needs to communicate with the :term:`client program`
|
|
about events which occur :term:`asynchronously <asynchronous garbage
|
|
collector>`, and so information cannot be returned as function call
|
|
results.
|
|
|
|
*Messages* are the mechanism for this asynchronous communication,
|
|
implemented in the form of a :term:`message queue` attached to each
|
|
:term:`arena`.
|
|
|
|
The client program must enable each message type that it is prepared
|
|
to handle, by calling :c:func:`mps_message_type_enable`. Then it must
|
|
poll the message queue at regular intervals when it is convenient to
|
|
do so, calling :c:func:`mps_message_get` to retrieve each message from
|
|
the queue, and finally calling :c:func:`mps_message_discard` when done
|
|
with the message.
|
|
|
|
Messages are thus :term:`manually managed <manual memory management>`:
|
|
if the client program enables one or more message types, and then
|
|
neglects to poll the message queue or neglects to discard the messages
|
|
it retrieved, then messages will :term:`leak <memory leak>`.
|
|
|
|
There is no requirement on the client program to retrieve and discard
|
|
messages promptly. However, a client program that allows the number of
|
|
garbage collection (or garbage collection start) messages on the
|
|
message queue to grow without limit will eventually find that new
|
|
garbage collections no longer start until some of these messages are
|
|
retrieved and discarded.
|
|
|
|
|
|
.. index::
|
|
pair: message; finalization
|
|
|
|
Finalization messages
|
|
---------------------
|
|
|
|
:term:`Finalization` is implemented by posting a finalization message
|
|
(of type :c:func:`mps_message_type_finalization`) to the arena's
|
|
message queue. This allows the :term:`client program` to perform the
|
|
finalization at a convenient time and so avoid synchronization
|
|
difficulties.
|
|
|
|
The block is not actually reclaimed until the finalization message is
|
|
removed from the message queue and discarded, by calling
|
|
:c:func:`mps_message_get` followed by :c:func:`mps_message_discard`.
|
|
|
|
See :ref:`topic-finalization`.
|
|
|
|
|
|
.. index::
|
|
single: message; example
|
|
single: Scheme; interactive chatter
|
|
|
|
Example: interactive chatter
|
|
----------------------------
|
|
|
|
The toy Scheme interpreter enables garbage collection messages when
|
|
started in interactive mode::
|
|
|
|
mps_message_type_enable(arena, mps_message_type_gc());
|
|
mps_message_type_enable(arena, mps_message_type_gc_start());
|
|
|
|
Then, after every interactive command finishes, it reads these
|
|
messages from the message queue and prints a description of the
|
|
contents of each one::
|
|
|
|
static void mps_chat(void)
|
|
{
|
|
mps_message_type_t type;
|
|
|
|
while (mps_message_queue_type(&type, arena)) {
|
|
mps_message_t message;
|
|
mps_bool_t b;
|
|
b = mps_message_get(&message, arena, type);
|
|
assert(b); /* we just checked there was one */
|
|
|
|
if (type == mps_message_type_gc_start()) {
|
|
printf("Collection started.\n");
|
|
printf(" Why: %s\n", mps_message_gc_start_why(arena, message));
|
|
printf(" Clock: %lu\n", (unsigned long)mps_message_clock(arena, message));
|
|
if (type == mps_message_type_gc()) {
|
|
/* ... and so on for other message types ... */
|
|
} else {
|
|
printf("Unknown message from MPS!\n");
|
|
}
|
|
|
|
mps_message_discard(arena, message);
|
|
}
|
|
}
|
|
|
|
Here's how this looks in operation:
|
|
|
|
.. code-block:: none
|
|
|
|
MPS Toy Scheme Example
|
|
9960, 0> (define (make-list n e) (if (eqv? n 0) '() (cons e (make-list (- n 1) e))))
|
|
make-list
|
|
10824, 0> (length (make-list 1000 #t))
|
|
1000
|
|
Collection started.
|
|
Why: Generation 0 of a chain has reached capacity: start a minor collection.
|
|
Clock: 6649
|
|
507408, 1> (length (make-list 200 #f))
|
|
200
|
|
Collection finished.
|
|
live 112360
|
|
condemned 196600
|
|
not_condemned 0
|
|
clock: 18431
|
|
607192, 1> Bye.
|
|
|
|
.. note::
|
|
|
|
This kind of interactive "chatter" may be useful when testing and
|
|
debugging memory management, but should not be used otherwise. The
|
|
scheduling of garbage collections is not normally of interest even
|
|
to programmers, and chatter of this sort may give the illusion
|
|
that a program is spending much more time garbage collecting than
|
|
is actually the case.
|
|
|
|
Versions of GNU Emacs prior to 19.31 (May 1996) used to display
|
|
the message "Garbage collecting..." during a collection. Erik
|
|
Naggum commented on this feature:
|
|
|
|
I have run some tests at the U of Oslo with about 100
|
|
users who generally agreed that Emacs had become faster in
|
|
the latest Emacs pretest. All I had done was to remove the
|
|
"Garbage collecting" message which people perceive as
|
|
slowing Emacs down and tell them that it had been sped up.
|
|
|
|
|
|
.. index::
|
|
single: message; types
|
|
|
|
Message types
|
|
-------------
|
|
|
|
.. c:type:: mps_message_type_t
|
|
|
|
The type of :term:`message types`.
|
|
|
|
There are three message types:
|
|
|
|
1. :c:func:`mps_message_type_finalization`
|
|
2. :c:func:`mps_message_type_gc`
|
|
3. :c:func:`mps_message_type_gc_start`
|
|
|
|
|
|
.. c:function:: void mps_message_type_disable(mps_arena_t arena, mps_message_type_t message_type)
|
|
|
|
Restore an :term:`arena` to the default state whereby
|
|
:term:`messages` of the specified :term:`message type`
|
|
are not posted, reversing the effect of an earlier call to
|
|
:c:func:`mps_message_type_enable`.
|
|
|
|
``arena`` is an arena.
|
|
|
|
``message_type`` is the message type to be disabled.
|
|
|
|
Any existing messages of the specified type are flushed from the
|
|
:term:`message queue` of ``arena``.
|
|
|
|
.. note::
|
|
|
|
It is permitted to call this function when ``message_type`` is
|
|
already disabled, in which case it has no effect.
|
|
|
|
|
|
.. c:function:: void mps_message_type_enable(mps_arena_t arena, mps_message_type_t message_type)
|
|
|
|
Enable an :term:`arena` to post :term:`messages` of a
|
|
specified :term:`message type`.
|
|
|
|
``arena`` is an arena.
|
|
|
|
``message_type`` is the message type to be enabled.
|
|
|
|
This function tells the MPS that ``arena`` may post messages of
|
|
``message_type`` to its :term:`message queue`. By default, the MPS
|
|
does not generate any messages of any type.
|
|
|
|
A :term:`client program` that enables messages for a message type
|
|
must access messages by calling :c:func:`mps_message_get` and
|
|
discard them by calling :c:func:`mps_message_discard`, or the
|
|
message queue may consume unbounded resources.
|
|
|
|
The client program may disable the posting of messages by calling
|
|
:c:func:`mps_message_type_disable`.
|
|
|
|
.. note::
|
|
|
|
It is permitted to call this function when ``message_type`` is
|
|
already enabled, in which case it has no effect.
|
|
|
|
|
|
.. index::
|
|
single: message; interface
|
|
|
|
Message interface
|
|
-----------------
|
|
|
|
.. c:type:: mps_message_t
|
|
|
|
The type of a :term:`message`.
|
|
|
|
Messages are :term:`manually <manual memory management>` managed.
|
|
They are created at the instigation of the MPS (but see
|
|
:c:func:`mps_message_type_enable`), and are deleted by the
|
|
:term:`client program` by calling :c:func:`mps_message_discard`.
|
|
|
|
An :term:`arena` has a :term:`message queue` from which messages
|
|
can be obtained by calling :c:func:`mps_message_get`.
|
|
|
|
An :c:type:`mps_message_t` is a :term:`reference` into MPS managed
|
|
memory, and can safely be :term:`fixed`.
|
|
|
|
|
|
.. c:function:: mps_clock_t mps_message_clock(mps_arena_t arena, mps_message_t message)
|
|
|
|
Returns the time at which the MPS posted a :term:`message`.
|
|
|
|
``arena`` is the :term:`arena` which posted the message.
|
|
|
|
``message`` is a message retrieved by :c:func:`mps_message_get` and
|
|
not yet discarded.
|
|
|
|
If ``message`` belongs to one of the following supported message,
|
|
return the time at which the MPS posted the message:
|
|
|
|
* :c:type:`mps_message_type_gc`;
|
|
* :c:type:`mps_message_type_gc_start`.
|
|
|
|
For other message types, the value returned is always zero.
|
|
|
|
Messages are asynchronous: they are posted by the MPS, wait on a
|
|
queue, and are later collected by the :term:`client program`. Each
|
|
message (of the supported message types) records the time that it
|
|
was posted, and this is what :c:func:`mps_message_clock` returns.
|
|
|
|
The time returned is the :c:func:`mps_clock_t` value returned by
|
|
the :term:`plinth` function :c:func:`mps_clock` at the time the
|
|
message was posted. You can subtract one clock value from another
|
|
to get the time interval between the posting of two messages.
|
|
|
|
|
|
.. c:function:: void mps_message_discard(mps_arena_t arena, mps_message_t message)
|
|
|
|
Indicate to the MPS that the :term:`client program` has no further
|
|
use for a :term:`message` and the MPS can now reclaim any storage
|
|
associated with the message.
|
|
|
|
``arena`` is the :term:`arena` which posted the message.
|
|
|
|
``message`` is the message. After this call, ``message`` is invalid
|
|
and should not be passed as an argument to any message functions.
|
|
|
|
Messages are essentially :term:`manually <manual memory
|
|
management>` managed. This function allows the MPS to reclaim
|
|
storage associated with messages. If the client does not discard
|
|
messages then the resources used may grow without bound.
|
|
|
|
As well as consuming resources, messages may have other effects
|
|
that require them to be tidied by calling this function. In
|
|
particular finalization messages refer to a :term:`finalized
|
|
block`, and prevent the object from being reclaimed (subject to
|
|
the usual :term:`garbage collection` liveness analysis). A
|
|
finalized block cannot be reclaimed until all its finalization
|
|
messages have been discarded. See
|
|
:c:func:`mps_message_type_finalization`.
|
|
|
|
.. seealso::
|
|
|
|
:ref:`topic-finalization`.
|
|
|
|
|
|
.. c:function:: mps_message_type_t mps_message_type(mps_arena_t arena, mps_message_t message)
|
|
|
|
Return the :term:`message type` of a :term:`message`.
|
|
|
|
``arena`` is the arena that posted the message.
|
|
|
|
``message`` is a message retrieved by :c:func:`mps_message_get` and
|
|
not yet discarded.
|
|
|
|
|
|
.. index::
|
|
single: message; queue interface
|
|
|
|
Message queue interface
|
|
-----------------------
|
|
|
|
.. c:function:: mps_bool_t mps_message_get(mps_message_t *message_o, mps_arena_t arena, mps_message_type_t message_type)
|
|
|
|
Get a :term:`message` of a specified type from the :term:`message
|
|
queue` for an :term:`arena`.
|
|
|
|
``message_o`` points to a location that will hold the address of the
|
|
message if the function succeeds.
|
|
|
|
``arena`` is the arena.
|
|
|
|
``message_type`` is the type of message to return.
|
|
|
|
If there is at least one message of the specified type on the
|
|
message queue of the specified arena, then this function removes
|
|
one such message from the queue, stores a pointer to the message
|
|
in the location pointed to by ``message_o``, and returns true.
|
|
Otherwise it returns false.
|
|
|
|
|
|
.. c:function:: mps_bool_t mps_message_poll(mps_arena_t arena)
|
|
|
|
Determine whether there are currently any :term:`messages` on a :term:`message queue` for an :term:`arena`.
|
|
|
|
``arena`` is the arena whose message queue will be polled.
|
|
|
|
Returns true if there is at least one message on the message queue
|
|
for ``arena``, or false if the message queue is empty.
|
|
|
|
.. note::
|
|
|
|
If you are interested in a particular type of message, it is
|
|
usually simpler to call :c:func:`mps_message_get`.
|
|
|
|
|
|
.. c:function:: mps_bool_t mps_message_queue_type(mps_message_type_t *message_type_o, mps_arena_t arena)
|
|
|
|
Determine whether there are currently any :term:`messages` on a :term:`message queue` for an :term:`arena`, and
|
|
return the :term:`message type` of the first message, if any.
|
|
|
|
``message_type_o`` points to a location that will hold the message
|
|
type of the first message on the queue, if any.
|
|
|
|
``arena`` is the arena whose message queue will be polled.
|
|
|
|
If there is at least one message on the message queue of ``arena``,
|
|
then this function returns true, and also writes the message type
|
|
of the first message on the queue into the location pointed to by
|
|
``message_type_o``. If there are no messages on the message queue,
|
|
it returns false.
|
|
|
|
.. note::
|
|
|
|
If you are interested in a particular type of message, it is
|
|
usually simpler to call :c:func:`mps_message_get`.
|