[pypy-commit] pypy stm-gc: Start to write support code around the GC for getting at thread-local
arigo
noreply at buildbot.pypy.org
Sun Apr 29 09:24:07 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch: stm-gc
Changeset: r54797:133049a5ba84
Date: 2012-04-29 09:21 +0200
http://bitbucket.org/pypy/pypy/changeset/133049a5ba84/
Log: Start to write support code around the GC for getting at thread-
local data. This, and (by the way) also regular GC pointers in non-
GC prebuilt structs, are not supported yet by the GC; it comes next.
diff --git a/pypy/rpython/memory/gc/stmgc.py b/pypy/rpython/memory/gc/stmgc.py
--- a/pypy/rpython/memory/gc/stmgc.py
+++ b/pypy/rpython/memory/gc/stmgc.py
@@ -86,14 +86,17 @@
# code (see tldict_lookup()).
#
# Invariant: between two transactions, all objects visible from the current
-# thread are always GLOBAL. In particular:
+# thread are always GLOBAL, with the exception of the ones only reachable
+# via thread-local data structures, which remain LOCAL. In particular:
#
-# - The LOCAL object of a thread are not visible at all from other threads.
+# - The LOCAL objects of a thread are not visible at all from other threads.
# This means that in transactional mode there is *no* pointer from a
# GLOBAL object directly to a LOCAL object.
#
# - At the end of enter_transactional_mode(), and at the beginning of
# leave_transactional_mode(), *all* objects everywhere are GLOBAL.
+# (With the possible exception of the thread-local ones from the main
+# thread.)
#
# Collection: for now we have only local_collection(), which ignores all
# GLOBAL objects.
@@ -110,9 +113,11 @@
#
# - A special case is the end-of-transaction collection, done by the same
# local_collection() with a twist: all pointers to a LOCAL COPY object
-# are replaced with copies to the corresponding GLOBAL original. When
-# it is done, we mark all surviving LOCAL objects as GLOBAL too, and we
-# are back to the situation where this thread sees only GLOBAL objects.
+# are replaced with copies to the corresponding GLOBAL original.
+# We additionally mark all surviving LOCAL objects as GLOBAL,
+# unless they are only reachable via thread-locals.
+# Then we are back to the situation where this thread sees only
+# GLOBAL objects (again, with the exception of thread-locals).
# What we leave to the C code to do "as a finishing touch" is to copy
# transactionally the content of the LOCAL COPY objects back over the
# GLOBAL originals; before this is done, the transaction can be aborted
@@ -127,7 +132,7 @@
# - if GCFLAG_WAS_COPIED, it points to the GLOBAL original.
#
# - if GCFLAG_HAS_SHADOW, to the shadow object outside the nursery.
-# (It is not used on any other nursery object.)
+# (It is not used on other nursery objects before collection.)
#
# - it contains the 'next' object of the 'mt_global_turned_local' list.
#
@@ -163,6 +168,7 @@
#needs_write_barrier = "stm"
prebuilt_gc_objects_are_static_roots = False
malloc_zero_filled = True # xxx?
+ handles_thread_locals = True
HDR = lltype.Struct('header', ('tid', lltype.Signed),
('version', llmemory.Address))
diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py
--- a/pypy/rpython/memory/gctransform/framework.py
+++ b/pypy/rpython/memory/gctransform/framework.py
@@ -168,6 +168,7 @@
a_random_address = llmemory.cast_ptr_to_adr(foo)
gcdata.static_root_start = a_random_address # patched in finish()
gcdata.static_root_nongcend = a_random_address # patched in finish()
+ gcdata.static_root_thrlocend = a_random_address # patched in finish()
gcdata.static_root_end = a_random_address # patched in finish()
gcdata.max_type_id = 13 # patched in finish()
gcdata.typeids_z = a_random_address # patched in finish()
@@ -207,6 +208,9 @@
'static_root_nongcend',
annmodel.SomeAddress())
data_classdef.generalize_attr(
+ 'static_root_thrlocend',
+ annmodel.SomeAddress())
+ data_classdef.generalize_attr(
'static_root_end',
annmodel.SomeAddress())
data_classdef.generalize_attr(
@@ -583,9 +587,11 @@
r_gcdata = self.translator.rtyper.getrepr(s_gcdata)
ll_instance = rmodel.inputconst(r_gcdata, self.gcdata).value
+ lb = self.layoutbuilder
addresses_of_static_ptrs = (
- self.layoutbuilder.addresses_of_static_ptrs_in_nongc +
- self.layoutbuilder.addresses_of_static_ptrs)
+ lb.addresses_of_static_ptrs_in_nongc +
+ lb.addresses_of_static_getters_thrloc +
+ lb.addresses_of_static_ptrs)
log.info("found %s static roots" % (len(addresses_of_static_ptrs), ))
ll_static_roots_inside = lltype.malloc(lltype.Array(llmemory.Address),
len(addresses_of_static_ptrs),
@@ -593,9 +599,23 @@
for i in range(len(addresses_of_static_ptrs)):
ll_static_roots_inside[i] = addresses_of_static_ptrs[i]
- ll_instance.inst_static_root_start = llmemory.cast_ptr_to_adr(ll_static_roots_inside) + llmemory.ArrayItemsOffset(lltype.Array(llmemory.Address))
- ll_instance.inst_static_root_nongcend = ll_instance.inst_static_root_start + llmemory.sizeof(llmemory.Address) * len(self.layoutbuilder.addresses_of_static_ptrs_in_nongc)
- ll_instance.inst_static_root_end = ll_instance.inst_static_root_start + llmemory.sizeof(llmemory.Address) * len(addresses_of_static_ptrs)
+
+ ll_instance.inst_static_root_start = (
+ llmemory.cast_ptr_to_adr(ll_static_roots_inside) +
+ llmemory.ArrayItemsOffset(lltype.Array(llmemory.Address)))
+ ll_instance.inst_static_root_nongcend = (
+ ll_instance.inst_static_root_start +
+ sizeofaddr * len(lb.addresses_of_static_ptrs_in_nongc))
+ ll_instance.inst_static_root_thrlocend = (
+ ll_instance.inst_static_root_nongcend +
+ sizeofaddr * len(lb.addresses_of_static_getters_thrloc))
+ ll_instance.inst_static_root_end = (
+ ll_instance.inst_static_root_thrlocend +
+ sizeofaddr * len(lb.addresses_of_static_ptrs))
+ assert ll_instance.inst_static_root_end == (
+ ll_instance.inst_static_root_start +
+ sizeofaddr * len(addresses_of_static_ptrs))
+
newgcdependencies = []
newgcdependencies.append(ll_static_roots_inside)
ll_instance.inst_max_type_id = len(group.members)
@@ -607,6 +627,15 @@
ll_typeids_z[i] = typeids_z[i]
ll_instance.inst_typeids_z = llmemory.cast_ptr_to_adr(ll_typeids_z)
newgcdependencies.append(ll_typeids_z)
+ #
+ if lb.addresses_of_static_getters_thrloc:
+ annhelper = annlowlevel.MixLevelHelperAnnotator(
+ self.translator.rtyper)
+ for getter in lb.addresses_of_static_getters_thrloc:
+ annhelper.getgraph(getter.ptr._obj._callable, [],
+ annmodel.SomeAddress())
+ annhelper.finish()
+ #
return newgcdependencies
def get_finish_tables(self):
@@ -1374,7 +1403,8 @@
def walk_roots(self, collect_stack_root,
collect_static_in_prebuilt_nongc,
- collect_static_in_prebuilt_gc):
+ collect_static_in_prebuilt_gc,
+ collect_static_in_prebuilt_threadlocal=None):
gcdata = self.gcdata
gc = self.gc
if collect_static_in_prebuilt_nongc:
@@ -1385,8 +1415,18 @@
if gc.points_to_valid_gc_object(result):
collect_static_in_prebuilt_nongc(gc, result)
addr += sizeofaddr
+ if collect_static_in_prebuilt_threadlocal:
+ addr = gcdata.static_root_nongcend
+ end = gcdata.static_root_thrlocend
+ while addr != end:
+ fadr = addr.address[0]
+ fptr = llmemory.cast_adr_to_ptr(fadr, gctypelayout.GETTERFN)
+ result = fptr()
+ if gc.points_to_valid_gc_object(result):
+ collect_static_in_prebuilt_threadlocal(gc, result)
+ addr += sizeofaddr
if collect_static_in_prebuilt_gc:
- addr = gcdata.static_root_nongcend
+ addr = gcdata.static_root_thrlocend
end = gcdata.static_root_end
while addr != end:
result = addr.address[0]
diff --git a/pypy/rpython/memory/gctypelayout.py b/pypy/rpython/memory/gctypelayout.py
--- a/pypy/rpython/memory/gctypelayout.py
+++ b/pypy/rpython/memory/gctypelayout.py
@@ -267,9 +267,14 @@
# prebuilt structures. It should list all the locations that could
# possibly point to a GC heap object.
# this lists contains pointers in GcStructs and GcArrays
+ # (note that on some GCs, we don't need this, so it is empty)
self.addresses_of_static_ptrs = []
# this lists contains pointers in raw Structs and Arrays
self.addresses_of_static_ptrs_in_nongc = []
+ # this lists contains addresses of functions that just return
+ # the thread-local address of a GC pointer from a raw Struct
+ # with the 'stm_thread_local' hint.
+ self.addresses_of_static_getters_thrloc = []
# for debugging, the following list collects all the prebuilt
# GcStructs and GcArrays
self.all_prebuilt_gc = []
@@ -425,24 +430,28 @@
adr = llmemory.cast_ptr_to_adr(value._as_ptr())
if TYPE._gckind == "gc":
if gc.prebuilt_gc_objects_are_static_roots or gc.DEBUG:
- appendto = self.addresses_of_static_ptrs
+ append = self.addresses_of_static_ptrs.append
else:
return
elif hasattr(TYPE, "_hints") and TYPE._hints.get('stm_thread_local'):
- # The exception data's value object is skipped: it's a thread-
- # local data structure. We assume that objects are stored
- # only temporarily there, so it is always cleared at the point
- # where we collect the roots.
- if TYPE._name == 'ExcData':
- return
- # Some other thread-local data don't have any GC pointers
- # themselves. These are fine.
- assert list(gc_pointers_inside(value, adr)) == []
- return
+ assert gc.handles_thread_locals
+ def append(a):
+ def getter():
+ return a
+ from pypy.annotation import model as annmodel
+ from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
+ annhelper = MixLevelHelperAnnotator(self.translator.rtyper)
+ fptr = annhelper.delayedfunction(getter, [],
+ annmodel.SomeAddress())
+ annhelper.finish()
+ adr = llmemory.cast_ptr_to_adr(fptr)
+ self.addresses_of_static_getters_thrloc.append(adr)
else:
- appendto = self.addresses_of_static_ptrs_in_nongc
+ append = self.addresses_of_static_ptrs_in_nongc.append
for a in gc_pointers_inside(value, adr, mutable_only=True):
- appendto.append(a)
+ append(a)
+
+GETTERFN = lltype.Ptr(lltype.FuncType([], llmemory.Address))
# ____________________________________________________________
#
More information about the pypy-commit
mailing list