[pypy-commit] pypy reverse-debugger: Hopefully correct handling of thread-locals

arigo pypy.commits at gmail.com
Thu Aug 11 13:58:04 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: reverse-debugger
Changeset: r86158:0981c3747dd3
Date: 2016-08-11 19:57 +0200
http://bitbucket.org/pypy/pypy/changeset/0981c3747dd3/

Log:	Hopefully correct handling of thread-locals

diff --git a/rpython/translator/c/genc.py b/rpython/translator/c/genc.py
--- a/rpython/translator/c/genc.py
+++ b/rpython/translator/c/genc.py
@@ -778,6 +778,10 @@
     for field in fields:
         print >> f, ('#define RPY_TLOFS_%s  offsetof(' % field.fieldname +
                      'struct pypy_threadlocal_s, %s)' % field.fieldname)
+    if fields:
+        print >> f, '#define RPY_TLOFSFIRST  RPY_TLOFS_%s' % fields[0].fieldname
+    else:
+        print >> f, '#define RPY_TLOFSFIRST  sizeof(struct pypy_threadlocal_s)'
     print >> f, 'struct pypy_threadlocal_s {'
     print >> f, '\tint ready;'
     print >> f, '\tchar *stack_end;'
diff --git a/rpython/translator/revdb/src-revdb/revdb.c b/rpython/translator/revdb/src-revdb/revdb.c
--- a/rpython/translator/revdb/src-revdb/revdb.c
+++ b/rpython/translator/revdb/src-revdb/revdb.c
@@ -26,6 +26,7 @@
 #include "revdb_def.h"
 #include "src/rtyper.h"
 #include "src/mem.h"
+#include "src/threadlocal.h"
 #include "src-revdb/revdb_include.h"
 
 #define RDB_SIGNATURE   "RevDB:"
@@ -673,6 +674,7 @@
 struct replay_thread_s {
     uint64_t tid;
     stacklet_handle h;
+    struct pypy_threadlocal_s tloc;
 };
 
 static stacklet_handle replay_thread_main(stacklet_handle h, void *arg)
@@ -737,6 +739,7 @@
            can switch it away at any point later */
         struct replay_thread_main_s m;
         stacklet_handle h;
+        struct pypy_threadlocal_s *real_tloc = NULL;
         m.entry_point = entry_point;
         m.argc = argc;
         m.argv = argv;
@@ -750,6 +753,10 @@
         while (1) {
             struct replay_thread_s *node, **item, dummy;
 
+            if (real_tloc == NULL) {
+                _OP_THREADLOCALREF_ADDR_SIGHANDLER(real_tloc);
+            }
+
             if (h == NULL)
                 goto out_of_memory;
 
@@ -761,6 +768,12 @@
                     goto out_of_memory;
                 node->tid = current_thread_id;
                 node->h = h;
+                /* save the thread-locals, if any */
+                if (real_tloc != NULL)
+                    node->tloc = *real_tloc;
+                else
+                    memset(&node->tloc, 0, sizeof(node->tloc));
+
                 item = tsearch(node, &thread_tree_root, compare_replay_thread);
                 if (item == NULL)
                     goto out_of_memory;
@@ -780,6 +793,9 @@
             item = tfind(&dummy, &thread_tree_root, compare_replay_thread);
             if (item == NULL) {
                 /* it's a new thread, start it now */
+                if (real_tloc != NULL)
+                    memset(((char *)real_tloc) + RPY_TLOFSFIRST, 0,
+                           sizeof(struct pypy_threadlocal_s) - RPY_TLOFSFIRST);
                 h = stacklet_new(st_thread, replay_thread_sub, NULL);
             }
             else {
@@ -787,6 +803,8 @@
                 assert(node->tid == target_thread_id);
                 h = node->h;
                 tdelete(node, &thread_tree_root, compare_replay_thread);
+                if (real_tloc != NULL)
+                    *real_tloc = node->tloc;
                 free(node);
 
                 h = stacklet_switch(h);
@@ -1068,7 +1086,10 @@
                 target_thread_id = fetch_async_block();
                 _RPY_REVDB_PRINT("[THRD]", target_thread_id);
                 rpy_revdb.buf_limit = rpy_revdb.buf_p;
-                st_outer_controller_h = stacklet_switch(st_outer_controller_h);
+                if (target_thread_id != current_thread_id) {
+                    st_outer_controller_h = stacklet_switch(
+                                                st_outer_controller_h);
+                }
                 if (rpy_revdb.buf_limit == rpy_revdb.buf_p)
                     rpy_reverse_db_fetch(__FILE__, __LINE__);
                 return;
diff --git a/rpython/translator/revdb/test/test_thread.py b/rpython/translator/revdb/test/test_thread.py
--- a/rpython/translator/revdb/test/test_thread.py
+++ b/rpython/translator/revdb/test/test_thread.py
@@ -169,3 +169,41 @@
             child.expect(ANSWER_READY, i, Ellipsis)
         child.send(Message(CMD_FORWARD, 1))
         child.expect(ANSWER_AT_END)
+
+
+class TestThreadLocal(InteractiveTests):
+    expected_stop_points = 1
+
+    def setup_class(cls):
+        from rpython.translator.revdb.test.test_basic import compile, run
+        class EC(object):
+            def __init__(self, value):
+                self.value = value
+        raw_thread_local = rthread.ThreadLocalReference(EC)
+
+        def bootstrap():
+            rthread.gc_thread_start()
+            _sleep(1)
+            ec = EC(4567)
+            raw_thread_local.set(ec)
+            revdb.stop_point()
+            print raw_thread_local.get().value
+            assert raw_thread_local.get() is ec
+            rthread.gc_thread_die()
+
+        def main(argv):
+            ec = EC(12)
+            raw_thread_local.set(ec)
+            rthread.start_new_thread(bootstrap, ())
+            _sleep(2)
+            print raw_thread_local.get().value
+            assert raw_thread_local.get() is ec
+            return 9
+
+        compile(cls, main, backendopt=False, thread=True)
+        assert run(cls, '') == '4567\n12\n'
+
+    def test_go_threadlocal(self):
+        child = self.replay()
+        child.send(Message(CMD_FORWARD, 1))
+        child.expect(ANSWER_AT_END)


More information about the pypy-commit mailing list