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