@@ -139,7 +139,7 @@ Client arenas
139139 * :c:macro:`MPS_KEY_ARENA_SIZE` (type :c:type: `size_t `) is its
140140 size.
141141
142- It also accepts three optional keyword arguments:
142+ It also accepts five optional keyword arguments:
143143
144144 * :c:macro:`MPS_KEY_COMMIT_LIMIT` (type :c:type: `size_t `) is
145145 the maximum amount of memory, in :term:`bytes (1)`, that the MPS
@@ -159,6 +159,17 @@ Client arenas
159159 may pause the :term:`client program` for. See
160160 :c:func:`mps_arena_pause_time_set` for details.
161161
162+ * :c:macro:`MPS_KEY_ARENA_EXTENDED` (type :c:type: `mps_fun_t `) is
163+ a function that will be called when the arena is *extended*:
164+ that is, when it acquires a new chunk of address space from the
165+ operating system. See :ref:`topic-arena-extension` for details.
166+
167+ * :c:macro:`MPS_KEY_ARENA_CONTRACTED` (type :c:type: `mps_fun_t `)
168+ is a function that will be called when the arena is
169+ *contracted*: that is, when it finishes with a chunk of address
170+ space and returns it to the operating system. See
171+ :ref:`topic-arena-extension` for details.
172+
162173 For example::
163174
164175 MPS_ARGS_BEGIN(args) {
@@ -983,8 +994,8 @@ Arena introspection and debugging
983994 from MPS-managed memory, then it may attempt to re-enter the
984995 MPS, which will fail as the MPS is not re-entrant.
985996
986- .. |RtlInstallFunctionTableCallback| replace:: `` RtlInstallFunctionTableCallback()` `
987- .. _RtlInstallFunctionTableCallback: https:// msdn .microsoft.com/en-us/library/ windows/desktop/ms680595(v=vs.85).aspx
997+ .. |RtlInstallFunctionTableCallback| replace:: :c:func:` RtlInstallFunctionTableCallback`
998+ .. _RtlInstallFunctionTableCallback: https:// docs .microsoft.com/en-gb/ windows/win32/api/winnt/nf-winnt-rtlinstallfunctiontablecallback
988999
9891000 If this happens, in order to allow the debugger to finish
9901001 decoding the call stack, the only remedy is to put the arena
@@ -1040,3 +1051,79 @@ Arena introspection and debugging
10401051 :c:func: `mps_addr_pool `, and to find out which :term: `object
10411052 format ` describes the object at the address, use
10421053 :c:func: `mps_addr_fmt `.
1054+
1055+
1056+ .. index ::
1057+ single: arena extension callbacks; introduction
1058+ single: extension callbacks; introduction
1059+ single: arena contraction callbacks; introduction
1060+ single: contraction callbacks; introduction
1061+
1062+ .. _topic-arena-extension :
1063+
1064+ Arena extension callbacks
1065+ -------------------------
1066+
1067+ There are situations in which the :term: `client program ` needs to be
1068+ informed about the chunks of address space that an :term: `arena ` is
1069+ managing. To support this, the MPS allows the client program to
1070+ specify two callback functions when creating a :term: `virtual memory
1071+ arena `: one function is called when the arena is *extended * (that is,
1072+ when it acquires a new chunk of address space from the operating
1073+ system), and the other when the arena is *contracted * (that is, when
1074+ it returns a chunk of address space to the operating system).
1075+
1076+ The use case that this feature is designed to support is debugging of
1077+ dynamically generated code in 64-bit Windows. Microsoft's
1078+ documentation for |RtlInstallFunctionTableCallback |_ says:
1079+
1080+ Function tables are used on 64-bit Windows to determine how to
1081+ unwind or walk the stack. These tables are usually generated by
1082+ the compiler and stored as part of the image. However,
1083+ applications must provide the function table for dynamically
1084+ generated code.
1085+
1086+ An application may install a dynamic function table by calling
1087+ |RtlInstallFunctionTableCallback |_, passing the region of memory in
1088+ which the dynamically generated functions can be found, and may later
1089+ delete the table by calling |RtlDeleteFunctionTable |_.
1090+
1091+ .. |RtlDeleteFunctionTable | replace :: :c:func: `RtlDeleteFunctionTable `
1092+ .. _RtlDeleteFunctionTable : https://docs.microsoft.com/en-gb/windows/win32/api/winnt/nf-winnt-rtldeletefunctiontable
1093+
1094+ So if the client program is storing dynamically generated functions in
1095+ MPS-managed memory, then it could define callback functions that
1096+ install and delete the function table callback for the dynamically
1097+ generated code, like this::
1098+
1099+ void arena_extended(mps_arena_t arena, void *base, size_t size)
1100+ {
1101+ RtlInstallFunctionTableCallback(...);
1102+ }
1103+
1104+ void arena_contracted(mps_arena_t arena, void *base, size_t size)
1105+ {
1106+ RtlDeleteFunctionTable(...);
1107+ }
1108+
1109+ and then pass these two functions using :term: `keyword arguments ` to
1110+ :c:func: `mps_arena_create_k `::
1111+
1112+ MPS_ARGS_BEGIN(args) {
1113+ MPS_ARGS_ADD(args, MPS_KEY_ARENA_EXTENDED, (mps_fun_t)arena_extended);
1114+ MPS_ARGS_ADD(args, MPS_KEY_ARENA_CONTRACTED, (mps_fun_t)arena_contracted);
1115+ /* ... other keyword arguments ... */
1116+ res = mps_arena_create_k(&arena, mps_arena_class_vm(), args);
1117+ } MPS_ARGS_END(args);
1118+
1119+ The callback functions receive three arguments: ``arena `` (the arena
1120+ being extended or contracted), ``base `` (the base address of the chunk
1121+ of address space that has just been acquired from, or is about to be
1122+ returned to, the operating system), and ``size `` (the size of the
1123+ chunk, in bytes). They must not call any function in the MPS, and must
1124+ not access any memory managed by the MPS.
1125+
1126+ .. note ::
1127+
1128+ Arena extension callbacks are only supported by :term: `virtual
1129+ memory arenas `.
0 commit comments