@@ -148,7 +148,7 @@ impl<VM: VMBinding> MMTK<VM> {
148
148
149
149
let state = Arc :: new ( GlobalState :: default ( ) ) ;
150
150
151
- let gc_requester = Arc :: new ( GCRequester :: new ( ) ) ;
151
+ let gc_requester = Arc :: new ( GCRequester :: new ( scheduler . clone ( ) ) ) ;
152
152
153
153
let gc_trigger = Arc :: new ( GCTrigger :: new (
154
154
options. clone ( ) ,
@@ -220,6 +220,93 @@ impl<VM: VMBinding> MMTK<VM> {
220
220
}
221
221
}
222
222
223
+ /// Initialize the GC worker threads that are required for doing garbage collections.
224
+ /// This is a mandatory call for a VM during its boot process once its thread system
225
+ /// is ready.
226
+ ///
227
+ /// Internally, this function will invoke [`Collection::spawn_gc_thread()`] to spawn GC worker
228
+ /// threads.
229
+ ///
230
+ /// # Arguments
231
+ ///
232
+ /// * `tls`: The thread that wants to enable the collection. This value will be passed back
233
+ /// to the VM in [`Collection::spawn_gc_thread()`] so that the VM knows the context.
234
+ ///
235
+ /// [`Collection::spawn_gc_thread()`]: crate::vm::Collection::spawn_gc_thread()
236
+ pub fn initialize_collection ( & ' static self , tls : VMThread ) {
237
+ assert ! (
238
+ !self . state. is_initialized( ) ,
239
+ "MMTk collection has been initialized (was initialize_collection() already called before?)"
240
+ ) ;
241
+ self . scheduler . spawn_gc_threads ( self , tls) ;
242
+ self . state . initialized . store ( true , Ordering :: SeqCst ) ;
243
+ probe ! ( mmtk, collection_initialized) ;
244
+ }
245
+
246
+ /// Prepare an MMTk instance for calling the `fork()` system call.
247
+ ///
248
+ /// The `fork()` system call is available on Linux and some UNIX variants, and may be emulated
249
+ /// on other platforms by libraries such as Cygwin. The properties of the `fork()` system call
250
+ /// requires the users to do some preparation before calling it.
251
+ ///
252
+ /// - **Multi-threading**: If `fork()` is called when the process has multiple threads, it
253
+ /// will only duplicate the current thread into the child process, and the child process can
254
+ /// only call async-signal-safe functions, notably `exec()`. For VMs that that use
255
+ /// multi-process concurrency, it is imperative that when calling `fork()`, only one thread may
256
+ /// exist in the process.
257
+ ///
258
+ /// - **File descriptors**: The child process inherits copies of the parent's set of open
259
+ /// file descriptors. This may or may not be desired depending on use cases.
260
+ ///
261
+ /// This function helps VMs that use `fork()` for multi-process concurrency. It instructs all
262
+ /// GC threads to save their contexts and return from their entry-point functions. Currently,
263
+ /// such threads only include GC workers, and the entry point is
264
+ /// [`crate::memory_manager::start_worker`]. A subsequent call to `MMTK::after_fork()` will
265
+ /// re-spawn the threads using their saved contexts. The VM must not allocate objects in the
266
+ /// MMTk heap before calling `MMTK::after_fork()`.
267
+ ///
268
+ /// TODO: Currently, the MMTk core does not keep any files open for a long time. In the
269
+ /// future, this function and the `after_fork` function may be used for handling open file
270
+ /// descriptors across invocations of `fork()`. One possible use case is logging GC activities
271
+ /// and statistics to files, such as performing heap dumps across multiple GCs.
272
+ ///
273
+ /// If a VM intends to execute another program by calling `fork()` and immediately calling
274
+ /// `exec`, it may skip this function because the state of the MMTk instance will be irrelevant
275
+ /// in that case.
276
+ ///
277
+ /// # Caution!
278
+ ///
279
+ /// This function sends an asynchronous message to GC threads and returns immediately, but it
280
+ /// is only safe for the VM to call `fork()` after the underlying **native threads** of the GC
281
+ /// threads have exited. After calling this function, the VM should wait for their underlying
282
+ /// native threads to exit in VM-specific manner before calling `fork()`.
283
+ pub fn prepare_to_fork ( & ' static self ) {
284
+ assert ! (
285
+ self . state. is_initialized( ) ,
286
+ "MMTk collection has not been initialized, yet (was initialize_collection() called before?)"
287
+ ) ;
288
+ probe ! ( mmtk, prepare_to_fork) ;
289
+ self . scheduler . stop_gc_threads_for_forking ( ) ;
290
+ }
291
+
292
+ /// Call this function after the VM called the `fork()` system call.
293
+ ///
294
+ /// This function will re-spawn MMTk threads from saved contexts.
295
+ ///
296
+ /// # Arguments
297
+ ///
298
+ /// * `tls`: The thread that wants to respawn MMTk threads after forking. This value will be
299
+ /// passed back to the VM in `Collection::spawn_gc_thread()` so that the VM knows the
300
+ /// context.
301
+ pub fn after_fork ( & ' static self , tls : VMThread ) {
302
+ assert ! (
303
+ self . state. is_initialized( ) ,
304
+ "MMTk collection has not been initialized, yet (was initialize_collection() called before?)"
305
+ ) ;
306
+ probe ! ( mmtk, after_fork) ;
307
+ self . scheduler . respawn_gc_threads_after_forking ( tls) ;
308
+ }
309
+
223
310
/// Generic hook to allow benchmarks to be harnessed. MMTk will trigger a GC
224
311
/// to clear any residual garbage and start collecting statistics for the benchmark.
225
312
/// This is usually called by the benchmark harness as its last step before the actual benchmark.
@@ -349,6 +436,8 @@ impl<VM: VMBinding> MMTK<VM> {
349
436
self . state
350
437
. internal_triggered_collection
351
438
. store ( true , Ordering :: Relaxed ) ;
439
+ // TODO: The current `GCRequester::request()` is probably incorrect for internally triggered GC.
440
+ // Consider removing functions related to "internal triggered collection".
352
441
self . gc_requester . request ( ) ;
353
442
}
354
443
0 commit comments