Author: Remi Meier <[email protected]>
Branch: c7
Changeset: r613:0c6d8dd59f10
Date: 2014-01-16 17:20 +0100
http://bitbucket.org/pypy/stmgc/changeset/0c6d8dd59f10/
Log: start doing minor collections
diff --git a/c7/core.c b/c7/core.c
--- a/c7/core.c
+++ b/c7/core.c
@@ -20,11 +20,13 @@
#define MAP_PAGES_FLAGS (MAP_SHARED | MAP_ANONYMOUS | MAP_NORESERVE)
#define LARGE_OBJECT_WORDS 36
#define NB_NURSERY_PAGES 1024
+#define LENGTH_SHADOW_STACK 163840
#define TOTAL_MEMORY (NB_PAGES * 4096UL * NB_THREADS)
#define READMARKER_END ((NB_PAGES * 4096UL) >> 4)
#define FIRST_OBJECT_PAGE ((READMARKER_END + 4095) / 4096UL)
+#define FIRST_NURSERY_PAGE FIRST_OBJECT_PAGE
#define READMARKER_START ((FIRST_OBJECT_PAGE * 4096UL) >> 4)
#define FIRST_READMARKER_PAGE (READMARKER_START / 4096UL)
#define FIRST_AFTER_NURSERY_PAGE (FIRST_OBJECT_PAGE + NB_NURSERY_PAGES)
@@ -56,10 +58,29 @@
struct stm_list_s *new_object_ranges;
struct alloc_for_size_s alloc[LARGE_OBJECT_WORDS];
localchar_t *nursery_current;
+
+ struct stm_list_s *old_objects_to_trace;
+ /* pages newly allocated in the current transaction only containing
+ uncommitted objects */
+ struct stm_list_s *uncommitted_pages;
};
#define _STM_TL2 ((_thread_local2_t *)_STM_TL1)
-enum { SHARED_PAGE=0, REMAPPING_PAGE, PRIVATE_PAGE }; /* flag_page_private */
+enum {
+ /* unprivatized page seen by all threads */
+ SHARED_PAGE=0,
+
+ /* page being in the process of privatization */
+ REMAPPING_PAGE,
+
+ /* page private for each thread */
+ PRIVATE_PAGE,
+
+ /* set for SHARED pages that only contain objects belonging
+ to the current transaction, so the whole page is not
+ visible yet for other threads */
+ UNCOMMITTED_SHARED_PAGE,
+}; /* flag_page_private */
static char *object_pages;
@@ -72,6 +93,8 @@
/************************************************************/
uintptr_t _stm_reserve_page(void);
void stm_abort_transaction(void);
+localchar_t *_stm_alloc_next_page(size_t i);
+void mark_page_as_uncommitted(uintptr_t pagenum);
static void spin_loop(void)
{
@@ -124,8 +147,7 @@
lock, so don't conflict with each other; when we need to do a global GC,
we take a writer lock to "stop the world". Note the initializer here,
which should give the correct priority for stm_possible_safe_point(). */
-static pthread_rwlock_t rwlock_shared =
- PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP;
+static pthread_rwlock_t rwlock_shared;
struct tx_descriptor *in_single_thread = NULL;
@@ -245,9 +267,9 @@
#define REAL_ADDRESS(object_pages, src) ((object_pages) + (uintptr_t)(src))
-static char *real_address(uintptr_t src)
+static struct object_s *real_address(object_t *src)
{
- return REAL_ADDRESS(_STM_TL2->thread_base, src);
+ return (struct object_s*)REAL_ADDRESS(_STM_TL2->thread_base, src);
}
@@ -256,11 +278,16 @@
return object_pages + thread_num * (NB_PAGES * 4096UL);
}
+bool _is_young(object_t *o)
+{
+ assert((uintptr_t)o >= FIRST_NURSERY_PAGE * 4096);
+ return (uintptr_t)o < FIRST_AFTER_NURSERY_PAGE * 4096;
+}
+
bool _stm_is_in_nursery(char *ptr)
{
object_t * o = _stm_tl_address(ptr);
- assert(o);
- return (uintptr_t)o < FIRST_AFTER_NURSERY_PAGE * 4096;
+ return _is_young(o);
}
char *_stm_real_address(object_t *o)
@@ -269,7 +296,7 @@
return NULL;
assert(FIRST_OBJECT_PAGE * 4096 <= (uintptr_t)o
&& (uintptr_t)o < NB_PAGES * 4096);
- return real_address((uintptr_t)o);
+ return (char*)real_address(o);
}
object_t *_stm_tl_address(char *ptr)
@@ -284,6 +311,7 @@
}
+
enum detect_conflicts_e { CANNOT_CONFLICT, CAN_CONFLICT, CHECK_CONFLICT };
static void update_to_current_version(enum detect_conflicts_e check_conflict)
@@ -309,12 +337,9 @@
char *dst = REAL_ADDRESS(local_base, item);
char *src = REAL_ADDRESS(remote_base, item);
- char *src_rebased = src - (uintptr_t)local_base;
- size_t size = stm_object_size_rounded_up((object_t *)src_rebased);
+ size_t size = stmcb_size((struct object_s*)src);
- memcpy(dst + sizeof(char *),
- src + sizeof(char *),
- size - sizeof(char *));
+ memcpy(dst, src, size);
}));
write_fence();
@@ -345,7 +370,17 @@
void _stm_write_slowpath(object_t *obj)
{
- _stm_privatize(((uintptr_t)obj) / 4096);
+ uintptr_t pagenum = ((uintptr_t)obj) / 4096;
+
+ /* old objects from the same transaction */
+ if (flag_page_private[pagenum] == UNCOMMITTED_SHARED_PAGE
+ || obj->stm_flags & GCFLAG_NOT_COMMITTED) {
+ _STM_TL2->old_objects_to_trace = stm_list_append
+ (_STM_TL2->old_objects_to_trace, obj);
+
+ return;
+ }
+ _stm_privatize(pagenum);
uintptr_t t0_offset = (uintptr_t)obj;
char* t0_addr = get_thread_base(0) + t0_offset;
@@ -372,6 +407,7 @@
/* Return the index'th object page, which is so far never used. */
uintptr_t index = __sync_fetch_and_add(&index_page_never_used, 1);
+ assert(flag_page_private[index] == SHARED_PAGE);
if (index >= NB_PAGES) {
fprintf(stderr, "Out of mmap'ed memory!\n");
abort();
@@ -386,6 +422,22 @@
((start) = (uint16_t)(uintptr_t)(range), \
(stop) = ((uintptr_t)(range)) >> 16)
+localchar_t *_stm_alloc_old(size_t size)
+{
+ size_t size_class = size / 8;
+ alloc_for_size_t *alloc = &_STM_TL2->alloc[size_class];
+ localchar_t *result;
+
+ if ((uint16_t)((uintptr_t)alloc->next) == alloc->stop)
+ result = _stm_alloc_next_page(size_class);
+ else {
+ result = alloc->next;
+ alloc->next += size;
+ }
+
+ return result;
+}
+
localchar_t *_stm_alloc_next_page(size_t i)
{
/* 'alloc->next' points to where the next allocation should go. The
@@ -404,21 +456,24 @@
alloc_for_size_t *alloc = &_STM_TL2->alloc[i];
size_t size = i * 8;
- if (alloc->flag_partial_page) {
- /* record this range in 'new_object_ranges' */
- localchar_t *ptr1 = alloc->next - size - 1;
- object_t *range;
- TO_RANGE(range, alloc->start, alloc->stop);
- page = ((uintptr_t)ptr1) / 4096;
- _STM_TL2->new_object_ranges = stm_list_append(
- _STM_TL2->new_object_ranges, (object_t *)page);
- _STM_TL2->new_object_ranges = stm_list_append(
- _STM_TL2->new_object_ranges, range);
- }
+ /* if (alloc->flag_partial_page) { */
+ /* /\* record this range in 'new_object_ranges' *\/ */
+ /* localchar_t *ptr1 = alloc->next - size - 1; */
+ /* object_t *range; */
+ /* TO_RANGE(range, alloc->start, alloc->stop); */
+ /* page = ((uintptr_t)ptr1) / 4096; */
+ /* _STM_TL2->new_object_ranges = stm_list_append( */
+ /* _STM_TL2->new_object_ranges, (object_t *)page); */
+ /* _STM_TL2->new_object_ranges = stm_list_append( */
+ /* _STM_TL2->new_object_ranges, range); */
+ /* } */
/* reserve a fresh new page */
page = _stm_reserve_page();
+ /* mark as UNCOMMITTED_... */
+ mark_page_as_uncommitted(page);
+
result = (localchar_t *)(page * 4096UL);
alloc->start = (uintptr_t)result;
alloc->stop = alloc->start + (4096 / size) * size;
@@ -427,18 +482,94 @@
return result;
}
+
+void mark_page_as_uncommitted(uintptr_t pagenum)
+{
+ flag_page_private[pagenum] = UNCOMMITTED_SHARED_PAGE;
+ _STM_TL2->uncommitted_pages = stm_list_append
+ (_STM_TL2->uncommitted_pages, (object_t*)pagenum);
+}
+
+void trace_if_young(object_t **pobj)
+{
+ if (*pobj == NULL)
+ return;
+ if (!_is_young(*pobj))
+ return;
+
+ /* the location the object moved to is at an 8b offset */
+ object_t **pforwared = (object_t**)(((char*)(*pobj)) + 8);
+ if ((*pobj)->stm_flags & GCFLAG_MOVED) {
+ *pobj = *pforwared;
+ return;
+ }
+
+ /* move obj to somewhere else */
+ size_t size = stmcb_size(real_address(*pobj));
+ object_t *moved = (object_t*)_stm_alloc_old(size);
+
+ memcpy((void*)real_address(moved),
+ (void*)real_address(*pobj),
+ size);
+
+ (*pobj)->stm_flags |= GCFLAG_MOVED;
+ *pforwared = moved;
+ *pobj = moved;
+
+ _STM_TL2->old_objects_to_trace = stm_list_append
+ (_STM_TL2->old_objects_to_trace, moved);
+}
+
+void minor_collect()
+{
+ /* visit shadowstack & add to old_obj_to_trace */
+ object_t **current = _STM_TL1->shadow_stack;
+ object_t **base = _STM_TL1->shadow_stack_base;
+ while (current-- != base) {
+ trace_if_young(current);
+ }
+
+ /* visit old_obj_to_trace until empty */
+ struct stm_list_s *old_objs = _STM_TL2->old_objects_to_trace;
+ while (!stm_list_is_empty(old_objs)) {
+ object_t *item = stm_list_pop_item(old_objs);
+ stmcb_trace(real_address(item),
+ trace_if_young);
+ }
+
+ /* XXX fix modified_objects? */
+
+ // also move objects to PRIVATE_PAGE pages, but then
+ // also add the GCFLAG_NOT_COMMITTED to these objects.
+
+ /* clear nursery */
+ localchar_t *nursery_base = (localchar_t*)(FIRST_NURSERY_PAGE * 4096);
+ memset((void*)real_address((object_t*)nursery_base), 0x0,
+ _STM_TL2->nursery_current - nursery_base);
+ _STM_TL2->nursery_current = nursery_base;
+}
+
+localchar_t *collect_and_reserve(size_t size)
+{
+ minor_collect();
+
+ localchar_t *current = _STM_TL2->nursery_current;
+ _STM_TL2->nursery_current = current + size;
+ return current;
+}
+
object_t *stm_allocate(size_t size)
{
assert(size % 8 == 0);
size_t i = size / 8;
assert(2 <= i && i < LARGE_OBJECT_WORDS);//XXX
+ assert(2 <= i && i < NB_NURSERY_PAGES * 4096);//XXX
localchar_t *current = _STM_TL2->nursery_current;
localchar_t *new_current = current + size;
_STM_TL2->nursery_current = new_current;
if ((uintptr_t)new_current > FIRST_AFTER_NURSERY_PAGE * 4096) {
- /* XXX: do minor collection */
- abort();
+ current = collect_and_reserve(size);
}
object_t *result = (object_t *)current;
@@ -450,6 +581,13 @@
void stm_setup(void)
{
+ pthread_rwlockattr_t attr;
+ pthread_rwlockattr_init(&attr);
+ pthread_rwlockattr_setkind_np(&attr,
+
PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
+ pthread_rwlock_init(&rwlock_shared, &attr);
+ pthread_rwlockattr_destroy(&attr);
+
/* Check that some values are acceptable */
assert(4096 <= ((uintptr_t)_STM_TL1));
assert(((uintptr_t)_STM_TL1) == ((uintptr_t)_STM_TL2));
@@ -526,24 +664,48 @@
_stm_restore_local_state(thread_num);
- _STM_TL2->nursery_current = (localchar_t*)(FIRST_OBJECT_PAGE * 4096);
+ _STM_TL2->nursery_current = (localchar_t*)(FIRST_NURSERY_PAGE * 4096);
+ _STM_TL1->shadow_stack = (object_t**)malloc(LENGTH_SHADOW_STACK *
sizeof(void*));
+ _STM_TL1->shadow_stack_base = _STM_TL1->shadow_stack;
+
+ _STM_TL2->old_objects_to_trace = stm_list_create();
+ _STM_TL2->uncommitted_pages = stm_list_create();
_STM_TL2->modified_objects = stm_list_create();
assert(!_STM_TL2->running_transaction);
}
+bool _stm_is_in_transaction(void)
+{
+ return _STM_TL2->running_transaction;
+}
+
void _stm_teardown_thread(void)
{
+ assert(!pthread_rwlock_trywrlock(&rwlock_shared));
+ assert(!pthread_rwlock_unlock(&rwlock_shared));
+
wait_until_updated();
stm_list_free(_STM_TL2->modified_objects);
_STM_TL2->modified_objects = NULL;
+ assert(_STM_TL1->shadow_stack == _STM_TL1->shadow_stack_base);
+ free(_STM_TL1->shadow_stack);
+
+ assert(_STM_TL2->old_objects_to_trace->count == 0);
+ stm_list_free(_STM_TL2->old_objects_to_trace);
+
+ assert(_STM_TL2->uncommitted_pages->count == 0);
+ stm_list_free(_STM_TL2->uncommitted_pages);
+
set_gs_register(INVALID_GS_VALUE);
}
void _stm_teardown(void)
{
munmap(object_pages, TOTAL_MEMORY);
+ memset(flag_page_private, 0, sizeof(flag_page_private));
+ pthread_rwlock_destroy(&rwlock_shared);
object_pages = NULL;
}
@@ -571,7 +733,8 @@
them non-reserved; apparently the kernel just skips them very
quickly.)
*/
- int res = madvise(real_address(FIRST_READMARKER_PAGE * 4096UL),
+ int res = madvise((void*)real_address
+ ((object_t*) (FIRST_READMARKER_PAGE * 4096UL)),
(FIRST_OBJECT_PAGE - FIRST_READMARKER_PAGE) * 4096UL,
MADV_DONTNEED);
if (res < 0) {
@@ -610,6 +773,8 @@
wait_until_updated();
stm_list_clear(_STM_TL2->modified_objects);
+ assert(stm_list_is_empty(_STM_TL2->old_objects_to_trace));
+ stm_list_clear(_STM_TL2->uncommitted_pages);
/* check that there is no stm_abort() in the following maybe_update() */
_STM_TL1->jmpbufptr = NULL;
@@ -646,6 +811,8 @@
start_exclusivelock();
_STM_TL1->jmpbufptr = NULL; /* cannot abort any more */
+
+ minor_collect();
/* copy modified object versions to other threads */
pending_updates = _STM_TL2->modified_objects;
@@ -654,7 +821,32 @@
_stm_restore_local_state(other_thread_num);
update_to_current_version(CHECK_CONFLICT); /* sets need_abort */
_stm_restore_local_state(my_thread_num);
+
+ /* uncommitted_pages */
+ long j;
+ for (j = 2; j < LARGE_OBJECT_WORDS; j++) {
+ alloc_for_size_t *alloc = &_STM_TL2->alloc[j];
+ uint16_t start = alloc->start;
+ uint16_t cur = (uintptr_t)alloc->next;
+ if (start == cur)
+ continue;
+ uintptr_t pagenum = ((uintptr_t)(alloc->next - 1)) / 4096UL;
+ if (flag_page_private[pagenum] == UNCOMMITTED_SHARED_PAGE) {
+ /* mark it as empty so it doesn't get used in the next
+ transaction */
+ /* XXX: flag_partial_page!! */
+ alloc->start = 0;
+ alloc->next = 0;
+ alloc->stop = 0;
+ }
+ }
+ STM_LIST_FOREACH(_STM_TL2->uncommitted_pages, ({
+ uintptr_t pagenum = (uintptr_t)item;
+ flag_page_private[pagenum] = SHARED_PAGE;
+ }));
+ stm_list_clear(_STM_TL2->uncommitted_pages);
+
/* /\* walk the new_object_ranges and manually copy the new objects */
/* to the other thread's pages in the (hopefully rare) case that */
@@ -737,6 +929,7 @@
}
/* stm_list_clear(_STM_TL2->new_object_ranges); */
stm_list_clear(_STM_TL2->modified_objects);
+ stm_list_clear(_STM_TL2->old_objects_to_trace);
assert(_STM_TL1->jmpbufptr != NULL);
assert(_STM_TL1->jmpbufptr != (jmpbufptr_t *)-1); /* for tests only */
_STM_TL2->running_transaction = 0;
diff --git a/c7/core.h b/c7/core.h
--- a/c7/core.h
+++ b/c7/core.h
@@ -30,17 +30,23 @@
*/
enum {
- GCFLAG_WRITE_BARRIER = (1 << 0),
/* set if the write-barrier slowpath needs to trigger. set on all
old objects if there was no write-barrier on it in the same
transaction and no collection inbetween. */
+ GCFLAG_WRITE_BARRIER = (1 << 0),
+ /* set on objects which are in pages visible to others (SHARED
+ or PRIVATE), but not committed yet. So only visible from
+ this transaction. */
+ GCFLAG_NOT_COMMITTED = (1 << 1),
+
+ GCFLAG_MOVED = (1 << 2),
};
struct object_s {
uint8_t stm_flags; /* reserved for the STM library */
uint8_t stm_write_lock; /* 1 if writeable by some thread */
- uint32_t header; /* for the user program -- only write in
- newly allocated objects */
+ /* make sure it doesn't get bigger than 4 bytes for performance
+ reasons */
};
struct read_marker_s {
@@ -53,6 +59,8 @@
jmpbufptr_t *jmpbufptr;
uint8_t transaction_read_version;
uint16_t transaction_write_version;
+ object_t **shadow_stack;
+ object_t **shadow_stack_base;
};
#define _STM_TL1 ((_thread_local1_t *)4352)
@@ -77,13 +85,24 @@
_stm_write_slowpath(obj);
}
+static inline void stm_push_root(object_t *obj)
+{
+ *(_STM_TL1->shadow_stack++) = obj;
+}
+
+static inline object_t *stm_pop_root(void)
+{
+ return *(--_STM_TL1->shadow_stack);
+}
/* must be provided by the user of this library */
-extern size_t stm_object_size_rounded_up(object_t *);
+extern size_t stmcb_size(struct object_s *);
+extern void stmcb_trace(struct object_s *, void (object_t **));
void _stm_restore_local_state(int thread_num);
void _stm_teardown(void);
void _stm_teardown_thread(void);
+bool _stm_is_in_transaction(void);
bool _stm_was_read(object_t *obj);
bool _stm_was_written(object_t *obj);
diff --git a/c7/list.h b/c7/list.h
--- a/c7/list.h
+++ b/c7/list.h
@@ -48,6 +48,11 @@
return lst->count;
}
+static inline object_t *stm_list_pop_item(struct stm_list_s *lst)
+{
+ return lst->items[--lst->count];
+}
+
static inline object_t *stm_list_item(struct stm_list_s *lst, uintptr_t index)
{
return lst->items[index];
diff --git a/c7/test/support.py b/c7/test/support.py
--- a/c7/test/support.py
+++ b/c7/test/support.py
@@ -54,6 +54,14 @@
void _stm_stop_safe_point(void);
bool _stm_check_stop_safe_point(void);
+void _set_type_id(object_t *obj, uint32_t h);
+uint32_t _get_type_id(object_t *obj);
+bool _stm_is_in_transaction(void);
+
+void stm_push_root(object_t *obj);
+object_t *stm_pop_root(void);
+
+
void *memset(void *s, int c, size_t n);
""")
@@ -63,6 +71,13 @@
#include "core.h"
+struct myobj_s {
+ struct object_s hdr;
+ uint32_t type_id;
+};
+typedef TLPREFIX struct myobj_s myobj_t;
+
+
size_t stm_object_size_rounded_up(object_t * obj) {
return 16;
}
@@ -94,6 +109,45 @@
}
+void _set_type_id(object_t *obj, uint32_t h) {
+ ((myobj_t*)obj)->type_id = h;
+}
+
+uint32_t _get_type_id(object_t *obj) {
+ return ((myobj_t*)obj)->type_id;
+}
+
+size_t stmcb_size(struct object_s *obj)
+{
+ struct myobj_s *myobj = (struct myobj_s*)obj;
+ if (myobj->type_id < 42142) {
+ /* basic case: tid equals 42 plus the size of the object */
+ assert(myobj->type_id >= 42 + sizeof(struct myobj_s));
+ return myobj->type_id - 42;
+ }
+ else {
+ int nrefs = myobj->type_id - 42142;
+ assert(nrefs < 100);
+ if (nrefs == 0) /* weakrefs */
+ nrefs = 1;
+ return sizeof(struct myobj_s) + nrefs * sizeof(void*);
+ }
+}
+
+void stmcb_trace(struct object_s *obj, void visit(object_t **))
+{
+ int i;
+ struct myobj_s *myobj = (struct myobj_s*)obj;
+ if (myobj->type_id < 42142) {
+ /* basic case: no references */
+ return;
+ }
+ for (i=0; i < myobj->type_id - 42142; i++) {
+ object_t **ref = ((object_t **)(myobj + 1)) + i;
+ visit(ref);
+ }
+}
+
''', sources=source_files,
define_macros=[('STM_TESTS', '1')],
undef_macros=['NDEBUG'],
@@ -102,15 +156,22 @@
force_generic_engine=True)
+MAGIC_HEADER = ffi.cast('uint32_t', 42142)
+
+
def is_in_nursery(ptr):
return lib._stm_is_in_nursery(ptr)
def stm_allocate_old(size):
o = lib._stm_allocate_old(size)
+ tid = 42 + size
+ lib._set_type_id(o, tid)
return o, lib._stm_real_address(o)
def stm_allocate(size):
o = lib.stm_allocate(size)
+ tid = 42 + size
+ lib._set_type_id(o, tid)
return o, lib._stm_real_address(o)
def stm_get_real_address(obj):
@@ -131,6 +192,12 @@
def stm_was_written(o):
return lib._stm_was_written(o)
+def stm_push_root(o):
+ return lib.stm_push_root(o)
+
+def stm_pop_root():
+ return lib.stm_pop_root()
+
def stm_start_transaction():
lib.stm_start_transaction(ffi.cast("jmpbufptr_t*", -1))
@@ -163,13 +230,23 @@
def teardown_method(self, meth):
lib._stm_restore_local_state(1)
+ if lib._stm_is_in_transaction():
+ stm_stop_transaction()
lib._stm_teardown_thread()
lib._stm_restore_local_state(0)
+ if lib._stm_is_in_transaction():
+ stm_stop_transaction()
lib._stm_teardown_thread()
lib._stm_teardown()
- def switch(self, thread_num):
+ def switch(self, thread_num, expect_conflict=False):
assert thread_num != self.current_thread
+ if lib._stm_is_in_transaction():
+ stm_start_safe_point()
lib._stm_restore_local_state(thread_num)
+ if lib._stm_is_in_transaction():
+ stm_stop_safe_point(expect_conflict)
+ elif expect_conflict:
+ assert False
self.current_thread = thread_num
diff --git a/c7/test/test_basic.py b/c7/test/test_basic.py
--- a/c7/test/test_basic.py
+++ b/c7/test/test_basic.py
@@ -25,12 +25,12 @@
def test_transaction_start_stop(self):
stm_start_transaction()
- stm_start_safe_point()
+
self.switch(1)
stm_start_transaction()
stm_stop_transaction()
self.switch(0)
- stm_stop_safe_point()
+
stm_stop_transaction()
def test_simple_read(self):
@@ -38,6 +38,7 @@
lp1, _ = stm_allocate(16)
stm_read(lp1)
assert stm_was_read(lp1)
+ stm_stop_transaction()
def test_simple_write(self):
stm_start_transaction()
@@ -45,6 +46,7 @@
assert stm_was_written(lp1)
stm_write(lp1)
assert stm_was_written(lp1)
+ stm_stop_transaction()
def test_allocate_old(self):
lp1, _ = stm_allocate_old(16)
@@ -58,12 +60,17 @@
stm_write(lp1)
assert stm_was_written(lp1)
p1[15] = 'a'
+
self.switch(1)
stm_start_transaction()
stm_read(lp1)
assert stm_was_read(lp1)
tp1 = stm_get_real_address(lp1)
assert tp1[15] == '\0'
+ stm_stop_transaction()
+ self.switch(0)
+
+ stm_stop_transaction()
def test_read_write_1(self):
lp1, p1 = stm_allocate_old(16)
@@ -77,35 +84,7 @@
p1 = stm_get_real_address(lp1)
assert p1[8] == 'a'
p1[8] = 'b'
- stm_start_safe_point()
- #
- self.switch(0)
- stm_start_transaction()
- stm_read(lp1)
- p1 = stm_get_real_address(lp1)
- assert p1[8] == 'a'
- stm_start_safe_point()
- #
- self.switch(1)
- stm_stop_safe_point()
- stm_stop_transaction(False)
- #
- self.switch(0)
- stm_stop_safe_point(True) # detects rw conflict
-
- def test_read_write_2(self):
- stm_start_transaction()
- lp1, p1 = stm_allocate(16)
- p1[8] = 'a'
- stm_stop_transaction(False)
- #
- self.switch(1)
- stm_start_transaction()
- stm_write(lp1)
- p1 = stm_get_real_address(lp1)
- assert p1[8] == 'a'
- p1[8] = 'b'
#
self.switch(0)
stm_start_transaction()
@@ -116,212 +95,256 @@
self.switch(1)
stm_stop_transaction(False)
#
- self.switch(0)
- p1 = stm_get_real_address(lp1)
- assert p1[8] == 'a'
+ self.switch(0, expect_conflict=True) # detects rw conflict
+
+ def test_commit_fresh_objects(self):
+ stm_start_transaction()
+ lp, p = stm_allocate(16)
+ p[8] = 'u'
+ stm_push_root(lp)
+ stm_stop_transaction()
+ lp = stm_pop_root()
+
+ self.switch(1)
+
+ stm_start_transaction()
+ stm_write(lp) # privatize page
+ p_ = stm_get_real_address(lp)
+ assert p != p_
+ assert p_[8] == 'u'
+ stm_stop_transaction()
+
+
- def test_start_transaction_updates(self):
- stm_start_transaction()
- p1 = stm_allocate(16)
- p1[8] = 'a'
- stm_stop_transaction(False)
- #
- self.switch(1)
- stm_start_transaction()
- stm_write(p1)
- assert p1[8] == 'a'
- p1[8] = 'b'
- stm_stop_transaction(False)
- #
- self.switch(0)
- assert p1[8] == 'a'
- stm_start_transaction()
- assert p1[8] == 'b'
+ # def test_read_write_2(self):
+ # stm_start_transaction()
+ # lp1, p1 = stm_allocate(16)
+ # p1[8] = 'a'
+ # stm_stop_transaction(False)
+ # #
+ # self.switch(1)
+ # stm_start_transaction()
+ # stm_write(lp1)
+ # p1 = stm_get_real_address(lp1)
+ # assert p1[8] == 'a'
+ # p1[8] = 'b'
+ # #
+ # self.switch(0)
+ # stm_start_transaction()
+ # stm_read(lp1)
+ # p1 = stm_get_real_address(lp1)
+ # assert p1[8] == 'a'
+ # #
+ # self.switch(1)
+ # stm_stop_transaction(False)
+ # #
+ # self.switch(0)
+ # p1 = stm_get_real_address(lp1)
+ # assert p1[8] == 'a'
- def test_resolve_no_conflict_empty(self):
- stm_start_transaction()
- #
- self.switch(1)
- stm_start_transaction()
- stm_stop_transaction(False)
- #
- self.switch(0)
- stm_stop_transaction(False)
+
+ # def test_start_transaction_updates(self):
+ # stm_start_transaction()
+ # p1 = stm_allocate(16)
+ # p1[8] = 'a'
+ # stm_stop_transaction(False)
+ # #
+ # self.switch(1)
+ # stm_start_transaction()
+ # stm_write(p1)
+ # assert p1[8] == 'a'
+ # p1[8] = 'b'
+ # stm_stop_transaction(False)
+ # #
+ # self.switch(0)
+ # assert p1[8] == 'a'
+ # stm_start_transaction()
+ # assert p1[8] == 'b'
- def test_resolve_no_conflict_write_only_in_already_committed(self):
- stm_start_transaction()
- p1 = stm_allocate(16)
- p1[8] = 'a'
- stm_stop_transaction(False)
- stm_start_transaction()
- #
- self.switch(1)
- stm_start_transaction()
- stm_write(p1)
- p1[8] = 'b'
- stm_stop_transaction(False)
- #
- self.switch(0)
- assert p1[8] == 'a'
- stm_stop_transaction(False)
- assert p1[8] == 'b'
+ # def test_resolve_no_conflict_empty(self):
+ # stm_start_transaction()
+ # #
+ # self.switch(1)
+ # stm_start_transaction()
+ # stm_stop_transaction(False)
+ # #
+ # self.switch(0)
+ # stm_stop_transaction(False)
- def test_resolve_write_read_conflict(self):
- stm_start_transaction()
- p1 = stm_allocate(16)
- p1[8] = 'a'
- stm_stop_transaction(False)
- stm_start_transaction()
- #
- self.switch(1)
- stm_start_transaction()
- stm_write(p1)
- p1[8] = 'b'
- stm_stop_transaction(False)
- #
- self.switch(0)
- stm_read(p1)
- assert p1[8] == 'a'
- stm_stop_transaction(expected_conflict=True)
- assert p1[8] in ('a', 'b')
- stm_start_transaction()
- assert p1[8] == 'b'
+ # def test_resolve_no_conflict_write_only_in_already_committed(self):
+ # stm_start_transaction()
+ # p1 = stm_allocate(16)
+ # p1[8] = 'a'
+ # stm_stop_transaction(False)
+ # stm_start_transaction()
+ # #
+ # self.switch(1)
+ # stm_start_transaction()
+ # stm_write(p1)
+ # p1[8] = 'b'
+ # stm_stop_transaction(False)
+ # #
+ # self.switch(0)
+ # assert p1[8] == 'a'
+ # stm_stop_transaction(False)
+ # assert p1[8] == 'b'
- def test_resolve_write_write_conflict(self):
- stm_start_transaction()
- p1 = stm_allocate(16)
- p1[8] = 'a'
- stm_stop_transaction(False)
- stm_start_transaction()
- #
- self.switch(1)
- stm_start_transaction()
- stm_write(p1)
- p1[8] = 'b'
- stm_stop_transaction(False)
- #
- self.switch(0)
- assert p1[8] == 'a'
- stm_write(p1)
- p1[8] = 'c'
- stm_stop_transaction(expected_conflict=True)
- assert p1[8] in ('a', 'b')
- stm_start_transaction()
- assert p1[8] == 'b'
+ # def test_resolve_write_read_conflict(self):
+ # stm_start_transaction()
+ # p1 = stm_allocate(16)
+ # p1[8] = 'a'
+ # stm_stop_transaction(False)
+ # stm_start_transaction()
+ # #
+ # self.switch(1)
+ # stm_start_transaction()
+ # stm_write(p1)
+ # p1[8] = 'b'
+ # stm_stop_transaction(False)
+ # #
+ # self.switch(0)
+ # stm_read(p1)
+ # assert p1[8] == 'a'
+ # stm_stop_transaction(expected_conflict=True)
+ # assert p1[8] in ('a', 'b')
+ # stm_start_transaction()
+ # assert p1[8] == 'b'
- def test_resolve_write_write_no_conflict(self):
- stm_start_transaction()
- p1 = stm_allocate(16)
- p2 = stm_allocate(16)
- p1[8] = 'a'
- p2[8] = 'A'
- stm_stop_transaction(False)
- stm_start_transaction()
- #
- self.switch(1)
- stm_start_transaction()
- stm_write(p1)
- p1[8] = 'b'
- stm_stop_transaction(False)
- #
- self.switch(0)
- stm_write(p2)
- p2[8] = 'C'
- stm_stop_transaction(False)
- assert p1[8] == 'b'
- assert p2[8] == 'C'
+ # def test_resolve_write_write_conflict(self):
+ # stm_start_transaction()
+ # p1 = stm_allocate(16)
+ # p1[8] = 'a'
+ # stm_stop_transaction(False)
+ # stm_start_transaction()
+ # #
+ # self.switch(1)
+ # stm_start_transaction()
+ # stm_write(p1)
+ # p1[8] = 'b'
+ # stm_stop_transaction(False)
+ # #
+ # self.switch(0)
+ # assert p1[8] == 'a'
+ # stm_write(p1)
+ # p1[8] = 'c'
+ # stm_stop_transaction(expected_conflict=True)
+ # assert p1[8] in ('a', 'b')
+ # stm_start_transaction()
+ # assert p1[8] == 'b'
- def test_page_extra_malloc_unchanged_page(self):
- stm_start_transaction()
- p1 = stm_allocate(16)
- p2 = stm_allocate(16)
- p1[8] = 'A'
- p2[8] = 'a'
- stm_stop_transaction(False)
- stm_start_transaction()
- #
- self.switch(1)
- stm_start_transaction()
- stm_write(p1)
- assert p1[8] == 'A'
- p1[8] = 'B'
- stm_stop_transaction(False)
- #
- self.switch(0)
- stm_read(p2)
- assert p2[8] == 'a'
- p3 = stm_allocate(16) # goes into the same page, which is
- p3[8] = ':' # not otherwise modified
- stm_stop_transaction(False)
- #
- assert p1[8] == 'B'
- assert p2[8] == 'a'
- assert p3[8] == ':'
+ # def test_resolve_write_write_no_conflict(self):
+ # stm_start_transaction()
+ # p1 = stm_allocate(16)
+ # p2 = stm_allocate(16)
+ # p1[8] = 'a'
+ # p2[8] = 'A'
+ # stm_stop_transaction(False)
+ # stm_start_transaction()
+ # #
+ # self.switch(1)
+ # stm_start_transaction()
+ # stm_write(p1)
+ # p1[8] = 'b'
+ # stm_stop_transaction(False)
+ # #
+ # self.switch(0)
+ # stm_write(p2)
+ # p2[8] = 'C'
+ # stm_stop_transaction(False)
+ # assert p1[8] == 'b'
+ # assert p2[8] == 'C'
- def test_page_extra_malloc_changed_page_before(self):
- stm_start_transaction()
- p1 = stm_allocate(16)
- p2 = stm_allocate(16)
- p1[8] = 'A'
- p2[8] = 'a'
- stm_stop_transaction(False)
- stm_start_transaction()
- #
- self.switch(1)
- stm_start_transaction()
- stm_write(p1)
- assert p1[8] == 'A'
- p1[8] = 'B'
- stm_stop_transaction(False)
- #
- self.switch(0)
- stm_write(p2)
- assert p2[8] == 'a'
- p2[8] = 'b'
- p3 = stm_allocate(16) # goes into the same page, which I already
- p3[8] = ':' # modified just above
- stm_stop_transaction(False)
- #
- assert p1[8] == 'B'
- assert p2[8] == 'b'
- assert p3[8] == ':'
+ # def test_page_extra_malloc_unchanged_page(self):
+ # stm_start_transaction()
+ # p1 = stm_allocate(16)
+ # p2 = stm_allocate(16)
+ # p1[8] = 'A'
+ # p2[8] = 'a'
+ # stm_stop_transaction(False)
+ # stm_start_transaction()
+ # #
+ # self.switch(1)
+ # stm_start_transaction()
+ # stm_write(p1)
+ # assert p1[8] == 'A'
+ # p1[8] = 'B'
+ # stm_stop_transaction(False)
+ # #
+ # self.switch(0)
+ # stm_read(p2)
+ # assert p2[8] == 'a'
+ # p3 = stm_allocate(16) # goes into the same page, which is
+ # p3[8] = ':' # not otherwise modified
+ # stm_stop_transaction(False)
+ # #
+ # assert p1[8] == 'B'
+ # assert p2[8] == 'a'
+ # assert p3[8] == ':'
- def test_page_extra_malloc_changed_page_after(self):
- stm_start_transaction()
- p1 = stm_allocate(16)
- p2 = stm_allocate(16)
- p1[8] = 'A'
- p2[8] = 'a'
- stm_stop_transaction(False)
- stm_start_transaction()
- #
- self.switch(1)
- stm_start_transaction()
- stm_write(p1)
- assert p1[8] == 'A'
- p1[8] = 'B'
- stm_stop_transaction(False)
- #
- self.switch(0)
- p3 = stm_allocate(16) # goes into the same page, which I will
- p3[8] = ':' # modify just below
- stm_write(p2)
- assert p2[8] == 'a'
- p2[8] = 'b'
- stm_stop_transaction(False)
- #
- assert p1[8] == 'B'
- assert p2[8] == 'b'
- assert p3[8] == ':'
+ # def test_page_extra_malloc_changed_page_before(self):
+ # stm_start_transaction()
+ # p1 = stm_allocate(16)
+ # p2 = stm_allocate(16)
+ # p1[8] = 'A'
+ # p2[8] = 'a'
+ # stm_stop_transaction(False)
+ # stm_start_transaction()
+ # #
+ # self.switch(1)
+ # stm_start_transaction()
+ # stm_write(p1)
+ # assert p1[8] == 'A'
+ # p1[8] = 'B'
+ # stm_stop_transaction(False)
+ # #
+ # self.switch(0)
+ # stm_write(p2)
+ # assert p2[8] == 'a'
+ # p2[8] = 'b'
+ # p3 = stm_allocate(16) # goes into the same page, which I already
+ # p3[8] = ':' # modified just above
+ # stm_stop_transaction(False)
+ # #
+ # assert p1[8] == 'B'
+ # assert p2[8] == 'b'
+ # assert p3[8] == ':'
- def test_overflow_write_history(self):
- stm_start_transaction()
- plist = [stm_allocate(n) for n in range(16, 256, 8)]
- stm_stop_transaction(False)
- #
- for i in range(20):
- stm_start_transaction()
- for p in plist:
- stm_write(p)
- stm_stop_transaction(False)
+ # def test_page_extra_malloc_changed_page_after(self):
+ # stm_start_transaction()
+ # p1 = stm_allocate(16)
+ # p2 = stm_allocate(16)
+ # p1[8] = 'A'
+ # p2[8] = 'a'
+ # stm_stop_transaction(False)
+ # stm_start_transaction()
+ # #
+ # self.switch(1)
+ # stm_start_transaction()
+ # stm_write(p1)
+ # assert p1[8] == 'A'
+ # p1[8] = 'B'
+ # stm_stop_transaction(False)
+ # #
+ # self.switch(0)
+ # p3 = stm_allocate(16) # goes into the same page, which I will
+ # p3[8] = ':' # modify just below
+ # stm_write(p2)
+ # assert p2[8] == 'a'
+ # p2[8] = 'b'
+ # stm_stop_transaction(False)
+ # #
+ # assert p1[8] == 'B'
+ # assert p2[8] == 'b'
+ # assert p3[8] == ':'
+
+ # def test_overflow_write_history(self):
+ # stm_start_transaction()
+ # plist = [stm_allocate(n) for n in range(16, 256, 8)]
+ # stm_stop_transaction(False)
+ # #
+ # for i in range(20):
+ # stm_start_transaction()
+ # for p in plist:
+ # stm_write(p)
+ # stm_stop_transaction(False)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit