From f6c22a06797735e4a65a91491d8373ba951a798b Mon Sep 17 00:00:00 2001
From: Damien George <damien.p.george@gmail.com>
Date: Mon, 6 Feb 2017 10:50:43 +1100
Subject: [PATCH] py/vm: Add MICROPY_PY_THREAD_GIL_VM_DIVISOR option.

This improves efficiency of GIL release within the VM, by only doing the
release after a fixed number of jump-opcodes have executed in the current
thread.
---
 py/mpconfig.h |  6 ++++++
 py/vm.c       | 20 +++++++++++++++++---
 2 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/py/mpconfig.h b/py/mpconfig.h
index 093625a46..1b47d822f 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -949,6 +949,12 @@ typedef double mp_float_t;
 #define MICROPY_PY_THREAD_GIL (MICROPY_PY_THREAD)
 #endif
 
+// Number of VM jump-loops to do before releasing the GIL.
+// Set this to 0 to disable the divisor.
+#ifndef MICROPY_PY_THREAD_GIL_VM_DIVISOR
+#define MICROPY_PY_THREAD_GIL_VM_DIVISOR (32)
+#endif
+
 // Extended modules
 
 #ifndef MICROPY_PY_UCTYPES
diff --git a/py/vm.c b/py/vm.c
index f4cfa2cd6..fb59bf9cf 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -169,6 +169,12 @@ run_code_state: ;
     volatile bool currently_in_except_block = MP_TAGPTR_TAG0(code_state->exc_sp); // 0 or 1, to detect nested exceptions
     mp_exc_stack_t *volatile exc_sp = MP_TAGPTR_PTR(code_state->exc_sp); // stack grows up, exc_sp points to top of stack
 
+    #if MICROPY_PY_THREAD_GIL && MICROPY_PY_THREAD_GIL_VM_DIVISOR
+    // This needs to be volatile and outside the VM loop so it persists across handling
+    // of any exceptions.  Otherwise it's possible that the VM never gives up the GIL.
+    volatile int gil_divisor = MICROPY_PY_THREAD_GIL_VM_DIVISOR;
+    #endif
+
     // outer exception handling loop
     for (;;) {
         nlr_buf_t nlr;
@@ -1243,9 +1249,17 @@ pending_exception_check:
                     RAISE(obj);
                 }
 
-                // TODO make GIL release more efficient
-                MP_THREAD_GIL_EXIT();
-                MP_THREAD_GIL_ENTER();
+                #if MICROPY_PY_THREAD_GIL
+                #if MICROPY_PY_THREAD_GIL_VM_DIVISOR
+                if (--gil_divisor == 0) {
+                    gil_divisor = MICROPY_PY_THREAD_GIL_VM_DIVISOR;
+                #else
+                {
+                #endif
+                    MP_THREAD_GIL_EXIT();
+                    MP_THREAD_GIL_ENTER();
+                }
+                #endif
 
             } // for loop
 
-- 
GitLab