Author: Armin Rigo <[email protected]> Branch: stm-thread Changeset: r54886:086878de9950 Date: 2012-05-03 14:34 +0200 http://bitbucket.org/pypy/pypy/changeset/086878de9950/
Log: Add a demo transaction target using the GIL. diff --git a/pypy/translator/stm/test/targetdemo2.py b/pypy/translator/stm/test/targetdemo2.py new file mode 100644 --- /dev/null +++ b/pypy/translator/stm/test/targetdemo2.py @@ -0,0 +1,176 @@ +import time +from pypy.module.thread import ll_thread, gil +from pypy.rlib.objectmodel import invoke_around_extcall, we_are_translated + + +class Node: + def __init__(self, value): + self.value = value + self.next = None + +class Global: + NUM_THREADS = 4 + LENGTH = 5000 + USE_MEMORY = False + anchor = Node(-1) +glob = Global() + +def add_at_end_of_chained_list(node, value, threadindex): + x = Node(value) + while node.next: + node = node.next + if glob.USE_MEMORY: + x = Node(value) + if not we_are_translated(): + print threadindex + time.sleep(0.01) + newnode = x + assert node.next is None + node.next = newnode + +def check_chained_list(node): + seen = [0] * (glob.LENGTH+1) + seen[-1] = glob.NUM_THREADS + errors = glob.LENGTH + while node is not None: + value = node.value + #print value + if not (0 <= value < glob.LENGTH): + print "node.value out of bounds:", value + raise AssertionError + seen[value] += 1 + if seen[value] > seen[value-1]: + errors = min(errors, value) + node = node.next + if errors < glob.LENGTH: + value = errors + print "seen[%d] = %d, seen[%d] = %d" % (value-1, seen[value-1], + value, seen[value]) + raise AssertionError + + if seen[glob.LENGTH-1] != glob.NUM_THREADS: + print "seen[LENGTH-1] != NUM_THREADS" + raise AssertionError + print "check ok!" + + +class ThreadRunner(object): + def __init__(self, i): + self.index = i + self.finished_lock = ll_thread.allocate_lock() + self.finished_lock.acquire(True) + + def run(self): + try: + self.really_run() + finally: + self.finished_lock.release() + + def really_run(self): + for value in range(glob.LENGTH): + add_at_end_of_chained_list(glob.anchor, value, self.index) + gil.do_yield_thread() + +# ____________________________________________________________ +# bah, we are really missing an RPython interface to threads + +class Bootstrapper(object): + # The following lock is held whenever the fields + # 'bootstrapper.w_callable' and 'bootstrapper.args' are in use. + lock = None + args = None + + @staticmethod + def setup(): + if bootstrapper.lock is None: + bootstrapper.lock = ll_thread.allocate_lock() + + @staticmethod + def reinit(): + bootstrapper.lock = None + bootstrapper.args = None + + def _freeze_(self): + self.reinit() + return False + + @staticmethod + def bootstrap(): + # Note that when this runs, we already hold the GIL. This is ensured + # by rffi's callback mecanism: we are a callback for the + # c_thread_start() external function. + ll_thread.gc_thread_start() + args = bootstrapper.args + bootstrapper.release() + # run! + try: + args.run() + finally: + ll_thread.gc_thread_die() + + @staticmethod + def acquire(args): + # If the previous thread didn't start yet, wait until it does. + # Note that bootstrapper.lock must be a regular lock, not a NOAUTO + # lock, because the GIL must be released while we wait. + bootstrapper.lock.acquire(True) + bootstrapper.args = args + + @staticmethod + def release(): + # clean up 'bootstrapper' to make it ready for the next + # start_new_thread() and release the lock to tell that there + # isn't any bootstrapping thread left. + bootstrapper.args = None + bootstrapper.lock.release() + +bootstrapper = Bootstrapper() + +def setup_threads(): + #space.threadlocals.setup_threads(space) + bootstrapper.setup() + invoke_around_extcall(gil.before_external_call, gil.after_external_call) + +def start_thread(args): + bootstrapper.acquire(args) + try: + ll_thread.gc_thread_prepare() # (this has no effect any more) + ident = ll_thread.start_new_thread(bootstrapper.bootstrap, ()) + except Exception, e: + bootstrapper.release() # normally called by the new thread + raise + return ident + +# __________ Entry point __________ + +def entry_point(argv): + print "hello 2nd world" + if len(argv) > 1: + glob.NUM_THREADS = int(argv[1]) + if len(argv) > 2: + glob.LENGTH = int(argv[2]) + if len(argv) > 3: + glob.USE_MEMORY = bool(int(argv[3])) + # + setup_threads() + # + locks = [] + for i in range(glob.NUM_THREADS): + threadrunner = ThreadRunner(i) + start_thread(threadrunner) + locks.append(threadrunner.finished_lock) + for lock in locks: + lock.acquire(True) + # + check_chained_list(glob.anchor.next) + # + return 0 + +# _____ Define and setup target ___ + +def target(*args): + return entry_point, None + +if __name__ == '__main__': + import sys + entry_point(sys.argv) _______________________________________________ pypy-commit mailing list [email protected] http://mail.python.org/mailman/listinfo/pypy-commit
