Author: Armin Rigo <ar...@tunes.org>
Branch: concurrent-marksweep
Changeset: r48052:08bcc238a411
Date: 2011-10-14 12:14 +0200
http://bitbucket.org/pypy/pypy/changeset/08bcc238a411/

Log:    Locking is needed in the AddressStack class, to access the pool of
        free pages (which is shared between all AddressStack instances, so
        accessed from the two threads concurrently).

diff --git a/pypy/rpython/memory/gc/base.py b/pypy/rpython/memory/gc/base.py
--- a/pypy/rpython/memory/gc/base.py
+++ b/pypy/rpython/memory/gc/base.py
@@ -24,10 +24,10 @@
     gcflag_extra = 0   # or a real GC flag that is always 0 when not collecting
 
     def __init__(self, config, chunk_size=DEFAULT_CHUNK_SIZE,
-                 translated_to_c=True):
+                 translated_to_c=True, lock=None):
         self.gcheaderbuilder = GCHeaderBuilder(self.HDR)
-        self.AddressStack = get_address_stack(chunk_size)
-        self.AddressDeque = get_address_deque(chunk_size)
+        self.AddressStack = get_address_stack(chunk_size, lock=lock)
+        self.AddressDeque = get_address_deque(chunk_size, lock=lock)
         self.AddressDict = AddressDict
         self.null_address_dict = null_address_dict
         self.config = config
diff --git a/pypy/rpython/memory/gc/concurrentms.py 
b/pypy/rpython/memory/gc/concurrentms.py
--- a/pypy/rpython/memory/gc/concurrentms.py
+++ b/pypy/rpython/memory/gc/concurrentms.py
@@ -71,6 +71,8 @@
         # 'small_request_threshold' is the largest size that we will
         # satisfy using our own pages mecanism.  Larger requests just
         # go to the system malloc().
+        self.addressstack_lock_object = SyncLock()
+        kwds['lock'] = self.addressstack_lock_object
         GCBase.__init__(self, config, **kwds)
         assert small_request_threshold % WORD == 0
         self.small_request_threshold = small_request_threshold
@@ -188,6 +190,7 @@
         self.ready_to_start_lock = ll_thread.allocate_ll_lock()
         self.finished_lock = ll_thread.allocate_ll_lock()
         self.mutex_lock = ll_thread.allocate_ll_lock()
+        self.addressstack_lock_object.setup()
         #
         self.acquire(self.finished_lock)
         self.acquire(self.ready_to_start_lock)
@@ -1065,8 +1068,8 @@
             ll_assert(offset >= 0, "bad weakref")
             obj = x + size_gc_header
             pointing_to = (obj + offset).address[0]
-            if (pointing_to == llmemory.NULL or
-                not self.is_marked_or_static(pointing_to, current_mark)):
+            ll_assert(pointing_to != llmemory.NULL, "null weakref?")
+            if not self.is_marked_or_static(pointing_to, current_mark):
                 # 'pointing_to' dies: relink to self.collect_pages[0]
                 (obj + offset).address[0] = llmemory.NULL
                 set_next(weakref_page, self.collect_pages[0])
@@ -1192,3 +1195,19 @@
                            [MostlyConcurrentMarkSweepGC.HDRPTR, lltype.Signed],
                            lltype.Void, compilation_info=eci, _nowrapper=True,
                            _callable=emulate_set_flags)
+
+# ____________________________________________________________
+#
+# A lock to synchronize access to AddressStack's free pages
+
+class SyncLock:
+    _alloc_flavor_ = "raw"
+    _lock = lltype.nullptr(ll_thread.TLOCKP.TO)
+    def setup(self):
+        self._lock = ll_thread.allocate_ll_lock()
+    def acquire(self):
+        if self._lock:
+            ll_thread.c_thread_acquirelock(self._lock, 1)
+    def release(self):
+        if self._lock:
+            ll_thread.c_thread_releaselock(self._lock)
diff --git a/pypy/rpython/memory/support.py b/pypy/rpython/memory/support.py
--- a/pypy/rpython/memory/support.py
+++ b/pypy/rpython/memory/support.py
@@ -16,9 +16,9 @@
 DEFAULT_CHUNK_SIZE = 1019
 
 
-def get_chunk_manager(chunk_size=DEFAULT_CHUNK_SIZE, cache={}):
+def get_chunk_manager(chunk_size=DEFAULT_CHUNK_SIZE, cache={}, lock=None):
     try:
-        return cache[chunk_size]
+        return cache[chunk_size, lock]
     except KeyError:
         pass
 
@@ -36,7 +36,9 @@
             self.free_list = null_chunk
 
         def get(self):
+            self._lock()
             if not self.free_list:
+                self._unlock()
                 # we zero-initialize the chunks to make the translation
                 # backends happy, but we don't need to do it at run-time.
                 if we_are_translated():
@@ -52,9 +54,11 @@
 
             result = self.free_list
             self.free_list = result.next
+            self._unlock()
             return result
 
         def put(self, chunk):
+            self._lock()
             if we_are_translated():
                 chunk.next = self.free_list
                 self.free_list = chunk
@@ -63,19 +67,27 @@
                 # Helps debugging, and avoids that old chunks full of
                 # addresses left behind by a test end up in genc...
                 lltype.free(chunk, flavor="raw", track_allocation=False)
+            self._unlock()
+
+        if lock is not None:
+            def _lock(self):   lock.acquire()
+            def _unlock(self): lock.release()
+        else:
+            def _lock(self):   pass
+            def _unlock(self): pass
 
     unused_chunks = FreeList()
-    cache[chunk_size] = unused_chunks, null_chunk
+    cache[chunk_size, lock] = unused_chunks, null_chunk
     return unused_chunks, null_chunk
 
 
-def get_address_stack(chunk_size=DEFAULT_CHUNK_SIZE, cache={}):
+def get_address_stack(chunk_size=DEFAULT_CHUNK_SIZE, cache={}, lock=None):
     try:
-        return cache[chunk_size]
+        return cache[chunk_size, lock]
     except KeyError:
         pass
 
-    unused_chunks, null_chunk = get_chunk_manager(chunk_size)
+    unused_chunks, null_chunk = get_chunk_manager(chunk_size, lock=lock)
 
     class AddressStack(object):
         _alloc_flavor_ = "raw"
@@ -187,20 +199,20 @@
                 chunk.items[count] = got
                 got = next
 
-    cache[chunk_size] = AddressStack
+    cache[chunk_size, lock] = AddressStack
     return AddressStack
 
 def _add_in_dict(item, d):
     d.add(item)
 
 
-def get_address_deque(chunk_size=DEFAULT_CHUNK_SIZE, cache={}):
+def get_address_deque(chunk_size=DEFAULT_CHUNK_SIZE, cache={}, lock=None):
     try:
-        return cache[chunk_size]
+        return cache[chunk_size, lock]
     except KeyError:
         pass
 
-    unused_chunks, null_chunk = get_chunk_manager(chunk_size)
+    unused_chunks, null_chunk = get_chunk_manager(chunk_size, lock=lock)
 
     class AddressDeque(object):
         _alloc_flavor_ = "raw"
@@ -275,7 +287,7 @@
                 cur = next
             free_non_gc_object(self)
 
-    cache[chunk_size] = AddressDeque
+    cache[chunk_size, lock] = AddressDeque
     return AddressDeque
 
 # ____________________________________________________________
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to