Author: Armin Rigo <[email protected]>
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
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit