Author: Armin Rigo <[email protected]>
Branch:
Changeset: r87:391c68e20cf5
Date: 2013-06-09 21:05 +0200
http://bitbucket.org/pypy/stmgc/changeset/391c68e20cf5/
Log: Implement most of the document, found a few issues to work on
diff --git a/README.txt b/README.txt
--- a/README.txt
+++ b/README.txt
@@ -7,13 +7,13 @@
This is a C library that combines a GC with STM capabilities.
It is meant to be a general library that can be used in C programs.
-The library interface is in "c3/stmgc.h".
+The library interface is in "c4/stmgc.h".
-The file "c3/doc-stmgc.txt" contains a high-level overview followed by
-more detailled explanations.
+The file "c4/doc-objects.txt" contains some low-level explanations.
-A demo program can be found in "c3/demo1.c", but the code so far is
-outdated (it doesn't follow what c3/doc-stmgc describes).
+Run tests with "py.test".
+
+A demo program will be found in "c4/demo1.c" (not there yet).
It can be built with "make debug-demo1" or "make build-demo1".
The plan is to use this C code directly with PyPy, and not write
diff --git a/c4/doc-objects.txt b/c4/doc-objects.txt
--- a/c4/doc-objects.txt
+++ b/c4/doc-objects.txt
@@ -219,13 +219,6 @@
(This occurs during commit, when we have got the collection_lock.)
-public_to_private:
-
- write GT into the private object
-
- make a stub with h_revision = private object | 2
-
- after a CPU write barrier, make the public h_revision to point to the stub
private_from_protected:
@@ -233,6 +226,8 @@
set P->h_revision to GT
+ remove GCFLAG_PRIVATE_FROM_PROTECTED from P
+
if B has GCFLAG_PUBLIC: it has been stolen
if it has been modified: conflict, abort transaction
@@ -242,3 +237,11 @@
else:
possibly free B now, it's not used any more
+
+public_to_private:
+
+ write GT into the private object
+
+ make a stub with h_revision = private object | 2
+
+ after a CPU write barrier, make the public h_revision to point to the stub
diff --git a/c4/et.c b/c4/et.c
--- a/c4/et.c
+++ b/c4/et.c
@@ -66,11 +66,16 @@
gcptr P = G;
revision_t v;
- if (UNLIKELY(d->public_descriptor->stolen_objects.size > 0))
+ if (P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED)
{
- spinlock_acquire(d->public_descriptor->collection_lock, 'N');
- stm_normalize_stolen_objects(d->public_descriptor);
- spinlock_release(d->public_descriptor->collection_lock);
+ private_from_protected:
+ /* check P->h_revision->h_revision: if a pointer, then it means
+ the backup copy has been stolen into a public object and then
+ modified by some other thread. Abort. */
+ if (!(((gcptr)P->h_revision)->h_revision & 1))
+ AbortTransaction(ABRT_STOLEN_MODIFIED);
+
+ goto add_in_recent_reads_cache;
}
if (P->h_tid & GCFLAG_PUBLIC)
@@ -142,8 +147,10 @@
}
register_in_list_of_read_objects:
+ gcptrlist_insert(&d->list_of_read_objects, P);
+
+ add_in_recent_reads_cache:
fxcache_add(&d->recent_reads_cache, P);
- gcptrlist_insert(&d->list_of_read_objects, P);
return P;
follow_stub:;
@@ -159,6 +166,12 @@
"private\n", G, P);
return P;
}
+ else if (P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED)
+ {
+ fprintf(stderr, "read_barrier: %p -> %p handle "
+ "private_from_protected\n", G, P);
+ goto private_from_protected;
+ }
else if (FXCACHE_AT(P) == P)
{
fprintf(stderr, "read_barrier: %p -> %p handle "
@@ -307,24 +320,15 @@
assert(!(P->h_tid & GCFLAG_PUBLIC_TO_PRIVATE));
assert(!(P->h_tid & GCFLAG_BACKUP_COPY));
assert(!(P->h_tid & GCFLAG_STUB));
+ assert(!(P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED));
- if (P->h_revision & 1)
- {
- /* does not have a backup yet */
- B = stmgc_duplicate(P);
- B->h_tid |= GCFLAG_BACKUP_COPY;
- }
- else
- {
- B = (gcptr)P->h_revision;
- assert(B->h_tid & GCFLAG_BACKUP_COPY);
- size_t size = stmcb_size(P);
- memcpy(B + 1, P + 1, size - sizeof(*B));
- }
- assert(B->h_tid & GCFLAG_BACKUP_COPY);
+ B = stmgc_duplicate(P);
+ B->h_tid |= GCFLAG_BACKUP_COPY;
- gcptrlist_insert2(&d->public_descriptor->active_backup_copies, P, B);
- P->h_revision = stm_private_rev_num;
+ P->h_tid |= GCFLAG_PRIVATE_FROM_PROTECTED;
+ P->h_revision = (revision_t)B;
+
+ gcptrlist_insert(&d->private_from_protected, P);
spinlock_release(d->public_descriptor->collection_lock);
return P;
@@ -333,21 +337,20 @@
static gcptr LocalizePublic(struct tx_descriptor *d, gcptr R)
{
assert(R->h_tid & GCFLAG_PUBLIC);
- if (R->h_tid & GCFLAG_PUBLIC_TO_PRIVATE)
- {
- wlog_t *entry;
- gcptr L;
- G2L_FIND(d->public_to_private, R, entry, goto not_found);
- L = entry->val;
- assert(L->h_revision == stm_private_rev_num); /* private object */
- return L;
- }
+
+#ifdef _GC_DEBUG
+ wlog_t *entry;
+ G2L_FIND(d->public_to_private, R, entry, goto not_found);
+ assert(!"R is already in public_to_private");
+ not_found:
+#endif
+
R->h_tid |= GCFLAG_PUBLIC_TO_PRIVATE;
- not_found:;
gcptr L = stmgc_duplicate(R);
assert(!(L->h_tid & GCFLAG_BACKUP_COPY));
assert(!(L->h_tid & GCFLAG_STUB));
+ assert(!(L->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED));
L->h_tid &= ~(GCFLAG_OLD |
GCFLAG_VISITED |
GCFLAG_PUBLIC |
@@ -369,36 +372,31 @@
gcptr stm_WriteBarrier(gcptr P)
{
- gcptr W;
+ gcptr R, W;
struct tx_descriptor *d = thread_descriptor;
assert(d->active >= 1);
- retry:
- P = stm_read_barrier(P);
+ R = stm_read_barrier(P);
- if (P->h_tid & GCFLAG_PUBLIC)
- W = LocalizePublic(d, P);
+ if (R->h_revision == stm_private_rev_num ||
+ (R->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED))
+ return R;
+
+ if (R->h_tid & GCFLAG_PUBLIC)
+ W = LocalizePublic(d, R);
else
- W = LocalizeProtected(d, P);
+ W = LocalizeProtected(d, R);
- fprintf(stderr, "write_barrier: %p -> %p\n", P, W);
+ fprintf(stderr, "write_barrier: %p -> %p -> %p\n", P, R, W);
return W;
}
-gcptr stm_get_backup_copy(long index)
+gcptr stm_get_private_from_protected(long index)
{
- struct tx_public_descriptor *pd = thread_descriptor->public_descriptor;
- if (index < gcptrlist_size(&pd->active_backup_copies))
- return pd->active_backup_copies.items[index];
- return NULL;
-}
-
-gcptr stm_get_stolen_obj(long index)
-{
- struct tx_public_descriptor *pd = thread_descriptor->public_descriptor;
- if (index < gcptrlist_size(&pd->stolen_objects))
- return pd->stolen_objects.items[index];
+ struct tx_descriptor *d = thread_descriptor;
+ if (index < gcptrlist_size(&d->private_from_protected))
+ return d->private_from_protected.items[index];
return NULL;
}
@@ -570,9 +568,9 @@
}
gcptrlist_clear(&d->list_of_read_objects);
- gcptrlist_clear(&d->public_descriptor->active_backup_copies);
abort();
- d->public_descriptor->stolen_objects;//XXX clean up
+ gcptrlist_clear(&d->private_from_protected); //XXX clean up
+ abort();
//stmgc_abort_transaction(d);
fprintf(stderr,
@@ -636,14 +634,15 @@
d->start_real_time.tv_nsec = -1;
}
assert(d->list_of_read_objects.size == 0);
+ assert(d->private_from_protected.size == 0);
assert(!g2l_any_entry(&d->public_to_private));
d->count_reads = 1;
fxcache_clear(&d->recent_reads_cache);
#if 0
gcptrlist_clear(&d->undolog);
+ gcptrlist_clear(&d->abortinfo);
#endif
- gcptrlist_clear(&d->abortinfo);
}
void BeginTransaction(jmp_buf* buf)
@@ -819,24 +818,41 @@
}
#endif
-void TurnPrivateWithBackupToProtected(struct tx_descriptor *d,
- revision_t cur_time)
+void CommitPrivateFromProtected(struct tx_descriptor *d, revision_t cur_time)
{
- struct tx_public_descriptor *pd = d->public_descriptor;
- long i, size = pd->active_backup_copies.size;
- gcptr *items = pd->active_backup_copies.items;
+ long i, size = d->private_from_protected.size;
+ gcptr *items = d->private_from_protected.items;
- for (i = 0; i < size; i += 2)
+ for (i = 0; i < size; i++)
{
gcptr P = items[i];
- gcptr B = items[i + 1];
- assert(B->h_tid & GCFLAG_BACKUP_COPY);
- assert(!(B->h_tid & GCFLAG_PUBLIC));
- assert(P->h_revision == stm_private_rev_num);
- B->h_revision = cur_time;
- P->h_revision = (revision_t)B;
+
+ assert(!(P->h_revision & 1)); // "is a pointer"
+ gcptr B = (gcptr)P->h_revision;
+
+ assert(P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED);
+ P->h_tid &= ~GCFLAG_PRIVATE_FROM_PROTECTED;
+ P->h_revision = cur_time;
+
+ if (B->h_tid & GCFLAG_PUBLIC)
+ {
+ /* B was stolen */
+ while (1)
+ {
+ revision_t v = ACCESS_ONCE(B->h_revision);
+ if (!(v & 1)) // "is a pointer", i.e. "was modified"
+ AbortTransaction(ABRT_STOLEN_MODIFIED);
+
+ if (bool_cas(&B->h_revision, v, (revision_t)P))
+ break;
+ }
+ }
+ else
+ {
+ //stm_free(B);
+ }
};
- gcptrlist_clear(&pd->active_backup_copies);
+ gcptrlist_clear(&d->private_from_protected);
}
void CommitTransaction(void)
@@ -846,9 +862,6 @@
assert(d->active >= 1);
spinlock_acquire(d->public_descriptor->collection_lock, 'C'); /*committing*/
- if (d->public_descriptor->stolen_objects.size)
- stm_normalize_stolen_objects(d->public_descriptor);
-
AcquireLocks(d);
if (is_inevitable(d))
@@ -885,6 +898,8 @@
if (!ValidateDuringTransaction(d, 1))
AbortTransaction(ABRT_VALIDATE_COMMIT);
}
+ CommitPrivateFromProtected(d, cur_time);
+
/* we cannot abort any more from here */
d->setjmp_buf = NULL;
gcptrlist_clear(&d->list_of_read_objects);
@@ -895,8 +910,6 @@
"*************************************\n",
(long)cur_time);
- TurnPrivateWithBackupToProtected(d, cur_time);
-
revision_t localrev = stm_private_rev_num;
//UpdateProtectedChainHeads(d, cur_time, localrev);
//smp_wmb();
@@ -1159,12 +1172,12 @@
thread_descriptor = NULL;
g2l_delete(&d->public_to_private);
- assert(d->public_descriptor->active_backup_copies.size == 0);
- gcptrlist_delete(&d->public_descriptor->active_backup_copies);
+ assert(d->private_from_protected.size == 0);
+ gcptrlist_delete(&d->private_from_protected);
gcptrlist_delete(&d->list_of_read_objects);
+#if 0
gcptrlist_delete(&d->abortinfo);
free(d->longest_abort_info);
-#if 0
gcptrlist_delete(&d->undolog);
#endif
diff --git a/c4/et.h b/c4/et.h
--- a/c4/et.h
+++ b/c4/et.h
@@ -62,6 +62,7 @@
#define GCFLAG_NURSERY_MOVED (STM_FIRST_GCFLAG << 6)
#define GCFLAG_BACKUP_COPY (STM_FIRST_GCFLAG << 7) /* debugging */
#define GCFLAG_STUB (STM_FIRST_GCFLAG << 8) /* debugging */
+#define GCFLAG_PRIVATE_FROM_PROTECTED (STM_FIRST_GCFLAG << 9)
/* this value must be reflected in PREBUILT_FLAGS in stmgc.h */
#define GCFLAG_PREBUILT (GCFLAG_VISITED | \
@@ -73,24 +74,25 @@
"VISITED", \
"PUBLIC", \
"PREBUILT_ORIGINAL", \
- "BACKUP_COPY", \
"PUBLIC_TO_PRIVATE", \
"WRITE_BARRIER", \
"NURSERY_MOVED", \
- "STOLEN", \
+ "BACKUP_COPY", \
"STUB", \
+ "PRIVATE_FROM_PROTECTED", \
NULL }
/************************************************************/
#define ABRT_MANUAL 0
#define ABRT_COMMIT 1
-#define ABRT_VALIDATE_INFLIGHT 2
-#define ABRT_VALIDATE_COMMIT 3
-#define ABRT_VALIDATE_INEV 4
-#define ABRT_COLLECT_MINOR 5
-#define ABRT_COLLECT_MAJOR 6
-#define ABORT_REASONS 7
+#define ABRT_STOLEN_MODIFIED 2
+#define ABRT_VALIDATE_INFLIGHT 3
+#define ABRT_VALIDATE_COMMIT 4
+#define ABRT_VALIDATE_INEV 5
+#define ABRT_COLLECT_MINOR 6
+#define ABRT_COLLECT_MAJOR 7
+#define ABORT_REASONS 8
#define SPLP_ABORT 0
#define SPLP_LOCKED_INFLIGHT 1
@@ -105,8 +107,6 @@
revision_t collection_lock;
struct stub_block_s *stub_blocks;
gcptr stub_free_list;
- struct GcPtrList active_backup_copies; /* (P,B) where P=private, B=backup */
- struct GcPtrList stolen_objects; /* (P,Q) where P=priv/prot, Q=public */
revision_t *private_revision_ref;
revision_t free_list_next;
/* xxx gcpage data here */
@@ -135,7 +135,8 @@
unsigned int num_aborts[ABORT_REASONS];
unsigned int num_spinloops[SPINLOOP_REASONS];
struct GcPtrList list_of_read_objects;
- struct GcPtrList abortinfo;
+ //struct GcPtrList abortinfo;
+ struct GcPtrList private_from_protected;
struct G2L public_to_private;
char *longest_abort_info;
long long longest_abort_info_time;
@@ -162,8 +163,7 @@
gcptr stm_RepeatReadBarrier(gcptr);
gcptr stm_WriteBarrier(gcptr);
gcptr _stm_nonrecord_barrier(gcptr, int *);
-gcptr stm_get_backup_copy(long); /* debugging */
-gcptr stm_get_stolen_obj(long); /* debugging */
+gcptr stm_get_private_from_protected(long); /* debugging */
gcptr stm_get_read_obj(long); /* debugging */
gcptr stmgc_duplicate(gcptr);
diff --git a/c4/steal.c b/c4/steal.c
--- a/c4/steal.c
+++ b/c4/steal.c
@@ -54,54 +54,21 @@
goto done; /* un-stubbed while we waited for the lock */
gcptr L = (gcptr)(v - 2);
- revision_t w = L->h_revision;
- if (w == *foreign_pd->private_revision_ref) {
- /* The stub points to a private object L. Because it cannot point
- to "really private" objects, it must mean that L used to be
- a protected object, and it has an attached backed copy.
- XXX find a way to optimize this search, maybe */
- long i, size = foreign_pd->active_backup_copies.size;
- gcptr *items = foreign_pd->active_backup_copies.items;
- for (i = size - 2; ; i -= 2) {
- assert(i >= 0);
- if (items[i] == L)
- break;
- }
- L = items[i + 1];
- assert(L->h_tid & GCFLAG_BACKUP_COPY);
+ if (L->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED) {
+ L = (gcptr)L->h_revision; /* the backup copy */
L->h_tid &= ~GCFLAG_BACKUP_COPY;
}
- else if (L->h_tid & GCFLAG_PUBLIC) {
- /* The stub already points to a public object */
- goto unstub;
- }
- else if (!(w & 1)) {
- /* The stub points to a protected object L which has a backup
- copy attached. Forget the backup copy. */
- w = ((gcptr)w)->h_revision;
- assert(w & 1);
- L->h_revision = w;
- }
- /* turn L into a public object */
+
+ /* change L from protected to public */
L->h_tid |= GCFLAG_PUBLIC;
- unstub:
+ smp_wmb(); /* the following update must occur "after" the flag
+ GCFLAG_PUBLIC was added, for other threads */
+
+ /* update the original P->h_revision to point directly to L */
P->h_revision = (revision_t)L;
done:
spinlock_release(foreign_pd->collection_lock);
}
-
-void stm_normalize_stolen_objects(struct tx_public_descriptor *pd)
-{
- long i, size = pd->stolen_objects.size;
- gcptr *items = pd->stolen_objects.items;
- for (i = 0; i < size; i += 2) {
- gcptr L = items[i];
- gcptr Q = items[i + 1];
- if (L->h_revision == stm_private_rev_num) {
-
- }
- }
-}
diff --git a/c4/stmsync.c b/c4/stmsync.c
--- a/c4/stmsync.c
+++ b/c4/stmsync.c
@@ -87,8 +87,8 @@
gcptr stm_write_barrier(gcptr obj)
{
/* XXX inline in the caller */
- if (UNLIKELY(((obj->h_tid & GCFLAG_WRITE_BARRIER) != 0) |
- (obj->h_revision != stm_private_rev_num)))
+ if (UNLIKELY((obj->h_revision != stm_private_rev_num) &
+ ((obj->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED) == 0)))
obj = stm_WriteBarrier(obj);
return obj;
}
diff --git a/c4/test/support.py b/c4/test/support.py
--- a/c4/test/support.py
+++ b/c4/test/support.py
@@ -68,8 +68,7 @@
void stm_start_sharedlock(void);
void stm_stop_sharedlock(void);
void AbortTransaction(int);
- gcptr stm_get_backup_copy(long index);
- gcptr stm_get_stolen_obj(long index);
+ gcptr stm_get_private_from_protected(long index);
gcptr stm_get_read_obj(long index);
void *STUB_THREAD(gcptr);
@@ -105,6 +104,7 @@
#define GCFLAG_WRITE_BARRIER ...
#define GCFLAG_NURSERY_MOVED ...
#define GCFLAG_STUB ...
+ #define GCFLAG_PRIVATE_FROM_PROTECTED ...
#define ABRT_MANUAL ...
//typedef struct { ...; } page_header_t;
''')
@@ -524,7 +524,8 @@
lib.AbortTransaction(lib.ABRT_MANUAL)
def classify(p):
- private = p.h_revision == lib.get_private_rev_num()
+ private = (p.h_revision == lib.get_private_rev_num() or
+ (p.h_tid & GCFLAG_PRIVATE_FROM_PROTECTED) != 0)
public = (p.h_tid & GCFLAG_PUBLIC) != 0
backup = (p.h_tid & GCFLAG_BACKUP_COPY) != 0
stub = (p.h_tid & GCFLAG_STUB) != 0
@@ -541,34 +542,26 @@
else:
return "protected"
-def list_of_read_objects():
+def _get_full_list(getter):
result = []
index = 0
while 1:
- p = lib.stm_get_read_obj(index)
+ p = getter(index)
if p == ffi.NULL:
break
result.append(p)
index += 1
return result
-def _list2dict(getter):
- result = {}
- index = 0
- while 1:
- p = getter(index)
- if p == ffi.NULL:
- break
- q = getter(index + 1)
- assert q != ffi.NULL
- result[p] = q
- index += 2
- return result
+def list_of_read_objects():
+ return _get_full_list(lib.stm_get_read_obj)
-def backup_copies():
- return _list2dict(lib.stm_get_backup_copy)
-
-def stolen_objs():
- return _list2dict(lib.stm_get_stolen_obj)
+def list_of_private_from_protected():
+ return _get_full_list(lib.stm_get_private_from_protected)
stub_thread = lib.STUB_THREAD
+
+def follow_revision(p):
+ r = p.h_revision
+ assert (r % 4) == 0
+ return ffi.cast("gcptr", r)
diff --git a/c4/test/test_et.py b/c4/test/test_et.py
--- a/c4/test/test_et.py
+++ b/c4/test/test_et.py
@@ -49,8 +49,10 @@
assert classify(p) == "protected"
p2 = lib.stm_write_barrier(p)
assert p2 == p # does not move
- assert p.h_revision == r2
assert classify(p) == "private"
+ pback = follow_revision(p)
+ assert classify(pback) == "backup"
+ assert list_of_private_from_protected() == [p]
def test_get_backup_copy():
p = nalloc(HDR + WORD)
@@ -58,52 +60,19 @@
lib.stm_commit_transaction()
lib.stm_begin_inevitable_transaction()
org_r = p.h_revision
+ assert classify(p) == "protected"
lib.setlong(p, 0, 927122)
- assert p.h_revision == lib.get_private_rev_num()
- pback = backup_copies()[p]
+ assert classify(p) == "private"
+ pback = follow_revision(p)
assert pback and pback != p
assert pback.h_revision == org_r
- assert pback.h_tid == p.h_tid | GCFLAG_BACKUP_COPY
+ assert pback.h_tid == ((p.h_tid & ~GCFLAG_PRIVATE_FROM_PROTECTED) |
+ GCFLAG_BACKUP_COPY)
assert lib.rawgetlong(pback, 0) == 78927812
assert lib.rawgetlong(p, 0) == 927122
assert classify(p) == "private"
assert classify(pback) == "backup"
-def test_protected_with_backup():
- p = nalloc(HDR + WORD)
- lib.setlong(p, 0, 78927812)
- lib.stm_commit_transaction()
- lib.stm_begin_inevitable_transaction()
- lib.setlong(p, 0, 927122)
- pback = backup_copies()[p]
- assert pback != p
- assert p.h_revision == lib.get_private_rev_num()
- lib.stm_commit_transaction()
- lib.stm_begin_inevitable_transaction()
- assert classify(p) == "protected"
- assert classify(pback) == "backup"
- assert ffi.cast("gcptr", p.h_revision) == pback
-
-def test_protected_backup_reused():
- p = nalloc(HDR + WORD)
- lib.setlong(p, 0, 78927812)
- lib.stm_commit_transaction()
- lib.stm_begin_inevitable_transaction()
- lib.setlong(p, 0, 927122)
- pback = backup_copies()[p]
- assert pback != p
- lib.stm_commit_transaction()
- lib.stm_begin_inevitable_transaction()
- assert classify(p) == "protected"
- assert classify(pback) == "backup"
- assert lib.rawgetlong(p, 0) == 927122
- assert lib.rawgetlong(pback, 0) == 78927812 # but should not be used
- lib.setlong(p, 0, 43891)
- assert p.h_revision == lib.get_private_rev_num()
- assert pback == backup_copies()[p]
- assert lib.rawgetlong(p, 0) == 43891
- assert lib.rawgetlong(pback, 0) == 927122
-
def test_prebuilt_is_public():
p = palloc(HDR)
assert p.h_revision == 1
@@ -240,15 +209,13 @@
assert classify(p) == "public"
assert classify(p1) == "protected"
plist.append(p1) # now p's most recent revision is protected
- assert classify(ffi.cast("gcptr", p.h_revision)) == "stub"
+ assert classify(follow_revision(p)) == "stub"
+ assert p1.h_revision & 1
r.set(2)
r.wait(3)
- d = stolen_objs()
- assert len(d) == 1
- assert d.keys() == [p1]
- [p2] = d.values()
- assert lib.stm_read_barrier(p) == p2
- assert lib.stm_read_barrier(p1) == p2
+ assert classify(p1) == "public"
+ assert lib.stm_read_barrier(p) == p1
+ assert lib.stm_read_barrier(p1) == p1
def f2(r):
r.wait(2)
p2 = lib.stm_read_barrier(p) # steals
@@ -256,8 +223,61 @@
assert p2 == lib.stm_read_barrier(p) # short-circuit h_revision
assert p.h_revision == int(ffi.cast("revision_t", p2))
assert p2 == lib.stm_read_barrier(p)
- assert p2 not in plist
+ assert p2 == plist[-1]
assert classify(p2) == "public"
- plist.append(p2)
r.set(3)
run_parallel(f1, f2)
+
+def test_stealing_while_modifying():
+ py.test.skip("in-progress")
+ p = palloc(HDR + WORD)
+
+ def f1(r):
+ p1 = lib.stm_write_barrier(p) # private copy
+ assert classify(p) == "public"
+ assert classify(p1) == "private"
+ lib.rawsetlong(p1, 0, 2782172)
+
+ def cb(c):
+ assert c == 0
+ assert classify(p) == "public"
+ assert classify(p1) == "protected"
+ assert classify(follow_revision(p)) == "stub"
+ p2 = lib.stm_write_barrier(p)
+ assert p2 == p1
+ lib.rawsetlong(p2, 0, -451112)
+ pback = follow_revision(p1)
+ assert classify(p1) == "private"
+ assert classify(pback) == "backup"
+ assert lib.stm_read_barrier(p) == p1
+ assert lib.stm_read_barrier(p1) == p1
+ assert pback.h_revision & 1
+ r.wait_while_in_parallel()
+ assert classify(p1) == "private"
+ assert classify(pback) == "public"
+ assert pback.h_tid & GCFLAG_PUBLIC_TO_PRIVATE
+ assert lib.stm_read_barrier(p) == p1
+ assert lib.stm_read_barrier(p1) == p1
+ assert pback.h_revision & 1
+ perform_transaction(cb)
+
+ lib.stm_commit_transaction()
+ lib.stm_begin_inevitable_transaction()
+ assert classify(p1) == "protected"
+ assert classify(pback) == "public"
+ assert classify(follow_revision(pback)) == "stub"
+ assert follow_revision(pback).h_revision == (
+ ffi.cast("revision_t", p1) | 2)
+
+ def f2(r):
+ def cb(c):
+ assert c == 0
+ r.enter_in_parallel()
+ p2 = lib.stm_read_barrier(p) # steals
+ assert lib.rawgetlong(p2, 0) == 2782172
+ assert p2 == lib.stm_read_barrier(p)
+ assert classify(p2) == "public"
+ r.leave_in_parallel()
+ perform_transaction(cb)
+
+ run_parallel(f1, f2)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit