/
boehm.cr
147 lines (118 loc) · 4.29 KB
/
boehm.cr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
@[Link("pthread")]
{% if flag?(:freebsd) %}
@[Link("gc-threaded")]
{% else %}
@[Link("gc")]
{% end %}
lib LibGC
alias Int = LibC::Int
alias SizeT = LibC::SizeT
alias Word = LibC::ULong
fun init = GC_init
fun malloc = GC_malloc(size : SizeT) : Void*
fun malloc_atomic = GC_malloc_atomic(size : SizeT) : Void*
fun realloc = GC_realloc(ptr : Void*, size : SizeT) : Void*
fun free = GC_free(ptr : Void*)
fun collect_a_little = GC_collect_a_little : Int
fun collect = GC_gcollect
fun add_roots = GC_add_roots(low : Void*, high : Void*)
fun enable = GC_enable
fun disable = GC_disable
fun set_handle_fork = GC_set_handle_fork(value : Int)
fun base = GC_base(displaced_pointer : Void*) : Void*
fun general_register_disappearing_link = GC_general_register_disappearing_link(link : Void**, obj : Void*) : Int
type Finalizer = Void*, Void* ->
fun register_finalizer = GC_register_finalizer(obj : Void*, fn : Finalizer, cd : Void*, ofn : Finalizer*, ocd : Void**)
fun register_finalizer_ignore_self = GC_register_finalizer_ignore_self(obj : Void*, fn : Finalizer, cd : Void*, ofn : Finalizer*, ocd : Void**)
fun invoke_finalizers = GC_invoke_finalizers : Int
fun get_heap_usage_safe = GC_get_heap_usage_safe(heap_size : Word*, free_bytes : Word*, unmapped_bytes : Word*, bytes_since_gc : Word*, total_bytes : Word*)
fun set_max_heap_size = GC_set_max_heap_size(Word)
fun get_start_callback = GC_get_start_callback : Void*
fun set_start_callback = GC_set_start_callback(callback : ->)
fun set_push_other_roots = GC_set_push_other_roots(proc : ->)
fun get_push_other_roots = GC_get_push_other_roots : ->
fun push_all_eager = GC_push_all_eager(bottom : Void*, top : Void*)
$stackbottom = GC_stackbottom : Void*
fun set_on_collection_event = GC_set_on_collection_event(cb : ->)
$gc_no = GC_gc_no : LibC::ULong
$bytes_found = GC_bytes_found : LibC::Long
# GC_on_collection_event isn't exported. Can't collect totals without it.
# bytes_allocd, heap_size, unmapped_bytes are macros
fun size = GC_size(addr : Void*) : LibC::SizeT
# Boehm GC requires to use GC_pthread_create and GC_pthread_join instead of pthread_create and pthread_join
fun pthread_create = GC_pthread_create(thread : LibC::PthreadT*, attr : Void*, start : Void* ->, arg : Void*) : LibC::Int
fun pthread_join = GC_pthread_join(thread : LibC::PthreadT, value : Void**) : LibC::Int
fun pthread_detach = GC_pthread_detach(thread : LibC::PthreadT) : LibC::Int
end
# :nodoc:
fun __crystal_malloc(size : UInt32) : Void*
LibGC.malloc(size)
end
# :nodoc:
fun __crystal_malloc_atomic(size : UInt32) : Void*
LibGC.malloc_atomic(size)
end
# :nodoc:
fun __crystal_realloc(ptr : Void*, size : UInt32) : Void*
LibGC.realloc(ptr, size)
end
module GC
def self.init
LibGC.set_handle_fork(1)
LibGC.init
end
def self.collect
LibGC.collect
end
def self.enable
LibGC.enable
end
def self.disable
LibGC.disable
end
def self.free(pointer : Void*)
LibGC.free(pointer)
end
def self.add_finalizer(object : Reference)
add_finalizer_impl(object)
end
def self.add_finalizer(object)
# Nothing
end
private def self.add_finalizer_impl(object : T) forall T
LibGC.register_finalizer_ignore_self(object.as(Void*),
->(obj, data) { obj.as(T).finalize },
nil, nil, nil)
nil
end
def self.add_root(object : Reference)
roots = @@roots ||= [] of Pointer(Void)
roots << Pointer(Void).new(object.object_id)
end
def self.register_disappearing_link(pointer : Void**)
base = LibGC.base(pointer.value)
LibGC.general_register_disappearing_link(pointer, base)
end
record Stats,
# collections : LibC::ULong,
# bytes_found : LibC::Long,
heap_size : LibC::ULong,
free_bytes : LibC::ULong,
unmapped_bytes : LibC::ULong,
bytes_since_gc : LibC::ULong,
total_bytes : LibC::ULong
def self.stats
LibGC.get_heap_usage_safe(out heap_size, out free_bytes, out unmapped_bytes, out bytes_since_gc, out total_bytes)
# collections = LibGC.gc_no - 1
# bytes_found = LibGC.bytes_found
Stats.new(
# collections: collections,
# bytes_found: bytes_found,
heap_size: heap_size,
free_bytes: free_bytes,
unmapped_bytes: unmapped_bytes,
bytes_since_gc: bytes_since_gc,
total_bytes: total_bytes
)
end
end