@@ -12,24 +12,37 @@ import (
12
12
// AddCleanup attaches a cleanup function to ptr. Some time after ptr is no longer
13
13
// reachable, the runtime will call cleanup(arg) in a separate goroutine.
14
14
//
15
- // If ptr is reachable from cleanup or arg, ptr will never be collected
16
- // and the cleanup will never run. AddCleanup panics if arg is equal to ptr.
15
+ // A typical use is that ptr is an object wrapping an underlying resource (e.g.,
16
+ // a File object wrapping an OS file descriptor), arg is the underlying resource
17
+ // (e.g., the OS file descriptor), and the cleanup function releases the underlying
18
+ // resource (e.g., by calling the close system call).
17
19
//
18
- // The cleanup(arg) call is not always guaranteed to run; in particular it is not
19
- // guaranteed to run before program exit.
20
+ // There are few constraints on ptr. In particular, multiple cleanups may be
21
+ // attached to the same pointer, or to different pointers within the same
22
+ // allocation.
20
23
//
21
- // Cleanups are not guaranteed to run if the size of T is zero bytes, because
22
- // it may share same address with other zero-size objects in memory. See
23
- // https://go.dev/ref/spec#Size_and_alignment_guarantees .
24
+ // If ptr is reachable from cleanup or arg, ptr will never be collected
25
+ // and the cleanup will never run. As a protection against simple cases of this,
26
+ // AddCleanup panics if arg is equal to ptr .
24
27
//
25
28
// There is no specified order in which cleanups will run.
29
+ // In particular, if several objects point to each other and all become
30
+ // unreachable at the same time, their cleanups all become eligible to run
31
+ // and can run in any order. This is true even if the objects form a cycle.
26
32
//
27
33
// A single goroutine runs all cleanup calls for a program, sequentially. If a
28
34
// cleanup function must run for a long time, it should create a new goroutine.
29
35
//
30
36
// If ptr has both a cleanup and a finalizer, the cleanup will only run once
31
37
// it has been finalized and becomes unreachable without an associated finalizer.
32
38
//
39
+ // The cleanup(arg) call is not always guaranteed to run; in particular it is not
40
+ // guaranteed to run before program exit.
41
+ //
42
+ // Cleanups are not guaranteed to run if the size of T is zero bytes, because
43
+ // it may share same address with other zero-size objects in memory. See
44
+ // https://go.dev/ref/spec#Size_and_alignment_guarantees.
45
+ //
33
46
// It is not guaranteed that a cleanup will run for objects allocated
34
47
// in initializers for package-level variables. Such objects may be
35
48
// linker-allocated, not heap-allocated.
@@ -41,6 +54,16 @@ import (
41
54
// allocation may never run if it always exists in the same batch as a
42
55
// referenced object. Typically, this batching only happens for tiny
43
56
// (on the order of 16 bytes or less) and pointer-free objects.
57
+ //
58
+ // A cleanup may run as soon as an object becomes unreachable.
59
+ // In order to use cleanups correctly, the program must ensure that
60
+ // the object is reachable until it is safe to run its cleanup.
61
+ // Objects stored in global variables, or that can be found by tracing
62
+ // pointers from a global variable, are reachable. A function argument or
63
+ // receiver may become unreachable at the last point where the function
64
+ // mentions it. To ensure a cleanup does not get called prematurely,
65
+ // pass the object to the [KeepAlive] function after the last point
66
+ // where the object must remain reachable.
44
67
func AddCleanup [T , S any ](ptr * T , cleanup func (S ), arg S ) Cleanup {
45
68
// Explicitly force ptr to escape to the heap.
46
69
ptr = abi .Escape (ptr )
0 commit comments