[pypy-commit] stmgc default: fix possible races for minor collections that look at possibly locked, global
Raemi
noreply at buildbot.pypy.org
Thu Nov 21 13:23:05 CET 2013
Author: Remi Meier <remi.meier at gmail.com>
Branch:
Changeset: r551:6e5022b6107e
Date: 2013-11-21 13:22 +0100
http://bitbucket.org/pypy/stmgc/changeset/6e5022b6107e/
Log: fix possible races for minor collections that look at possibly
locked, global objects
diff --git a/c4/et.h b/c4/et.h
--- a/c4/et.h
+++ b/c4/et.h
@@ -140,7 +140,8 @@
#define SPLP_LOCKED_INFLIGHT 1
#define SPLP_LOCKED_VALIDATE 2
#define SPLP_LOCKED_COMMIT 3
-#define SPINLOOP_REASONS 4
+#define SPLP_LOCKED_COLLECT 4
+#define SPINLOOP_REASONS 5
/* this struct contains thread-local data that may be occasionally
* accessed by a foreign thread and that must stay around after the
diff --git a/c4/nursery.c b/c4/nursery.c
--- a/c4/nursery.c
+++ b/c4/nursery.c
@@ -55,6 +55,9 @@
|| *d->nursery_current_ref == d->nursery_end);
stm_free(d->nursery_base);
+ assert(d->public_with_young_copy.size == 0);
+ assert(d->old_objects_to_trace.size == 0);
+ assert(d->young_weakrefs.size == 0);
gcptrlist_delete(&d->old_objects_to_trace);
gcptrlist_delete(&d->public_with_young_copy);
gcptrlist_delete(&d->young_weakrefs);
@@ -281,7 +284,16 @@
/* ignore stub if it is outdated, because then the transaction
will abort (or has been aborted long ago) */
- revision_t w = ACCESS_ONCE(S->h_revision);
+ revision_t w;
+
+ retry:
+ w = ACCESS_ONCE(S->h_revision);
+ if (!IS_POINTER(w) && w >= LOCKED) {
+ /* check again when unlocked */
+ SpinLoop(SPLP_LOCKED_COLLECT);
+ goto retry;
+ }
+
if ((w & 3) != 2) {
/* P has a ptr in h_revision, but this object is not a stub
with a protected pointer. It has likely been the case
@@ -335,6 +347,7 @@
*/
long i, size = d->public_with_young_copy.size;
gcptr *items = d->public_with_young_copy.items;
+ revision_t v;
for (i = 0; i < size; i++) {
gcptr P = items[i];
@@ -342,7 +355,7 @@
assert(P->h_tid & GCFLAG_OLD);
assert(P->h_tid & GCFLAG_PUBLIC_TO_PRIVATE);
- revision_t v = ACCESS_ONCE(P->h_revision);
+ v = ACCESS_ONCE(P->h_revision);
wlog_t *item;
G2L_FIND(d->public_to_private, P, item, goto not_in_public_to_private);
@@ -363,10 +376,19 @@
item->addr, item->val));
assert(_stm_is_private(item->val));
visit_if_young(&item->val);
+ assert(item->val->h_tid & GCFLAG_OLD);
continue;
not_in_public_to_private:
+ /* re-read because of possible spinloop */
+ v = ACCESS_ONCE(P->h_revision);
+
if (!IS_POINTER(v)) {
+ if (v >= LOCKED) {
+ /* check again when unlocked */
+ SpinLoop(SPLP_LOCKED_COLLECT);
+ goto not_in_public_to_private;
+ }
/* P is neither a key in public_to_private nor outdated.
It must come from an older transaction that aborted.
Nothing to do now.
More information about the pypy-commit
mailing list