[pypy-commit] stmgc c7-refactor: Carefully synchronize the threads in order to run a minor collection
arigo
noreply at buildbot.pypy.org
Sun Feb 16 15:30:16 CET 2014
Author: Armin Rigo <arigo at tunes.org>
Branch: c7-refactor
Changeset: r754:4fa29629edfa
Date: 2014-02-16 15:30 +0100
http://bitbucket.org/pypy/stmgc/changeset/4fa29629edfa/
Log: Carefully synchronize the threads in order to run a minor collection
diff --git a/c7/stm/contention.c b/c7/stm/contention.c
--- a/c7/stm/contention.c
+++ b/c7/stm/contention.c
@@ -38,7 +38,7 @@
}
else if (wait) {
/* otherwise, we will issue a safe point and wait: */
- STM_PSEGMENT->safe_point = SP_SAFE_POINT;
+ STM_PSEGMENT->safe_point = SP_SAFE_POINT_CANNOT_COLLECT;
/* signal the other thread; it must abort */
cond_broadcast();
diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -131,6 +131,10 @@
{
long remote_num = 1 - STM_SEGMENT->segment_num;
while (get_priv_segment(remote_num)->safe_point == SP_RUNNING) {
+
+ /* we have the mutex here */
+ get_segment(remote_num)->nursery_section_end = NSE_SIGNAL;
+
cond_wait();
}
}
diff --git a/c7/stm/core.h b/c7/stm/core.h
--- a/c7/stm/core.h
+++ b/c7/stm/core.h
@@ -60,12 +60,13 @@
uint8_t write_lock_num;
uint8_t safe_point; /* one of the SP_xxx constants */
uint8_t transaction_state; /* one of the TS_xxx constants */
+ uintptr_t real_nursery_section_end;
};
enum {
SP_NO_TRANSACTION=0,
SP_RUNNING,
- SP_SAFE_POINT,
+ SP_SAFE_POINT_CANNOT_COLLECT,
SP_SAFE_POINT_CAN_COLLECT,
};
enum {
diff --git a/c7/stm/nursery.c b/c7/stm/nursery.c
--- a/c7/stm/nursery.c
+++ b/c7/stm/nursery.c
@@ -25,6 +25,7 @@
/************************************************************/
+
static union {
struct {
uint64_t used; /* number of bytes from the nursery used so far */
@@ -32,6 +33,10 @@
char reserved[64];
} nursery_ctl __attribute__((aligned(64)));
+static uint64_t requested_minor_collections = 0;
+static uint64_t completed_minor_collections = 0;
+
+
/************************************************************/
static void setup_nursery(void)
@@ -50,32 +55,142 @@
}
+/************************************************************/
+
+
+static void minor_collection(void)
+{
+ fprintf(stderr, "minor_collection\n");
+ abort(); //...;
+
+ assert(requested_minor_collections == completed_minor_collections + 1);
+ completed_minor_collections += 1;
+ nursery_ctl.used = 0;
+}
+
+
+static void sync_point_for_collection(void)
+{
+ mutex_lock();
+
+ STM_PSEGMENT->safe_point = SP_SAFE_POINT_CAN_COLLECT;
+
+ restart:
+ if (requested_minor_collections == completed_minor_collections) {
+ if (nursery_ctl.used < NURSERY_SIZE)
+ goto exit;
+
+ requested_minor_collections++;
+ }
+
+ /* are all threads in a safe-point? */
+ long i;
+ bool must_wait = false;
+ for (i = 0; i < NB_SEGMENTS; i++) {
+ struct stm_priv_segment_info_s *other_pseg = get_priv_segment(i);
+
+ if (other_pseg->safe_point != SP_NO_TRANSACTION &&
+ other_pseg->safe_point != SP_SAFE_POINT_CAN_COLLECT) {
+ /* segment i is not at a safe point, or at one where
+ collection is not possible (SP_SAFE_POINT_CANNOT_COLLECT) */
+
+ /* we have the mutex here */
+ other_pseg->pub.nursery_section_end = NSE_SIGNAL;
+ must_wait = true;
+ }
+ }
+ if (must_wait) {
+ /* wait until all threads are indeed in a safe-point that allows
+ collection */
+ cond_wait();
+ goto restart;
+ }
+
+ /* now we can run minor collection */
+ minor_collection();
+
+ exit:
+ /* we have the mutex here, and at this point there is no
+ pending requested minor collection, so we simply reset
+ our value of nursery_section_end and return. */
+ STM_SEGMENT->nursery_section_end =
+ STM_PSEGMENT->real_nursery_section_end;
+
+ STM_PSEGMENT->safe_point = SP_RUNNING;
+
+ mutex_unlock();
+}
+
+
+/************************************************************/
+
#define NURSERY_ALIGN(bytes) \
(((bytes) + NURSERY_LINE - 1) & ~(NURSERY_LINE - 1))
static stm_char *allocate_from_nursery(uint64_t bytes)
{
+ /* may collect! */
/* thread-safe; allocate a chunk of memory from the nursery */
bytes = NURSERY_ALIGN(bytes);
- uint64_t p = __sync_fetch_and_add(&nursery_ctl.used, bytes);
- if (p + bytes > NURSERY_SIZE) {
- //major_collection();
- abort();
+ while (1) {
+ uint64_t p = __sync_fetch_and_add(&nursery_ctl.used, bytes);
+ if (LIKELY(p + bytes <= NURSERY_SIZE)) {
+ return (stm_char *)(NURSERY_START + p);
+ }
+ sync_point_for_collection();
}
- return (stm_char *)(NURSERY_START + p);
}
stm_char *_stm_allocate_slowpath(ssize_t size_rounded_up)
{
+ /* may collect! */
+ STM_SEGMENT->nursery_current -= size_rounded_up; /* restore correct val */
+
+ restart:
+ if (UNLIKELY(STM_SEGMENT->nursery_section_end == NSE_SIGNAL)) {
+
+ /* If nursery_section_end was set to NSE_SIGNAL by another thread,
+ we end up here as soon as we try to call stm_allocate(). */
+ sync_point_for_collection();
+
+ /* Once the sync point is done, retry. */
+ goto restart;
+ }
+
if (size_rounded_up < MEDIUM_OBJECT) {
- /* This is a small object. The current section is simply full.
+ /* This is a small object. We first try to check if the current
+ section really doesn't fit the object; maybe all we were called
+ for was the sync point above */
+ stm_char *p1 = STM_SEGMENT->nursery_current;
+ stm_char *end1 = p1 + size_rounded_up;
+ if ((uintptr_t)end1 <= STM_PSEGMENT->real_nursery_section_end) {
+ /* fits */
+ STM_SEGMENT->nursery_current = end1;
+ return p1;
+ }
+
+ /* Otherwise, the current section is really full.
Allocate the next section and initialize it with zeroes. */
stm_char *p = allocate_from_nursery(NURSERY_SECTION_SIZE);
+ STM_SEGMENT->nursery_current = p + size_rounded_up;
+
+ /* Set nursery_section_end, but carefully: another thread may
+ have forced it to be equal to NSE_SIGNAL. */
+ uintptr_t end = (uintptr_t)p + NURSERY_SECTION_SIZE;
+
+ if (UNLIKELY(!__sync_bool_compare_and_swap(
+ &STM_SEGMENT->nursery_section_end,
+ STM_PSEGMENT->real_nursery_section_end,
+ end))) {
+ assert(STM_SEGMENT->nursery_section_end == NSE_SIGNAL);
+ goto restart;
+ }
+
+ STM_PSEGMENT->real_nursery_section_end = end;
+
memset(REAL_ADDRESS(STM_SEGMENT->segment_base, p), 0,
NURSERY_SECTION_SIZE);
- STM_SEGMENT->nursery_current = p + size_rounded_up;
- STM_SEGMENT->nursery_section_end = (uintptr_t)p + NURSERY_SECTION_SIZE;
/* Also fill the corresponding creation markers with 0xff. */
set_creation_markers(p, NURSERY_SECTION_SIZE,
@@ -109,9 +224,18 @@
c = NURSERY_ALIGN(c);
STM_SEGMENT->nursery_current = (stm_char *)c;
- uint64_t size = STM_SEGMENT->nursery_section_end - c;
+ uint64_t size = STM_PSEGMENT->real_nursery_section_end - c;
if (size > 0) {
set_creation_markers((stm_char *)c, size,
CM_CURRENT_TRANSACTION_IN_NURSERY);
}
}
+
+#ifdef STM_TESTS
+void _stm_set_nursery_free_count(uint64_t free_count)
+{
+ assert(free_count == NURSERY_ALIGN(free_count));
+ assert(nursery_ctl.used <= NURSERY_SIZE - free_count);
+ nursery_ctl.used = NURSERY_SIZE - free_count;
+}
+#endif
diff --git a/c7/stm/nursery.h b/c7/stm/nursery.h
--- a/c7/stm/nursery.h
+++ b/c7/stm/nursery.h
@@ -1,2 +1,4 @@
+
+#define NSE_SIGNAL 1
static void align_nursery_at_transaction_start(void);
diff --git a/c7/stm/pages.c b/c7/stm/pages.c
--- a/c7/stm/pages.c
+++ b/c7/stm/pages.c
@@ -8,7 +8,7 @@
/* call remap_file_pages() to make all pages in the
range(pagenum, pagenum+count) refer to the same
physical range of pages from segment 0 */
- long i;
+ uintptr_t i;
for (i = 1; i < NB_SEGMENTS; i++) {
char *segment_base = get_segment_base(i);
int res = remap_file_pages(segment_base + pagenum * 4096UL,
diff --git a/c7/stm/sync.c b/c7/stm/sync.c
--- a/c7/stm/sync.c
+++ b/c7/stm/sync.c
@@ -67,6 +67,9 @@
static inline void mutex_unlock(void)
{
+ assert(STM_PSEGMENT->safe_point == SP_NO_TRANSACTION ||
+ STM_PSEGMENT->safe_point == SP_RUNNING);
+
if (UNLIKELY(pthread_mutex_unlock(&sync_ctl.global_mutex) != 0)) {
perror("pthread_mutex_unlock");
abort();
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -62,7 +62,8 @@
int segment_num;
char *segment_base;
stm_char *nursery_current;
- uintptr_t nursery_section_end;
+ uintptr_t nursery_section_end; /* forced to 1 by
+ sync_all_threads_for_collection() */
struct stm_thread_local_s *running_thread;
stm_jmpbuf_t *jmpbuf_ptr;
};
@@ -96,6 +97,7 @@
void _stm_large_dump(void);
void _stm_start_safe_point(void);
void _stm_stop_safe_point(void);
+void _stm_set_nursery_free_count(uint64_t free_count);
#endif
#define _STM_GCFLAG_WRITE_BARRIER_CALLED 0x80
diff --git a/c7/test/support.py b/c7/test/support.py
--- a/c7/test/support.py
+++ b/c7/test/support.py
@@ -69,6 +69,8 @@
void _stm_start_safe_point(void);
bool _check_stop_safe_point(void);
+
+void _stm_set_nursery_free_count(uint64_t free_count);
""")
diff --git a/c7/test/test_nursery.py b/c7/test/test_nursery.py
--- a/c7/test/test_nursery.py
+++ b/c7/test/test_nursery.py
@@ -49,3 +49,15 @@
self.commit_transaction()
assert stm_creation_marker(lp1) == 0
assert stm_creation_marker(lp2) == 0
+
+ def test_nursery_full(self):
+ lib._stm_set_nursery_free_count((SOME_MEDIUM_SIZE + 255) & ~255)
+ self.push_root_no_gc()
+ self.start_transaction()
+ lp1 = stm_allocate(SOME_MEDIUM_SIZE)
+ self.pop_root()
+ #
+ self.push_root(lp1)
+ lp2 = stm_allocate(16)
+ lp1b = self.pop_root()
+ assert lp1b != lp1 # collection occurred
More information about the pypy-commit
mailing list