1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-01-14 07:20:35 -08:00

Part of making extension callbacks part of the public mps.

* Move type and macro declarations to the public header mps.h.
* Move documentation to appropriate sections of manual.

(cherry picked from commit b928fa236178fb1bdbe20442c3f53b8e8a545a4b)
This commit is contained in:
Richard Brooksby 2023-04-13 10:07:58 +01:00
parent e3accea56d
commit bf20351ddb
3 changed files with 109 additions and 3 deletions

View file

@ -120,6 +120,13 @@ typedef mps_addr_t (*mps_fmt_isfwd_t)(mps_addr_t);
typedef void (*mps_fmt_pad_t)(mps_addr_t, size_t);
typedef mps_addr_t (*mps_fmt_class_t)(mps_addr_t);
/* Callbacks indicating that the arena has extended or contracted.
* These are used to register chunks with RtlInstallFunctionTableCallback
* <https://docs.microsoft.com/en-gb/windows/win32/api/winnt/nf-winnt-rtlinstallfunctiontablecallback>
* so that the client can unwind the stack through functions in the arena.
*/
typedef void (*mps_arena_extended_t)(mps_arena_t, mps_addr_t, size_t);
typedef void (*mps_arena_contracted_t)(mps_arena_t, mps_addr_t, size_t);
/* Keyword argument lists */
@ -171,6 +178,12 @@ extern const struct mps_key_s _mps_key_ARENA_SIZE;
extern const struct mps_key_s _mps_key_ARENA_ZONED;
#define MPS_KEY_ARENA_ZONED (&_mps_key_ARENA_ZONED)
#define MPS_KEY_ARENA_ZONED_FIELD b
extern const struct mps_key_s _mps_key_arena_extended;
#define MPS_KEY_ARENA_EXTENDED (&_mps_key_arena_extended)
#define MPS_KEY_ARENA_EXTENDED_FIELD fun
extern const struct mps_key_s _mps_key_arena_contracted;
#define MPS_KEY_ARENA_CONTRACTED (&_mps_key_arena_contracted)
#define MPS_KEY_ARENA_CONTRACTED_FIELD fun
extern const struct mps_key_s _mps_key_FORMAT;
#define MPS_KEY_FORMAT (&_mps_key_FORMAT)
#define MPS_KEY_FORMAT_FIELD format

View file

@ -47,6 +47,12 @@ New features
:ref:`topic-scanning-protocol`. This allows the client program to
safely update references in the visited objects.
#. A :term:`virtual memory arena` can now be configured to call
functions when it acquires a new chunk of :term:`address space`,
and when it returns a chunk of address space to the operation
system. This is intended to support dynamic function tables in
Windows. See :ref:`topic-arena-extension`.
Interface changes
.................

View file

@ -139,7 +139,7 @@ Client arenas
* :c:macro:`MPS_KEY_ARENA_SIZE` (type :c:type:`size_t`) is its
size.
It also accepts three optional keyword arguments:
It also accepts five optional keyword arguments:
* :c:macro:`MPS_KEY_COMMIT_LIMIT` (type :c:type:`size_t`) is
the maximum amount of memory, in :term:`bytes (1)`, that the MPS
@ -159,6 +159,17 @@ Client arenas
may pause the :term:`client program` for. See
:c:func:`mps_arena_pause_time_set` for details.
* :c:macro:`MPS_KEY_ARENA_EXTENDED` (type :c:type:`mps_fun_t`) is
a function that will be called when the arena is *extended*:
that is, when it acquires a new chunk of address space from the
operating system. See :ref:`topic-arena-extension` for details.
* :c:macro:`MPS_KEY_ARENA_CONTRACTED` (type :c:type:`mps_fun_t`)
is a function that will be called when the arena is
*contracted*: that is, when it finishes with a chunk of address
space and returns it to the operating system. See
:ref:`topic-arena-extension` for details.
For example::
MPS_ARGS_BEGIN(args) {
@ -983,8 +994,8 @@ Arena introspection and debugging
from MPS-managed memory, then it may attempt to re-enter the
MPS, which will fail as the MPS is not re-entrant.
.. |RtlInstallFunctionTableCallback| replace:: ``RtlInstallFunctionTableCallback()``
.. _RtlInstallFunctionTableCallback: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680595(v=vs.85).aspx
.. |RtlInstallFunctionTableCallback| replace:: :c:func:`RtlInstallFunctionTableCallback`
.. _RtlInstallFunctionTableCallback: https://docs.microsoft.com/en-gb/windows/win32/api/winnt/nf-winnt-rtlinstallfunctiontablecallback
If this happens, in order to allow the debugger to finish
decoding the call stack, the only remedy is to put the arena
@ -1040,3 +1051,79 @@ Arena introspection and debugging
:c:func:`mps_addr_pool`, and to find out which :term:`object
format` describes the object at the address, use
:c:func:`mps_addr_fmt`.
.. index::
single: arena extension callbacks; introduction
single: extension callbacks; introduction
single: arena contraction callbacks; introduction
single: contraction callbacks; introduction
.. _topic-arena-extension:
Arena extension callbacks
-------------------------
There are situations in which the :term:`client program` needs to be
informed about the chunks of address space that an :term:`arena` is
managing. To support this, the MPS allows the client program to
specify two callback functions when creating a :term:`virtual memory
arena`: one function is called when the arena is *extended* (that is,
when it acquires a new chunk of address space from the operating
system), and the other when the arena is *contracted* (that is, when
it returns a chunk of address space to the operating system).
The use case that this feature is designed to support is debugging of
dynamically generated code in 64-bit Windows. Microsoft's
documentation for |RtlInstallFunctionTableCallback|_ says:
Function tables are used on 64-bit Windows to determine how to
unwind or walk the stack. These tables are usually generated by
the compiler and stored as part of the image. However,
applications must provide the function table for dynamically
generated code.
An application may install a dynamic function table by calling
|RtlInstallFunctionTableCallback|_, passing the region of memory in
which the dynamically generated functions can be found, and may later
delete the table by calling |RtlDeleteFunctionTable|_.
.. |RtlDeleteFunctionTable| replace:: :c:func:`RtlDeleteFunctionTable`
.. _RtlDeleteFunctionTable: https://docs.microsoft.com/en-gb/windows/win32/api/winnt/nf-winnt-rtldeletefunctiontable
So if the client program is storing dynamically generated functions in
MPS-managed memory, then it could define callback functions that
install and delete the function table callback for the dynamically
generated code, like this::
void arena_extended(mps_arena_t arena, void *base, size_t size)
{
RtlInstallFunctionTableCallback(...);
}
void arena_contracted(mps_arena_t arena, void *base, size_t size)
{
RtlDeleteFunctionTable(...);
}
and then pass these two functions using :term:`keyword arguments` to
:c:func:`mps_arena_create_k`::
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_EXTENDED, (mps_fun_t)arena_extended);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_CONTRACTED, (mps_fun_t)arena_contracted);
/* ... other keyword arguments ... */
res = mps_arena_create_k(&arena, mps_arena_class_vm(), args);
} MPS_ARGS_END(args);
The callback functions receive three arguments: ``arena`` (the arena
being extended or contracted), ``base`` (the base address of the chunk
of address space that has just been acquired from, or is about to be
returned to, the operating system), and ``size`` (the size of the
chunk, in bytes). They must not call any function in the MPS, and must
not access any memory managed by the MPS.
.. note::
Arena extension callbacks are only supported by :term:`virtual
memory arenas`.