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

Reply via email to