[pypy-commit] pypy stm-gc: Complete the tests and the code.
arigo
noreply at buildbot.pypy.org
Mon Apr 23 21:11:09 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch: stm-gc
Changeset: r54692:3e6d963c1ab2
Date: 2012-04-23 15:16 +0200
http://bitbucket.org/pypy/pypy/changeset/3e6d963c1ab2/
Log: Complete the tests and the code.
diff --git a/pypy/rpython/memory/gc/stmtls.py b/pypy/rpython/memory/gc/stmtls.py
--- a/pypy/rpython/memory/gc/stmtls.py
+++ b/pypy/rpython/memory/gc/stmtls.py
@@ -47,6 +47,10 @@
# --- the LOCAL objects which are weakrefs. They are also listed
# in the appropriate place, like sharedarea_tls, if needed.
self.local_weakrefs = self.AddressStack()
+ # --- main thread only: this is the list of GLOBAL objects that
+ # have been turned into LOCAL objects
+ if in_main_thread:
+ self.main_thread_was_global_objects = NULL
#
self._register_with_C_code()
@@ -105,6 +109,16 @@
"""Called on the main thread, just before spawning the other
threads."""
self.stop_transaction()
+ #
+ # We must also mark the following objects as GLOBAL again
+ obj = self.main_thread_was_global_objects
+ self.main_thread_was_global_objects = NULL
+ while obj:
+ hdr = self.gc.header(obj)
+ hdr.tid |= GCFLAG_GLOBAL
+ obj = hdr.version
+ if not we_are_translated():
+ del self.main_thread_was_global_objects # don't use any more
def leave_transactional_mode(self):
"""Restart using the main thread for mallocs."""
@@ -113,11 +127,16 @@
if value is not self:
del StmGCTLS.nontranslated_dict[key]
self.start_transaction()
- # do something special here after we restarted the "transaction"
- # in the main thread: we have to make sure that the write_barrier
- # calls done in the main thread before enter/leave_transactional_mode
- # are still pointing to local objects. Conservatively, we mark as
- # local all objects directly referenced from the stack.
+ #
+ # Do something special here after we restarted the "transaction"
+ # in the main thread. At this point, *all* objects are GLOBAL.
+ # The write_barrier will ensure that any write makes the written-to
+ # objects LOCAL again. However, it is possible that the write
+ # barrier was called before the enter/leave_transactional_mode()
+ # and will not be called again before writing. But such objects
+ # are right now directly in the stack. So to fix this issue, we
+ # conservatively mark as local all objects directly from the stack.
+ self.main_thread_was_global_objects = NULL
self.gc.root_walker.walk_current_stack_roots(
StmGCTLS._remark_object_as_local, self)
@@ -195,6 +214,8 @@
# objects.
if not self.in_main_thread:
self.collect_roots_from_tldict()
+ else:
+ self.collect_from_main_thread_was_global_objects()
#
# Now repeatedly follow objects until 'pending' is empty.
self.collect_flush_pending()
@@ -264,14 +285,19 @@
self.local_weakrefs.append(obj)
def _remark_object_as_local(self, root):
- self.main_thread_writes_to_global_obj(root.address[0])
+ obj = root.address[0]
+ hdr = self.gc.header(obj)
+ if hdr.tid & GCFLAG_GLOBAL:
+ self.main_thread_writes_to_global_obj(obj)
def main_thread_writes_to_global_obj(self, obj):
hdr = self.gc.header(obj)
ll_assert(hdr.tid & GCFLAG_WAS_COPIED == 0,
"write in main thread: unexpected GCFLAG_WAS_COPIED")
hdr.tid &= ~GCFLAG_GLOBAL
- self.sharedarea_tls.add_regular(obj)
+ # add the object into this linked list
+ hdr.version = self.main_thread_was_global_objects
+ self.main_thread_was_global_objects = obj
# ------------------------------------------------------------
@@ -474,6 +500,19 @@
#
self.trace_and_drag_out_of_nursery(localobj)
+ def collect_from_main_thread_was_global_objects(self):
+ # NB. all objects in the 'main_thread_was_global_objects' list are
+ # currently immortal (because they were once GLOBAL)
+ obj = self.main_thread_was_global_objects
+ while obj:
+ hdr = self.gc.header(obj)
+ ll_assert(hdr.tid & GCFLAG_GLOBAL == 0,
+ "unexpected GLOBAL in main_thread_was_global_objects")
+ if hdr.tid & GCFLAG_VISITED == 0:
+ hdr.tid |= GCFLAG_VISITED
+ self.pending.append(obj)
+ obj = hdr.version
+
def collect_flush_pending(self):
# Follow the objects in the 'pending' stack and move the
# young objects they point to out of the nursery.
diff --git a/pypy/rpython/memory/gc/test/test_stmgc.py b/pypy/rpython/memory/gc/test/test_stmgc.py
--- a/pypy/rpython/memory/gc/test/test_stmgc.py
+++ b/pypy/rpython/memory/gc/test/test_stmgc.py
@@ -342,23 +342,56 @@
from pypy.rpython.memory.gc.test import test_stmtls
self.gc.root_walker = test_stmtls.FakeRootWalker()
#
- tr1, tr1_adr = self.malloc(SR, globl=True)
+ tr1, tr1_adr = self.malloc(SR, globl=True) # three prebuilt objects
tr2, tr2_adr = self.malloc(SR, globl=True)
+ tr3, tr3_adr = self.malloc(SR, globl=True)
tr1.sr2 = tr2
self.gc.root_walker.current_stack = [tr1]
obj = self.gc.stm_writebarrier(tr1_adr)
assert obj == tr1_adr
obj = self.gc.stm_writebarrier(tr2_adr)
assert obj == tr2_adr
+ obj = self.gc.stm_writebarrier(tr3_adr)
+ assert obj == tr3_adr
self.checkflags(tr1_adr, False, False) # tr1 has become local
self.checkflags(tr2_adr, False, False) # tr2 has become local
+ self.checkflags(tr3_adr, False, False) # tr3 has become local
#
self.gc.enter_transactional_mode()
self.gc.leave_transactional_mode()
self.checkflags(tr2_adr, True, False) # tr2 has become global again
+ self.checkflags(tr3_adr, True, False) # tr3 has become global again
# but tr1 is still local, because it is directly referenced from stack
self.checkflags(tr1_adr, False, False)
+ def test_non_prebuilt_relocalize_after_transactional_mode(self):
+ from pypy.rpython.memory.gc.test import test_stmtls
+ self.gc.root_walker = test_stmtls.FakeRootWalker()
+ #
+ tr1, tr1_adr = self.malloc(SR) # local
+ tr2, tr2_adr = self.malloc(SR) # local
+ tr1.sr2 = tr2
+ self.gc.root_walker.current_stack = [tr1]
+ self.gc.enter_transactional_mode()
+ self.checkflags(tr1_adr, True, False) # tr1 has become global
+ self.checkflags(tr2_adr, True, False) # tr2 has become global
+ self.gc.leave_transactional_mode()
+ self.checkflags(tr2_adr, True, False) # tr2 is still global
+ self.checkflags(tr1_adr, False, False) # tr1 is back to a local
+
+ def test_collect_from_main_thread_was_global_objects(self):
+ tr1, tr1_adr = self.malloc(SR, globl=True) # a global prebuilt object
+ tr2, tr2_adr = self.malloc(SR, globl=False) # tr2 is a local
+ self.checkflags(tr2_adr, False, False) # check that tr2 is a local
+ obj = self.gc.stm_writebarrier(tr1_adr)
+ assert obj == tr1_adr # tr1 is now local
+ tr1.sr2 = tr2
+ self.gc.collect(0)
+ tr2 = tr1.sr2 # reload, because it moved
+ tr2_adr = llmemory.cast_ptr_to_adr(tr2)
+ self.checkflags(tr2_adr, False, False) # tr2 is still alive and local
+ self.checkflags(tr1_adr, False, False) # tr1 is still local
+
def test_commit_transaction_empty(self):
self.select_thread(1)
s, s_adr = self.malloc(S)
More information about the pypy-commit
mailing list