Commits

Armin Rigo committed 0f73f6e

Fix and test stm_read_word(). Separate getsize_fn from stm_set_tls().

  • Participants
  • Parent commits 470ded2
  • Branches stm-gc

Comments (0)

Files changed (6)

File pypy/rpython/memory/gc/stmgc.py

         self.collector = Collector(self)
         self.max_nursery_size = max_nursery_size
         #
-        def _do_get_size(obj):     # indirection to hide 'self'
+        def _get_size(obj):     # indirection to hide 'self'
             return self.get_size(obj)
-        GETSIZE = lltype.Ptr(lltype.FuncType([llmemory.Address],lltype.Signed))
-        self._do_get_size = llhelper(GETSIZE, _do_get_size)
+        self._getsize_fn = _get_size
         #
         self.declare_readers()
         self.declare_write_barrier()
     def setup(self):
         """Called at run-time to initialize the GC."""
         GCBase.setup(self)
+        GETSIZE = lltype.Ptr(lltype.FuncType([llmemory.Address],lltype.Signed))
+        self.stm_operations.setup_size_getter(
+                llhelper(GETSIZE, self._getsize_fn))
         self.main_thread_tls = self.setup_thread(True)
         self.mutex_lock = ll_thread.allocate_ll_lock()
 
         Must be called only once per OS-level thread."""
         tls = lltype.malloc(self.GCTLS, flavor='raw')
         self.stm_operations.set_tls(llmemory.cast_ptr_to_adr(tls),
-                                    self._do_get_size)
+                                    int(in_main_thread))
         tls.nursery_start = self._alloc_nursery()
         tls.nursery_size  = self.max_nursery_size
         tls.nursery_free  = tls.nursery_start

File pypy/rpython/memory/gc/test/test_stmgc.py

 
     threadnum = 0          # 0 = main thread; 1,2,3... = transactional threads
 
-    def set_tls(self, tls, getsize_fn):
+    def setup_size_getter(self, getsize_fn):
+        self._getsize_fn = getsize_fn
+
+    def set_tls(self, tls, in_main_thread):
         assert lltype.typeOf(tls) == llmemory.Address
         assert tls
         if self.threadnum == 0:
+            assert in_main_thread == 1
             assert not hasattr(self, '_tls_dict')
             self._tls_dict = {0: tls}
             self._tldicts = {0: {}}
             self._tldicts_iterators = {}
-            self._getsize_fn = getsize_fn
             self._transactional_copies = []
         else:
+            assert in_main_thread == 0
             self._tls_dict[self.threadnum] = tls
             self._tldicts[self.threadnum] = {}
 

File pypy/translator/stm/src_stm/et.c

 #ifdef PYPY_STANDALONE         /* obscure: cannot include debug_print.h if compiled */
 # define RPY_STM_DEBUG_PRINT   /* via ll2ctypes; only include it in normal builds */
 # include "src/debug_print.h"
+#else
+# define RPY_STM_ASSERT    1
 #endif
 
 /************************************************************/
 
 struct tx_descriptor {
   void *rpython_tls_object;
-  long (*rpython_get_size)(void*);
   jmp_buf *setjmp_buf;
   owner_version_t start_time;
   owner_version_t end_time;
   /*unsigned long last_known_global_timestamp;*/
+  owner_version_t my_lock_word;
   struct OrecList reads;
   unsigned num_commits;
   unsigned num_aborts[ABORT_REASONS];
   unsigned num_spinloops[SPINLOOP_REASONS];
   /*unsigned int spinloop_counter;*/
-  owner_version_t my_lock_word;
   struct RedoLog redolog;   /* last item, because it's the biggest one */
 };
 
    if there is an inevitable transaction running */
 static volatile unsigned long global_timestamp = 2;
 static __thread struct tx_descriptor *thread_descriptor = NULL;
+static long (*rpython_get_size)(void*);
 
 /************************************************************/
 
 #endif
 }
 
+static _Bool is_main_thread(struct tx_descriptor *d)
+{
+  return d->my_lock_word == 0;
+}
+
 static _Bool is_inevitable(struct tx_descriptor *d)
 {
   return d->setjmp_buf == NULL;
       void *globalobj = item->addr;
       void *localobj = item->val;
       owner_version_t p = item->p;
-      long size = d->rpython_get_size(localobj);
+      long size = rpython_get_size(localobj);
       memcpy(((char *)globalobj) + sizeof(orec_t),
              ((char *)localobj) + sizeof(orec_t),
              size - sizeof(orec_t));
 static void mutex_lock(void)
 {
   unsigned long pself = (unsigned long)pthread_self();
+#ifdef RPY_STM_DEBUG_PRINT
   if (PYPY_HAVE_DEBUG_PRINTS) fprintf(PYPY_DEBUG_FILE,
                                       "%lx: mutex inev locking...\n", pself);
+#endif
   assert(locked_by != pself);
   pthread_mutex_lock(&mutex_inevitable);
   locked_by = pself;
+#ifdef RPY_STM_DEBUG_PRINT
   if (PYPY_HAVE_DEBUG_PRINTS) fprintf(PYPY_DEBUG_FILE,
                                       "%lx: mutex inev locked\n", pself);
+#endif
 }
 static void mutex_unlock(void)
 {
   unsigned long pself = (unsigned long)pthread_self();
   locked_by = 0;
+#ifdef RPY_STM_DEBUG_PRINT
   if (PYPY_HAVE_DEBUG_PRINTS) fprintf(PYPY_DEBUG_FILE,
                                       "%lx: mutex inev unlocked\n", pself);
+#endif
   pthread_mutex_unlock(&mutex_inevitable);
 }
 # else
     not_found:;
     }
 
+  // XXX try to remove this check from the main path
+  if (is_main_thread(d))
+    return *(long *)(((char *)addr) + offset);
+
  retry:
   // read the orec BEFORE we read anything else
   ovt = o->version;
 }
 
 
-static struct tx_descriptor *descriptor_init(void)
+static struct tx_descriptor *descriptor_init(_Bool is_main_thread)
 {
   assert(thread_descriptor == NULL);
   if (1)  /* for hg diff */
       PYPY_DEBUG_START("stm-init");
 #endif
 
-      /* initialize 'my_lock_word' to be a unique negative number */
-      d->my_lock_word = (owner_version_t)d;
-      if (!IS_LOCKED(d->my_lock_word))
-        d->my_lock_word = ~d->my_lock_word;
-      assert(IS_LOCKED(d->my_lock_word));
+      if (is_main_thread)
+        {
+          d->my_lock_word = 0;
+        }
+      else
+        {
+          /* initialize 'my_lock_word' to be a unique negative number */
+          d->my_lock_word = (owner_version_t)d;
+          if (!IS_LOCKED(d->my_lock_word))
+            d->my_lock_word = ~d->my_lock_word;
+          assert(IS_LOCKED(d->my_lock_word));
+        }
       /*d->spinloop_counter = (unsigned int)(d->my_lock_word | 1);*/
 
       thread_descriptor = d;
 static long commit_transaction(void)
 {
   struct tx_descriptor *d = thread_descriptor;
+  assert(!is_main_thread(d));
 
   // if I don't have writes, I'm committed
   if (!redolog_any_entry(&d->redolog))
 }
 
 
-void stm_set_tls(void *newtls, long (*getsize)(void*))
+void stm_set_tls(void *newtls, long is_main_thread)
 {
-  struct tx_descriptor *d = descriptor_init();
+  struct tx_descriptor *d = descriptor_init(is_main_thread);
   d->rpython_tls_object = newtls;
-  d->rpython_get_size = getsize;
 }
 
 void *stm_get_tls(void)
     } REDOLOG_LOOP_END;
 }
 
+void stm_setup_size_getter(long(*getsize_fn)(void*))
+{
+  rpython_get_size = getsize_fn;
+}
+
 #endif  /* PYPY_NOT_MAIN_FILE */

File pypy/translator/stm/src_stm/et.h

 #include "src/commondefs.h"
 
 
-void stm_set_tls(void *, long(*)(void*));
+void stm_setup_size_getter(long(*)(void*));
+
+void stm_set_tls(void *, long);
 void *stm_get_tls(void);
 void stm_del_tls(void);
 

File pypy/translator/stm/stmgcintf.py

     def _freeze_(self):
         return True
 
-    set_tls = smexternal('stm_set_tls', [llmemory.Address, GETSIZE],
+    setup_size_getter = smexternal('stm_setup_size_getter', [GETSIZE],
+                                   lltype.Void)
+
+    set_tls = smexternal('stm_set_tls', [llmemory.Address, lltype.Signed],
                          lltype.Void)
     get_tls = smexternal('stm_get_tls', [], llmemory.Address)
     del_tls = smexternal('stm_del_tls', [], lltype.Void)

File pypy/translator/stm/test/test_stmgcintf.py

 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 from pypy.rpython.annlowlevel import llhelper
 from pypy.translator.stm.stmgcintf import StmOperations, CALLBACK, GETSIZE
+from pypy.rpython.memory.gc import stmgc
 
 stm_operations = StmOperations()
 
 DEFAULT_TLS = lltype.Struct('DEFAULT_TLS')
 
+S1 = lltype.Struct('S1', ('hdr', stmgc.StmGC.HDR),
+                         ('x', lltype.Signed),
+                         ('y', lltype.Signed))
+
 
 def test_set_get_del():
     # assume that they are really thread-local; not checked here
     s = lltype.malloc(lltype.Struct('S'), flavor='raw')
     a = llmemory.cast_ptr_to_adr(s)
-    stm_operations.set_tls(a, lltype.nullptr(GETSIZE.TO))
+    stm_operations.set_tls(a, 1)
     assert stm_operations.get_tls() == a
     stm_operations.del_tls()
     lltype.free(s, flavor='raw')
         s = lltype.malloc(TLS, flavor='raw', immortal=True)
         self.tls = s
         a = llmemory.cast_ptr_to_adr(s)
-        getsize = llhelper(GETSIZE, self.getsize)
-        stm_operations.set_tls(a, getsize)
+        in_main_thread = getattr(meth, 'in_main_thread', True)
+        stm_operations.set_tls(a, int(in_main_thread))
 
     def teardown_method(self, meth):
         stm_operations.del_tls()
 
-    def getsize(self, obj):
-        xxx
-
     def test_set_get_del(self):
         a = llmemory.cast_ptr_to_adr(self.tls)
         assert stm_operations.get_tls() == a
         p_callback, seen = self.get_callback()
         stm_operations.tldict_enum(p_callback)
         assert seen == []
+
+    def stm_read_case(self, flags, copied=False):
+        # doesn't test STM behavior, but just that it appears to work
+        s1 = lltype.malloc(S1, flavor='raw')
+        s1.hdr.tid = stmgc.GCFLAG_GLOBAL | flags
+        s1.hdr.version = llmemory.NULL
+        s1.x = 42042
+        if copied:
+            s2 = lltype.malloc(S1, flavor='raw')
+            s2.hdr.tid = stmgc.GCFLAG_WAS_COPIED
+            s2.hdr.version = llmemory.NULL
+            s2.x = 84084
+            a1 = llmemory.cast_ptr_to_adr(s1)
+            a2 = llmemory.cast_ptr_to_adr(s2)
+            stm_operations.tldict_add(a1, a2)
+        res = stm_operations.stm_read_word(llmemory.cast_ptr_to_adr(s1),
+                                           rffi.sizeof(S1.hdr))  # 'x'
+        lltype.free(s1, flavor='raw')
+        if copied:
+            lltype.free(s2, flavor='raw')
+        return res
+
+    def test_stm_read_word_main_thread(self):
+        res = self.stm_read_case(0)                        # not copied
+        assert res == 42042
+        res = self.stm_read_case(stmgc.GCFLAG_WAS_COPIED)  # but ignored
+        assert res == 42042
+
+    def test_stm_read_word_transactional_thread(self):
+        res = self.stm_read_case(0)                        # not copied
+        assert res == 42042
+        res = self.stm_read_case(stmgc.GCFLAG_WAS_COPIED)  # but ignored
+        assert res == 42042
+        res = self.stm_read_case(stmgc.GCFLAG_WAS_COPIED, copied=True)
+        assert res == 84084
+    test_stm_read_word_transactional_thread.in_main_thread = False
+
+    def test_stm_size_getter(self):
+        def getsize(addr):
+            xxx
+        getter = llhelper(GETSIZE, getsize)
+        stm_operations.setup_size_getter(getter)
+        # just tests that the function is really defined