[pypy-commit] stmgc c8-gil-like: progress
arigo
noreply at buildbot.pypy.org
Wed Jun 10 22:50:16 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: c8-gil-like
Changeset: r1799:370c663b47f6
Date: 2015-06-10 22:50 +0200
http://bitbucket.org/pypy/stmgc/changeset/370c663b47f6/
Log: progress
diff --git a/c8/stm/detach.c b/c8/stm/detach.c
--- a/c8/stm/detach.c
+++ b/c8/stm/detach.c
@@ -3,26 +3,20 @@
#endif
-/* _stm_detached_inevitable_from_thread is:
+/* _stm_detached_inevitable_segnum is:
- - 0: there is no inevitable transaction, or it is not detached
+ - -1: there is no inevitable transaction, or it is not detached
- - a stm_thread_local_t pointer: this thread-local has detached its
- own inevitable transaction, and might concurrently reattach to it
- at any time
-
- - DETACHED_AND_FETCHED: another thread ran
- synchronize_all_threads(), so in order to reattach, the detaching
- thread must first go through s_mutex_lock()/s_mutex_unlock().
+ - in range(1, NB_SEGMENTS): an inevitable transaction belongs to
+ the segment and was detached. It might concurrently be
+ reattached at any time, with an XCHG (__sync_lock_test_and_set).
*/
-#define DETACHED_AND_FETCHED 1
-
-volatile uintptr_t _stm_detached_inevitable_from_thread;
+volatile int _stm_detached_inevitable_seg_num;
static void setup_detach(void)
{
- _stm_detached_inevitable_from_thread = 0;
+ _stm_detached_inevitable_seg_num = -1;
}
@@ -39,85 +33,24 @@
}
}
-static struct stm_priv_segment_info_s *detached_and_fetched(void)
+void _stm_reattach_transaction(int old, stm_thread_local_t *tl)
{
- long i;
- struct stm_priv_segment_info_s *result = NULL;
- for (i = 1; i < NB_SEGMENTS; i++) {
- if (get_priv_segment(i)->safe_point == SP_RUNNING_DETACHED_FETCHED) {
- assert(result == NULL);
- result = get_priv_segment(i);
- }
- }
- assert(result != NULL);
- return result;
-}
-
-void _stm_reattach_transaction(uintptr_t old, stm_thread_local_t *tl)
-{
- if (old == 0) {
+ if (old == -1) {
/* there was no detached inevitable transaction */
_stm_start_transaction(tl);
- return;
}
+ else {
+ /* We took over the inevitable transaction originally detached
+ from a different segment. We have to fix the %gs register if
+ it is incorrect.
+ */
+ tl->last_associated_segment_num = old;
+ ensure_gs_register(old);
+ assert(STM_PSEGMENT->transaction_state == TS_INEVITABLE);
+ STM_SEGMENT->running_thread = tl;
- if (old == DETACHED_AND_FETCHED) {
- /* The detached transaction was fetched; wait until the s_mutex_lock
- is free. The fetched transaction can only be reattached by the
- code here; there should be no risk of its state changing while
- we wait.
- */
- struct stm_priv_segment_info_s *pseg;
- s_mutex_lock();
- pseg = detached_and_fetched();
- pseg->safe_point = SP_RUNNING;
- old = (uintptr_t)pseg->running_thread;
- s_mutex_unlock();
+ stm_safe_point();
}
-
- /* We took over the inevitable transaction originally detached
- from a different thread. We have to fix the %gs register if
- it is incorrect.
- */
- ensure_gs_register(tl->last_associated_segment_num);
- assert(STM_SEGMENT->running_thread == (stm_thread_local_t *)old);
- STM_SEGMENT->running_thread = tl;
-
- stm_safe_point();
-}
-
-static bool fetch_detached_transaction(void)
-{
- /* returns True if there is a detached transaction; afterwards, it
- is not necessary to call fetch_detached_transaction() again
- regularly.
- */
- uintptr_t old;
- stm_thread_local_t *tl;
- struct stm_priv_segment_info_s *pseg;
- assert(_has_mutex_here);
-
- restart:
- old = _stm_detached_inevitable_from_thread;
- if (old == 0)
- return false;
- if (old < NB_SEGMENTS) {
- /* we have the mutex here, so this fetched detached transaction
- cannot get reattached in parallel */
- assert(get_priv_segment(old)->safe_point ==
- SP_RUNNING_DETACHED_FETCHED);
- return true;
- }
-
- if (!__sync_bool_compare_and_swap(&_stm_detached_inevitable_from_thread,
- old, old + 1))
- goto restart;
-
- tl = (stm_thread_local_t *)old;
- pseg = get_priv_segment(tl->last_associated_segment_num);
- assert(pseg->safe_point == SP_RUNNING);
- pseg->safe_point = SP_RUNNING_DETACHED_FETCHED;
- return true;
}
void stm_force_transaction_break(stm_thread_local_t *tl)
@@ -127,16 +60,32 @@
_stm_start_transaction(tl);
}
-static void commit_own_inevitable_detached_transaction(stm_thread_local_t *tl)
+static int fetch_detached_transaction(void)
{
- uintptr_t cur = _stm_detached_inevitable_from_thread;
- if ((cur & ~1) == (uintptr_t)tl) {
- stm_enter_transactional_zone(tl);
- _stm_commit_transaction();
- }
+ int cur = _stm_detached_inevitable_seg_num;
+ if (cur != -1)
+ cur = __sync_lock_test_and_set( /* XCHG */
+ &_stm_detached_inevitable_seg_num, -1);
+ return cur;
}
-REWRITE:. we need a function to grab and commit the detached inev transaction
-anyway. So kill the special values of _stm_detached_inevitable_from_thread.
-And call that function from core.c when we wait for the inev transaction to
-finish
+static void commit_fetched_detached_transaction(int segnum)
+{
+ /* Here, 'seg_num' is the segment that contains the detached
+ inevitable transaction from fetch_detached_transaction(),
+ probably belonging to an unrelated thread. We fetched it,
+ which means that nobody else can concurrently fetch it now, but
+ everybody will see that there is still a concurrent inevitable
+ transaction. This should guarantee there are not race
+ conditions.
+ */
+ assert(segnum > 0);
+
+ int mysegnum = STM_SEGMENT->segment_num;
+ ensure_gs_register(segnum);
+
+ assert(STM_PSEGMENT->transaction_state == TS_INEVITABLE);
+ _stm_commit_transaction(); /* can't abort */
+
+ ensure_gs_register(mysegnum);
+}
diff --git a/c8/stm/detach.h b/c8/stm/detach.h
--- a/c8/stm/detach.h
+++ b/c8/stm/detach.h
@@ -1,4 +1,4 @@
static void setup_detach(void);
-static bool fetch_detached_transaction(void);
-static void commit_own_inevitable_detached_transaction(stm_thread_local_t *tl);
+static int fetch_detached_transaction(void);
+static void commit_fetched_detached_transaction(int segnum);
diff --git a/c8/stm/setup.c b/c8/stm/setup.c
--- a/c8/stm/setup.c
+++ b/c8/stm/setup.c
@@ -264,9 +264,6 @@
void stm_unregister_thread_local(stm_thread_local_t *tl)
{
- /* If we own the detached inevitable transaction, commit it now */
- commit_own_inevitable_detached_transaction(tl);
-
s_mutex_lock();
assert(tl->prev != NULL);
assert(tl->next != NULL);
diff --git a/c8/stm/sync.c b/c8/stm/sync.c
--- a/c8/stm/sync.c
+++ b/c8/stm/sync.c
@@ -66,6 +66,7 @@
static void ensure_gs_register(long segnum)
{
+ /* XXX use this instead of set_gs_register() in many places */
if (STM_SEGMENT->segment_num != segnum) {
set_gs_register(get_segment_base(segnum));
assert(STM_SEGMENT->segment_num == segnum);
@@ -392,18 +393,7 @@
static void synchronize_all_threads(enum sync_type_e sync_type)
{
- /* Regularly, we try fetch_detached_transaction(), which, if there
- is a detached inevitable transaction, will take it out of the
- global variable that reattaching tries to read, and put it in
- our local 'detached_tl' variable. The status of such a fetched
- detached transaction is temporarily set from SP_RUNNING to
- SP_RUNNING_DETACHED_FETCHED, which is not counted any more by
- count_other_threads_sp_running(). 'detached_tl' will be copied
- back into '_stm_detached_inevitable_from_thread' by the other
- thread running _stm_reattach_transaction(), later.
- */
- bool detached = fetch_detached_transaction();
-
+ restart:
assert(_has_mutex());
enter_safe_point_if_requested();
@@ -414,7 +404,6 @@
enter_safe_point_if_requested() above.
*/
if (UNLIKELY(globally_unique_transaction)) {
- assert(!detached);
assert(count_other_threads_sp_running() == 0);
return;
}
@@ -424,18 +413,17 @@
/* If some other threads are SP_RUNNING, we cannot proceed now.
Wait until all other threads are suspended. */
while (count_other_threads_sp_running() > 0) {
+
+ int detached = fetch_detached_transaction();
+ if (detached >= 0) {
+ remove_requests_for_safe_point(); /* => C_REQUEST_REMOVED */
+ commit_fetched_detached_transaction(detached);
+ goto restart;
+ }
+
STM_PSEGMENT->safe_point = SP_WAIT_FOR_C_AT_SAFE_POINT;
- if (!detached) {
- do {
- detached = fetch_detached_transaction();
- if (detached)
- break;
- } while (!cond_wait_timeout(C_AT_SAFE_POINT, 0.00001));
- /* every 10 microsec, try again fetch_detached_transaction() */
- }
- else {
- cond_wait(C_AT_SAFE_POINT);
- }
+ cond_wait_timeout(C_AT_SAFE_POINT, 0.00001);
+ /* every 10 microsec, try again fetch_detached_transaction() */
STM_PSEGMENT->safe_point = SP_RUNNING;
if (must_abort()) {
diff --git a/c8/stmgc.h b/c8/stmgc.h
--- a/c8/stmgc.h
+++ b/c8/stmgc.h
@@ -84,15 +84,16 @@
object_t *_stm_allocate_slowpath(ssize_t);
object_t *_stm_allocate_external(ssize_t);
-extern volatile uintptr_t _stm_detached_inevitable_from_thread;
+extern volatile int _stm_detached_inevitable_seg_num;
long _stm_start_transaction(stm_thread_local_t *tl);
void _stm_commit_transaction(void);
void _stm_leave_noninevitable_transactional_zone(void);
-#define _stm_detach_inevitable_transaction(tl) do { \
- write_fence(); \
- _stm_detached_inevitable_from_thread = (uintptr_t)(tl); \
+#define _stm_detach_inevitable_transaction(tl) do { \
+ write_fence(); \
+ assert((tl)->last_associated_segment_num == STM_SEGMENT->segment_num); \
+ _stm_detached_inevitable_seg_num = STM_SEGMENT->segment_num; \
} while (0)
-void _stm_reattach_transaction(uintptr_t old, stm_thread_local_t *tl);
+void _stm_reattach_transaction(int old, stm_thread_local_t *tl);
void _stm_become_inevitable(const char*);
void _stm_collectable_safe_point(void);
@@ -420,9 +421,11 @@
transactions.
*/
static inline void stm_enter_transactional_zone(stm_thread_local_t *tl) {
- uintptr_t old = __sync_lock_test_and_set( /* XCHG */
- &_stm_detached_inevitable_from_thread, 0);
- if (old != (uintptr_t)(tl))
+ int old = __sync_lock_test_and_set( /* XCHG */
+ &_stm_detached_inevitable_seg_num, -1);
+ if (old == tl->last_associated_segment_num)
+ STM_SEGMENT->running_thread = tl;
+ else
_stm_reattach_transaction(old, tl);
}
static inline void stm_leave_transactional_zone(stm_thread_local_t *tl) {
@@ -455,7 +458,7 @@
if (!stm_is_inevitable())
_stm_become_inevitable(msg);
/* now, we're running the inevitable transaction, so: */
- assert(_stm_detached_inevitable_from_thread == 0);
+ assert(_stm_detached_inevitable_seg_num == -1);
}
/* Forces a safe-point if needed. Normally not needed: this is
More information about the pypy-commit
mailing list