Author: Armin Rigo <ar...@tunes.org> Branch: stm-gc Changeset: r54419:53a337586265 Date: 2012-04-16 15:43 +0200 http://bitbucket.org/pypy/pypy/changeset/53a337586265/
Log: Some progress, fixing test_rstm. diff --git a/pypy/module/transaction/interp_transaction.py b/pypy/module/transaction/interp_transaction.py --- a/pypy/module/transaction/interp_transaction.py +++ b/pypy/module/transaction/interp_transaction.py @@ -220,8 +220,8 @@ """The main function running one of the threads.""" # Note that we cannot allocate any object here outside a transaction, # so we need to be very careful. + rstm.descriptor_init() state.lock() - rstm.descriptor_init() # rstm.perform_transaction(_setup_thread, AbstractPending, None) my_transactions_pending = state.getvalue()._transaction_pending @@ -260,10 +260,10 @@ state.lock() _add_list(my_transactions_pending) # - rstm.descriptor_done() if state.num_waiting_threads == 0: # only the last thread to leave state.unlock_unfinished() state.unlock() + rstm.descriptor_done() @rgc.no_collect diff --git a/pypy/rlib/test/test_rstm.py b/pypy/rlib/test/test_rstm.py --- a/pypy/rlib/test/test_rstm.py +++ b/pypy/rlib/test/test_rstm.py @@ -1,12 +1,14 @@ import os, thread, time -from pypy.rlib.debug import debug_print, ll_assert +from pypy.rlib.debug import debug_print, ll_assert, fatalerror from pypy.rlib import rstm +from pypy.rpython.annlowlevel import llhelper from pypy.translator.stm.test.support import CompiledSTMTests +from pypy.module.thread import ll_thread class Arg(object): pass -arg = Arg() +arg_list = [Arg() for i in range(10)] def setx(arg, retry_counter): debug_print(arg.x) @@ -17,22 +19,29 @@ assert rstm._debug_get_state() == 2 arg.x = 42 -def stm_perform_transaction(initial_x=202): - arg.x = initial_x +def stm_perform_transaction(done=None, i=0): ll_assert(rstm._debug_get_state() == -2, "bad debug_get_state (1)") rstm.descriptor_init() + arg = arg_list[i] + if done is None: + arg.x = 202 + else: + arg.x = done.initial_x ll_assert(rstm._debug_get_state() == 0, "bad debug_get_state (2)") rstm.perform_transaction(setx, Arg, arg) ll_assert(rstm._debug_get_state() == 0, "bad debug_get_state (3)") + ll_assert(arg.x == 42, "bad arg.x") + if done is not None: + ll_thread.release_NOAUTO(done.finished_lock) rstm.descriptor_done() ll_assert(rstm._debug_get_state() == -2, "bad debug_get_state (4)") - ll_assert(arg.x == 42, "bad arg.x") def test_stm_multiple_threads(): ok = [] def f(i): - stm_perform_transaction() + stm_perform_transaction(i=i) ok.append(i) + rstm.enter_transactional_mode() for i in range(10): thread.start_new_thread(f, (i,)) timeout = 10 @@ -40,6 +49,7 @@ time.sleep(0.1) timeout -= 0.1 assert timeout >= 0.0, "timeout!" + rstm.leave_transactional_mode() assert sorted(ok) == range(10) @@ -58,22 +68,23 @@ assert '102' in dataerr.splitlines() def build_perform_transaction(self): - from pypy.module.thread import ll_thread class Done: done = False done = Done() def g(): - stm_perform_transaction(done.initial_x) - done.done = True + stm_perform_transaction(done) def f(argv): done.initial_x = int(argv[1]) assert rstm._debug_get_state() == -1 # main thread - ll_thread.start_new_thread(g, ()) - for i in range(20): - if done.done: break - time.sleep(0.1) - else: - print "timeout!" - raise Exception + done.finished_lock = ll_thread.allocate_ll_lock() + ll_thread.acquire_NOAUTO(done.finished_lock, True) + # + rstm.enter_transactional_mode() + # + llcallback = llhelper(ll_thread.CALLBACK, g) + ident = ll_thread.c_thread_start_NOGIL(llcallback) + ll_thread.acquire_NOAUTO(done.finished_lock, True) + # + rstm.leave_transactional_mode() return 0 t, cbuilder = self.compile(f) return cbuilder diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py --- a/pypy/rpython/lltypesystem/lloperation.py +++ b/pypy/rpython/lltypesystem/lloperation.py @@ -403,8 +403,8 @@ 'stm_become_inevitable': LLOp(), 'stm_descriptor_init': LLOp(canrun=True), 'stm_descriptor_done': LLOp(canrun=True), - 'stm_enter_transactional_mode': LLOp(), - 'stm_leave_transactional_mode': LLOp(), + 'stm_enter_transactional_mode': LLOp(canrun=True), + 'stm_leave_transactional_mode': LLOp(canrun=True), 'stm_writebarrier': LLOp(sideeffects=False), 'stm_normalize_global': LLOp(), 'stm_start_transaction': LLOp(canrun=True), diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py --- a/pypy/rpython/lltypesystem/opimpl.py +++ b/pypy/rpython/lltypesystem/opimpl.py @@ -630,6 +630,12 @@ def op_stm_commit_transaction(): pass +def op_stm_enter_transactional_mode(): + pass + +def op_stm_leave_transactional_mode(): + pass + # ____________________________________________________________ def get_op_impl(opname): 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 @@ -240,8 +240,7 @@ self.get_tls().start_transaction() def commit_transaction(self): - raise NotImplementedError - self.collector.commit_transaction() + self.get_tls().stop_transaction() @always_inline @@ -317,6 +316,11 @@ # @dont_inline def _stm_write_barrier_global(obj): + tls = self.get_tls() + if not tls.in_transaction(): + return obj # not in transaction: only when running the code + # in _run_thread(), i.e. in sub-threads outside + # transactions. xxx statically detect this case? # we need to find or make a local copy hdr = self.header(obj) if hdr.tid & GCFLAG_WAS_COPIED == 0: @@ -339,7 +343,6 @@ # Here, we need to really make a local copy size = self.get_size(obj) totalsize = self.gcheaderbuilder.size_gc_header + size - tls = self.get_tls() try: localobj = tls.malloc_local_copy(totalsize) except MemoryError: @@ -453,230 +456,3 @@ def identityhash(self, gcobj): return self.id_or_identityhash(gcobj, True) - -# ------------------------------------------------------------ - - -class Collector(object): - """A separate frozen class. Useful to prevent any buggy concurrent - access to GC data. The methods here use the GCTLS instead for - storing things in a thread-local way.""" - - def __init__(self, gc): - self.gc = gc - self.stm_operations = gc.stm_operations - - def _freeze_(self): - return True - - def is_in_nursery(self, tls, addr): - ll_assert(llmemory.cast_adr_to_int(addr) & 1 == 0, - "odd-valued (i.e. tagged) pointer unexpected here") - return tls.nursery_start <= addr < tls.nursery_top - - def header(self, obj): - return self.gc.header(obj) - - - def start_transaction(self): - """Start a transaction, by clearing and resetting the tls nursery.""" - tls = self.get_tls() - self.gc.reset_nursery(tls) - - - def commit_transaction(self): - """End of a transaction, just before its end. No more GC - operations should occur afterwards! Note that the C code that - does the commit runs afterwards, and may still abort.""" - # - debug_start("gc-collect-commit") - # - tls = self.get_tls() - # - # Do a mark-and-move minor collection out of the tls' nursery - # into the main thread's global area (which is right now also - # called a nursery). - debug_print("local arena:", tls.nursery_free - tls.nursery_start, - "bytes") - # - # We are starting from the tldict's local objects as roots. At - # this point, these objects have GCFLAG_WAS_COPIED, and the other - # local objects don't. We want to move all reachable local objects - # to the global area. - # - # Start from tracing the root objects - self.collect_roots_from_tldict(tls) - # - # Continue iteratively until we have reached all the reachable - # local objects - self.collect_from_pending_list(tls) - # - # Fix up the weakrefs that used to point to local objects - self.fixup_weakrefs(tls) - # - # Now, all indirectly reachable local objects have been copied into - # the global area, and all pointers have been fixed to point to the - # global copies, including in the local copy of the roots. What - # remains is only overwriting of the global copy of the roots. - # This is done by the C code. - debug_stop("gc-collect-commit") - - - def collect_roots_from_tldict(self, tls): - tls.pending_list = NULL - tls.surviving_weakrefs = NULL - # Enumerate the roots, which are the local copies of global objects. - # For each root, trace it. - CALLBACK = self.stm_operations.CALLBACK_ENUM - callback = llhelper(CALLBACK, self._enum_entries) - # xxx hack hack hack! Stores 'self' in a global place... but it's - # pointless after translation because 'self' is a Void. - _global_collector.collector = self - self.stm_operations.tldict_enum(callback) - - - @staticmethod - def _enum_entries(tls_addr, globalobj, localobj): - self = _global_collector.collector - tls = llmemory.cast_adr_to_ptr(tls_addr, lltype.Ptr(StmGC.GCTLS)) - # - localhdr = self.header(localobj) - ll_assert(localhdr.version == globalobj, - "in a root: localobj.version != globalobj") - ll_assert(localhdr.tid & GCFLAG_GLOBAL == 0, - "in a root: unexpected GCFLAG_GLOBAL") - ll_assert(localhdr.tid & GCFLAG_WAS_COPIED != 0, - "in a root: missing GCFLAG_WAS_COPIED") - # - self.trace_and_drag_out_of_nursery(tls, localobj) - - - def collect_from_pending_list(self, tls): - while tls.pending_list != NULL: - pending_obj = tls.pending_list - pending_hdr = self.header(pending_obj) - # - # 'pending_list' is a chained list of fresh global objects, - # linked together via their 'version' field. The 'version' - # must be replaced with NULL after we pop the object from - # the linked list. - tls.pending_list = pending_hdr.version - pending_hdr.version = NULL - # - # Check the flags of pending_obj: it should be a fresh global - # object, without GCFLAG_WAS_COPIED - ll_assert(pending_hdr.tid & GCFLAG_GLOBAL != 0, - "from pending list: missing GCFLAG_GLOBAL") - ll_assert(pending_hdr.tid & GCFLAG_WAS_COPIED == 0, - "from pending list: unexpected GCFLAG_WAS_COPIED") - # - self.trace_and_drag_out_of_nursery(tls, pending_obj) - - - def trace_and_drag_out_of_nursery(self, tls, obj): - # This is called to fix the references inside 'obj', to ensure that - # they are global. If necessary, the referenced objects are copied - # into the global area first. This is called on the *local* copy of - # the roots, and on the fresh *global* copy of all other reached - # objects. - self.gc.trace(obj, self._trace_drag_out, tls) - - def _trace_drag_out(self, root, tls): - obj = root.address[0] - hdr = self.header(obj) - # - # Figure out if the object is GLOBAL or not by looking at its - # address, not at its header --- to avoid cache misses and - # pollution for all global objects - if not self.is_in_nursery(tls, obj): - ll_assert(hdr.tid & GCFLAG_GLOBAL != 0, - "trace_and_mark: non-GLOBAL obj is not in nursery") - return # ignore global objects - # - ll_assert(hdr.tid & GCFLAG_GLOBAL == 0, - "trace_and_mark: GLOBAL obj in nursery") - # - if hdr.tid & (GCFLAG_WAS_COPIED | GCFLAG_HAS_SHADOW) == 0: - # First visit to a local-only 'obj': allocate a corresponding - # global object - size = self.gc.get_size(obj) - globalobj = self.gc._malloc_global_raw(tls, size) - need_to_copy = True - # - else: - globalobj = hdr.version - if hdr.tid & GCFLAG_WAS_COPIED != 0: - # this local object is a root or was already marked. Either - # way, its 'version' field should point to the corresponding - # global object. - size = 0 - need_to_copy = False - else: - # this local object has a shadow made by id_or_identityhash(); - # and the 'version' field points to the global shadow. - ll_assert(hdr.tid & GCFLAG_HAS_SHADOW != 0, "uh?") - size = self.gc.get_size(obj) - need_to_copy = True - # - if need_to_copy: - # Copy the data of the object from the local to the global - llmemory.raw_memcopy(obj, globalobj, size) - # - # Initialize the header of the 'globalobj' - globalhdr = self.header(globalobj) - globalhdr.tid = hdr.tid | GCFLAG_GLOBAL - # - # Add the flags to 'localobj' to say 'has been copied now' - hdr.tid |= GCFLAG_WAS_COPIED - hdr.version = globalobj - # - # Set a temporary linked list through the globalobj's version - # numbers. This is normally not allowed, but it works here - # because these new globalobjs are not visible to any other - # thread before the commit is really complete. - globalhdr.version = tls.pending_list - tls.pending_list = globalobj - # - if hdr.tid & GCFLAG_WEAKREF != 0: - # this was a weakref object that survives. - self.young_weakref_survives(tls, obj) - # - # Fix the original root.address[0] to point to the globalobj - root.address[0] = globalobj - - - @dont_inline - def young_weakref_survives(self, tls, obj): - # Relink it in the tls.surviving_weakrefs chained list, - # via the weakpointer_offset in the local copy of the object. - # Do it only if the weakref points to a local object. - offset = self.gc.weakpointer_offset(self.gc.get_type_id(obj)) - if self.is_in_nursery(tls, (obj + offset).address[0]): - (obj + offset).address[0] = tls.surviving_weakrefs - tls.surviving_weakrefs = obj - - def fixup_weakrefs(self, tls): - obj = tls.surviving_weakrefs - while obj: - offset = self.gc.weakpointer_offset(self.gc.get_type_id(obj)) - # - hdr = self.header(obj) - ll_assert(hdr.tid & GCFLAG_GLOBAL == 0, - "weakref: unexpectedly global") - globalobj = hdr.version - obj2 = (globalobj + offset).address[0] - hdr2 = self.header(obj2) - ll_assert(hdr2.tid & GCFLAG_GLOBAL == 0, - "weakref: points to a global") - if hdr2.tid & GCFLAG_WAS_COPIED: - obj2g = hdr2.version # obj2 survives, going there - else: - obj2g = llmemory.NULL # obj2 dies - (globalobj + offset).address[0] = obj2g - # - obj = (obj + offset).address[0] - - -class _GlobalCollector(object): - pass -_global_collector = _GlobalCollector() 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 @@ -1,13 +1,15 @@ from pypy.rpython.lltypesystem import lltype, llmemory, llarena, rffi -from pypy.rpython.annlowlevel import cast_instance_to_base_ptr +from pypy.rpython.annlowlevel import cast_instance_to_base_ptr, llhelper from pypy.rpython.annlowlevel import cast_base_ptr_to_instance, base_ptr_lltype from pypy.rlib.objectmodel import we_are_translated, free_non_gc_object +from pypy.rlib.objectmodel import specialize from pypy.rlib.rarithmetic import r_uint from pypy.rlib.debug import ll_assert, debug_start, debug_stop, fatalerror from pypy.rpython.memory.gc.stmgc import WORD, NULL from pypy.rpython.memory.gc.stmgc import always_inline, dont_inline from pypy.rpython.memory.gc.stmgc import GCFLAG_GLOBAL, GCFLAG_VISITED +from pypy.rpython.memory.gc.stmgc import GCFLAG_WAS_COPIED class StmGCTLS(object): @@ -101,11 +103,8 @@ def enter_transactional_mode(self): """Called on the main thread, just before spawning the other threads.""" - self.local_collection() - if not self.local_nursery_is_empty(): - self.local_collection(run_finalizers=False) - self._promote_locals_to_globals() - self._disable_mallocs() + self.stop_transaction() + self.stm_operations.enter_transactional_mode() def leave_transactional_mode(self): """Restart using the main thread for mallocs.""" @@ -113,10 +112,11 @@ for key, value in StmGCTLS.nontranslated_dict.items(): if value is not self: del StmGCTLS.nontranslated_dict[key] + self.stm_operations.leave_transactional_mode() self.start_transaction() def start_transaction(self): - """Enter a thread: performs any pending cleanups, and set + """Start a transaction: performs any pending cleanups, and set up a fresh state for allocating. Called at the start of each transaction, and at the start of the main thread.""" # Note that the calls to enter() and @@ -134,11 +134,24 @@ self.nursery_free = self.nursery_start self.nursery_top = self.nursery_start + self.nursery_size + def stop_transaction(self): + """Stop a transaction: do a local collection to empty the + nursery and track which objects are still alive now, and + then mark all these objects as global.""" + self.local_collection() + if not self.local_nursery_is_empty(): + self.local_collection(run_finalizers=False) + self._promote_locals_to_globals() + self._disable_mallocs() + def local_nursery_is_empty(self): ll_assert(bool(self.nursery_free), "local_nursery_is_empty: gc not running") return self.nursery_free == self.nursery_start + def in_transaction(self): + return bool(self.nursery_free) + # ------------------------------------------------------------ def local_collection(self, run_finalizers=True): @@ -192,18 +205,6 @@ # debug_stop("gc-local") - def end_of_transaction_collection(self): - """Do an end-of-transaction collection. Finds all surviving - non-GCFLAG_WAS_COPIED young objects and make them old. Assumes - that there are no roots from the stack. This guarantees that the - nursery will end up empty, apart from GCFLAG_WAS_COPIED objects. - To finish the commit, the C code will need to copy them over the - global objects (or abort in case of conflict, which is still ok). - - No more mallocs are allowed after this is called. - """ - raise NotImplementedError - # ------------------------------------------------------------ @always_inline @@ -245,8 +246,6 @@ def _promote_locals_to_globals(self): ll_assert(self.local_nursery_is_empty(), "nursery must be empty [1]") - ll_assert(not self.sharedarea_tls.special_stack.non_empty(), - "special_stack should be empty here [1]") # # Promote all objects in sharedarea_tls to global obj = self.sharedarea_tls.chained_list @@ -272,18 +271,31 @@ self.gc.root_walker.walk_current_stack_roots( StmGCTLS._trace_drag_out1, self) + def trace_and_drag_out_of_nursery(self, obj): + # This is called to fix the references inside 'obj', to ensure that + # they are global. If necessary, the referenced objects are copied + # into the global area first. This is called on the LOCAL copy of + # the roots, and on the freshly OLD copy of all other reached LOCAL + # objects. + self.gc.trace(obj, self._trace_drag_out, None) + def _trace_drag_out1(self, root): self._trace_drag_out(root, None) def _trace_drag_out(self, root, ignored): """Trace callback: 'root' is the address of some pointer. If that pointer points to a YOUNG object, allocate an OLD copy of it and - fix the pointer. Also, add the object to 'pending_list', if it was - not done so far. + fix the pointer. Also, add the object to the 'pending' stack, if + it was not done so far. """ obj = root.address[0] hdr = self.gc.header(obj) # + # If 'obj' is a LOCAL copy of a GLOBAL object, skip it + # (this case is handled differently in collect_roots_from_tldict) + if hdr.tid & GCFLAG_WAS_COPIED: + return + # # If 'obj' is not in the nursery, we set GCFLAG_VISITED if not self.is_in_nursery(obj): if hdr.tid & GCFLAG_VISITED == 0: @@ -335,14 +347,32 @@ self.sharedarea_tls.add_regular(obj) def collect_roots_from_tldict(self): - pass # XXX + if not we_are_translated(): + if not hasattr(self.stm_operations, 'tldict_enum'): + return + CALLBACK = self.stm_operations.CALLBACK_ENUM + callback = llhelper(CALLBACK, StmGCTLS._enum_entries) + self.stm_operations.tldict_enum(callback) + + @staticmethod + def _enum_entries(tlsaddr, globalobj, localobj): + self = StmGCTLS.cast_address_to_tls_object(tlsaddr) + localhdr = self.gc.header(localobj) + ll_assert(localhdr.version == globalobj, + "in a root: localobj.version != globalobj") + ll_assert(localhdr.tid & GCFLAG_GLOBAL == 0, + "in a root: unexpected GCFLAG_GLOBAL") + ll_assert(localhdr.tid & GCFLAG_WAS_COPIED != 0, + "in a root: missing GCFLAG_WAS_COPIED") + # + self.trace_and_drag_out_of_nursery(localobj) def collect_flush_pending(self): # Follow the objects in the 'pending' stack and move the # young objects they point to out of the nursery. while self.pending.non_empty(): obj = self.pending.pop() - self.gc.trace(obj, self._trace_drag_out, None) + self.trace_and_drag_out_of_nursery(obj) self.pending.delete() def mass_free_old_local(self, previous_sharedarea_tls): diff --git a/pypy/rpython/memory/gctransform/stmframework.py b/pypy/rpython/memory/gctransform/stmframework.py --- a/pypy/rpython/memory/gctransform/stmframework.py +++ b/pypy/rpython/memory/gctransform/stmframework.py @@ -57,6 +57,14 @@ def gct_stm_descriptor_done(self, hop): hop.genop("direct_call", [self.teardown_thread_ptr, self.c_const_gc]) + def gct_stm_enter_transactional_mode(self, hop): + hop.genop("direct_call", [self.stm_enter_transactional_mode_ptr, + self.c_const_gc]) + + def gct_stm_leave_transactional_mode(self, hop): + hop.genop("direct_call", [self.stm_leave_transactional_mode_ptr, + self.c_const_gc]) + def gct_stm_writebarrier(self, hop): op = hop.spaceop v_adr = hop.genop('cast_ptr_to_adr', diff --git a/pypy/translator/stm/src_stm/et.c b/pypy/translator/stm/src_stm/et.c --- a/pypy/translator/stm/src_stm/et.c +++ b/pypy/translator/stm/src_stm/et.c @@ -143,26 +143,18 @@ { owner_version_t newver = d->end_time; wlog_t *item; - /* loop in "forward" order: in this order, if there are duplicate orecs - then only the last one has p != -1. */ REDOLOG_LOOP_FORWARD(d->redolog, item) { void *globalobj = item->addr; void *localobj = item->val; - owner_version_t p = item->p; long size = rpython_get_size(localobj); memcpy(((char *)globalobj) + sizeof(orec_t), ((char *)localobj) + sizeof(orec_t), size - sizeof(orec_t)); - /* but we must only unlock the orec if it's the last time it - appears in the redolog list. If it's not, then p == -1. - XXX I think that duplicate orecs are not possible any more. */ - if (p != -1) - { - volatile orec_t* o = get_orec(globalobj); - CFENCE; - o->version = newver; - } + /* unlock the orec */ + volatile orec_t* o = get_orec(globalobj); + CFENCE; + o->version = newver; } REDOLOG_LOOP_END; } @@ -186,12 +178,10 @@ wlog_t *item; REDOLOG_LOOP_FORWARD(d->redolog, item) { - if (item->p != -1) - { - volatile orec_t* o = get_orec(item->addr); - o->version = item->p; - item->p = -1; - } + volatile orec_t* o = get_orec(item->addr); + assert(item->p != -1); + o->version = item->p; + item->p = -1; } REDOLOG_LOOP_END; } @@ -218,14 +208,14 @@ if (!bool_cas(&o->version, ovt, d->my_lock_word)) goto retry; // save old version to item->p. Now we hold the lock. - // in case of duplicate orecs, only the last one has p != -1. item->p = ovt; } // else if the location is too recent... else if (!IS_LOCKED(ovt)) tx_abort(0); - // else it is locked: if we don't hold the lock... - else if (ovt != d->my_lock_word) { + // else it is locked: check it's not by me + else { + assert(ovt != d->my_lock_word); // we can either abort or spinloop. Because we are at the end of // the transaction we might try to spinloop, even though after the // lock is released the ovt will be very recent, possibly @@ -534,7 +524,10 @@ /*d->spinloop_counter = (unsigned int)(d->my_lock_word | 1);*/ thread_descriptor = d; - /* active_thread_descriptor stays NULL */ + if (in_main_thread) + stm_leave_transactional_mode(); + else + ; /* active_thread_descriptor stays NULL */ #ifdef RPY_STM_DEBUG_PRINT if (PYPY_HAVE_DEBUG_PRINTS) fprintf(PYPY_DEBUG_FILE, "thread %lx starting\n", @@ -681,6 +674,33 @@ return result; } +void stm_enter_transactional_mode(void) +{ + struct tx_descriptor *d = active_thread_descriptor; + assert(d != NULL); + assert(is_inevitable(d)); + /* we only need a subset of a full commit */ + acquireLocks(d); + commitInevitableTransaction(d); + common_cleanup(d); + active_thread_descriptor = NULL; +} + +void stm_leave_transactional_mode(void) +{ + struct tx_descriptor *d = thread_descriptor; + assert(active_thread_descriptor == NULL); + + mutex_lock(); + d->setjmp_buf = NULL; + d->start_time = get_global_timestamp(d); + assert(!(d->start_time & 1)); + set_global_timestamp(d, d->start_time | 1); + + assert(is_inevitable(d)); + active_thread_descriptor = d; +} + void stm_try_inevitable(STM_CCHARP1(why)) { /* when a transaction is inevitable, its start_time is equal to @@ -745,13 +765,12 @@ return -2; if (active_thread_descriptor == NULL) { - if (d->my_lock_word == 0) - return -1; - else - return 0; + assert(d->my_lock_word != 0); + return 0; } assert(d == active_thread_descriptor); - assert(d->my_lock_word != 0); + if (d->my_lock_word == 0) + return -1; if (!is_inevitable(d)) return 1; else diff --git a/pypy/translator/stm/src_stm/et.h b/pypy/translator/stm/src_stm/et.h --- a/pypy/translator/stm/src_stm/et.h +++ b/pypy/translator/stm/src_stm/et.h @@ -40,6 +40,8 @@ void* stm_perform_transaction(void*(*)(void*, long), void*); +void stm_enter_transactional_mode(void); +void stm_leave_transactional_mode(void); void stm_try_inevitable(STM_CCHARP1(why)); void stm_abort_and_retry(void); long stm_debug_get_state(void); /* -1: descriptor_init() was not called diff --git a/pypy/translator/stm/stmgcintf.py b/pypy/translator/stm/stmgcintf.py --- a/pypy/translator/stm/stmgcintf.py +++ b/pypy/translator/stm/stmgcintf.py @@ -56,6 +56,11 @@ get_tls = smexternal('stm_get_tls', [], llmemory.Address) del_tls = smexternal('stm_del_tls', [], lltype.Void) + enter_transactional_mode = smexternal('stm_enter_transactional_mode', + [], lltype.Void) + leave_transactional_mode = smexternal('stm_leave_transactional_mode', + [], lltype.Void) + tldict_lookup = smexternal('stm_tldict_lookup', [llmemory.Address], llmemory.Address) tldict_add = smexternal('stm_tldict_add', [llmemory.Address] * 2, _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit