Author: Armin Rigo <[email protected]>
Branch: c7-refactor
Changeset: r737:c773165c8774
Date: 2014-02-14 19:01 +0100
http://bitbucket.org/pypy/stmgc/changeset/c773165c8774/
Log: Copy the complete logic for _stm_write_slowpath()
diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -2,20 +2,60 @@
# error "must be compiled via stmgc.c"
#endif
+#include <unistd.h>
+
static uint8_t write_locks[READMARKER_END - READMARKER_START];
+static void teardown_core(void)
+{
+ memset(write_locks, 0, sizeof(write_locks));
+}
+
+
+static void contention_management(uint8_t current_lock_owner)
+{
+ /* A simple contention manager. Called when we do stm_write()
+ on an object, but some other thread already holds the write
+ lock on the same object. */
+
+ /* By construction it should not be possible that the owner
+ of the object is precisely us */
+ assert(current_lock_owner != STM_PSEGMENT->write_lock_num);
+
+ /* Who should abort here: this thread, or the other thread? */
+ struct stm_priv_segment_info_s* other_pseg;
+ other_pseg = get_priv_segment(current_lock_owner - 1);
+ assert(other_pseg->write_lock_num == current_lock_owner);
+
+ if ((STM_PSEGMENT->approximate_start_time <
+ other_pseg->approximate_start_time) || is_inevitable()) {
+ /* we are the thread that must succeed */
+ other_pseg->need_abort = 1;
+ _stm_start_safe_point(0);
+ /* XXX: not good, maybe should be signalled by other thread */
+ usleep(1);
+ _stm_stop_safe_point(0);
+ /* done, will retry */
+ }
+ else {
+ /* we are the thread that must abort */
+ stm_abort_transaction();
+ }
+}
+
void _stm_write_slowpath(object_t *obj)
{
assert(_running_transaction());
LIST_APPEND(STM_PSEGMENT->old_objects_to_trace, obj);
- obj->stm_flags |= GCFLAG_WRITE_BARRIER_CALLED;
/* for old objects from the same transaction, we are done now */
- if (obj_from_same_transaction(obj))
+ if (obj_from_same_transaction(obj)) {
+ obj->stm_flags |= GCFLAG_WRITE_BARRIER_CALLED;
return;
+ }
/* otherwise, we need to privatize the pages containing the object,
if they are still SHARED_PAGE. The common case is that there is
@@ -28,8 +68,27 @@
pages_privatize(((uintptr_t)obj) / 4096UL, 1);
}
- //... write_locks
+ /* claim the write-lock for this object */
+ do {
+ uintptr_t lock_idx = (((uintptr_t)obj) >> 4) - READMARKER_START;
+ uint8_t lock_num = STM_PSEGMENT->write_lock_num;
+ uint8_t prev_owner;
+ prev_owner = __sync_val_compare_and_swap(&write_locks[lock_idx],
+ 0, lock_num);
+
+ /* if there was no lock-holder, we are done */
+ if (LIKELY(prev_owner == 0))
+ break;
+
+ /* otherwise, call the contention manager, and then possibly retry */
+ contention_management(prev_owner);
+ } while (1);
+
+ /* add the write-barrier-already-called flag ONLY if we succeeded in
+ getting the write-lock */
stm_read(obj);
+ obj->stm_flags |= GCFLAG_WRITE_BARRIER_CALLED;
+ LIST_APPEND(STM_PSEGMENT->modified_objects, obj);
}
static void reset_transaction_read_version(void)
diff --git a/c7/stm/core.h b/c7/stm/core.h
--- a/c7/stm/core.h
+++ b/c7/stm/core.h
@@ -54,6 +54,10 @@
struct stm_priv_segment_info_s {
struct stm_segment_info_s pub;
struct list_s *old_objects_to_trace;
+ struct list_s *modified_objects;
+ uint64_t approximate_start_time;
+ uint8_t write_lock_num;
+ uint8_t need_abort;
};
static char *stm_object_pages;
@@ -88,3 +92,9 @@
static inline bool obj_from_same_transaction(object_t *obj) {
return ((stm_creation_marker_t *)(((uintptr_t)obj) >> 8))->cm != 0;
}
+
+static inline bool is_inevitable(void) {
+ return STM_SEGMENT->jmpbuf_ptr == NULL;
+}
+
+static void teardown_core(void);
diff --git a/c7/stm/setup.c b/c7/stm/setup.c
--- a/c7/stm/setup.c
+++ b/c7/stm/setup.c
@@ -60,9 +60,12 @@
PROT_NONE);
struct stm_priv_segment_info_s *pr = get_priv_segment(i);
+ assert(i + 1 < 256);
+ pr->write_lock_num = i + 1;
pr->pub.segment_num = i;
pr->pub.segment_base = segment_base;
pr->old_objects_to_trace = list_create();
+ pr->modified_objects = list_create();
}
/* Make the nursery pages shared. The other pages are
@@ -100,6 +103,7 @@
memset(flag_page_private, 0, sizeof(flag_page_private));
+ teardown_core();
teardown_sync();
}
diff --git a/c7/stm/sync.c b/c7/stm/sync.c
--- a/c7/stm/sync.c
+++ b/c7/stm/sync.c
@@ -8,6 +8,7 @@
struct {
sem_t semaphore;
uint8_t in_use[NB_SEGMENTS + 1]; /* 1 if running a pthread */
+ uint64_t global_time; /* approximate */
};
char reserved[64];
} segments_ctl __attribute__((aligned(64)));
@@ -69,6 +70,9 @@
exit:
assert(STM_SEGMENT->running_thread == NULL);
STM_SEGMENT->running_thread = tl;
+
+ /* global_time is approximate -> no synchronization required */
+ STM_PSEGMENT->approximate_start_time = ++segments_ctl.global_time;
}
static void release_thread_segment(stm_thread_local_t *tl)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit