[pypy-commit] stmgc c8-gil-like: Plan

arigo noreply at buildbot.pypy.org
Wed Jun 3 07:58:26 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: c8-gil-like
Changeset: r1789:2ee1030752df
Date: 2015-06-03 07:59 +0200
http://bitbucket.org/pypy/stmgc/changeset/2ee1030752df/

Log:	Plan

diff --git a/c8/CALL_RELEASE_GIL b/c8/CALL_RELEASE_GIL
new file mode 100644
--- /dev/null
+++ b/c8/CALL_RELEASE_GIL
@@ -0,0 +1,88 @@
+
+c8-gil-like
+===========
+
+A branch to have "GIL-like" behavior for inevitable transactions: one
+not-too-short inevitable transaction that is passed around multiple
+threads.
+
+The goal is to have good fast-case behavior with the PyPy JIT around
+CALL_RELEASE_GIL.  This is how it works in default (with shadowstack):
+
+
+- "rpy_fastgil" is a global variable.  The value 0 means the GIL is
+  definitely unlocked; the value 1 means it is probably locked (it is
+  actually locked only if some mutex object is acquired too).
+
+- before CALL_RELEASE_GIL, we know that we have the GIL and we need to
+  release it.  So we know that "rpy_fastgil" is 1, and we just write 0
+  there.
+
+- then we do the external call.
+
+- after CALL_RELEASE_GIL, two cases:
+
+  - if "rpy_fastgil" has been changed to 1 by some other thread *or*
+    if the (non-thread-local) shadowstack pointer changed, then we
+    call reacqgil_addr();
+
+  - otherwise, we swap rpy_fastgil back to 1 and we're done.
+
+- a different mechanism is used when we voluntarily release the GIL,
+  based on the mutex mentioned above.  The mutex is also used by the
+  the reacqgil_addr() function if it actually needs to wait.
+
+
+Plan for porting this idea to stmgc:
+
+- we add a few macros to stmgc.h which can be used by C code, around
+  external calls; and we also inline these macros manually around
+  CALL_RELEASE_GIL in PyPy's JIT.
+
+- we add the "detached" mode to inevitable transactions: it means that
+  no thread is actively running this inevitable transaction for now,
+  but it was not committed yet.  It is meant to be reattached, by the
+  same or a different thread.
+
+- we add a global variable, "stm_detached_inevitable_from_thread".  It
+  is equal to the shadowstack pointer of the thread that detached
+  inevitable transaction (like rpy_fastgil == 0), or NULL if there is
+  no detached inevitable transaction (like rpy_fastgil == 1).
+
+- the macro stm_detach_inevitable_transaction() simply writes the
+  current thread's shadowstack pointer into the global variable
+  stm_detached_inevitable_from_thread.  It can only be used if the
+  current transaction is inevitable (and in particular the inevitable
+  transaction was not detached already, because we're running it).
+  After the macro is called, the current thread is assumed not to be
+  running in a transaction any more (no more object or shadowstack
+  access).
+
+- the macro stm_reattach_transaction() does an atomic swap on
+  stm_detached_inevitable_from_thread to change it to NULL.  If the
+  old value was equal to our own shadowstack pointer, we are done.  If
+  not, we call a helper, _stm_reattach_transaction().
+
+- we also add the macro stm_detach_transation().  If the current
+  thread is inevitable it calls stm_detach_inevitable_transaction().
+  Otherwise it calls a helper, _stm_detach_noninevitable_transaction().
+
+- _stm_reattach_transaction(old): called with the old value from
+  stm_detach_inevitable_transaction (which was swapped to be NULL just
+  now).  If old != NULL, this swap had the effect that we took over
+  the inevitable transaction originally detached from a different
+  thread; we need to fix a few things like the shadowstack and %gs but
+  then we can continue running this reattached inevitable transaction.
+  If old == NULL, we need to fall back to the current
+  stm_start_transaction().
+
+- _stm_detach_noninevitable_transaction(): we try to make the
+  transaction inevitable.  If it works we can then use
+  stm_detach_inevitable_transaction().  On the other hand, if we can't
+  make it inevitable without waiting, then instead we just commit it
+  and continue.  In the latter case,
+  stm_detached_inevitable_from_thread is still NULL.
+
+- other place to fix: major collections.  Maybe simply look inside
+  stm_detached_inevitable_from_thread, and if not NULL, grab the
+  inevitable transaction and commit it now.


More information about the pypy-commit mailing list