[pypy-commit] stmgc bag: First tests pass

arigo noreply at buildbot.pypy.org
Sat Jan 24 10:35:01 CET 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: bag
Changeset: r1579:a46480cfd06d
Date: 2015-01-24 10:35 +0100
http://bitbucket.org/pypy/stmgc/changeset/a46480cfd06d/

Log:	First tests pass

diff --git a/c7/stm/bag.c b/c7/stm/bag.c
--- a/c7/stm/bag.c
+++ b/c7/stm/bag.c
@@ -42,8 +42,7 @@
 
 
 struct stm_bag_seg_s {
-    struct deque_block_s *deque_left, *deque_middle, *deque_right;
-    deque_idx_t deque_left_pos, deque_middle_pos, deque_right_pos;
+    uintptr_t *deque_left, *deque_middle, *deque_right;
     struct list_s *abort_list;
 };
 
@@ -59,12 +58,9 @@
     for (i = 0; i < STM_NB_SEGMENTS; i++) {
         struct stm_bag_seg_s *bs = &bag->by_segment[i];
         struct deque_block_s *block = deque_new_block();
-        bs->deque_left = block;
-        bs->deque_middle = block;
-        bs->deque_right = block;
-        bs->deque_left_pos = 0;
-        bs->deque_middle_pos = 0;
-        bs->deque_right_pos = 0;
+        bs->deque_left = &block->items[0];
+        bs->deque_middle = &block->items[0];
+        bs->deque_right = &block->items[0];
         LIST_CREATE(bs->abort_list);
     }
     return bag;
@@ -75,11 +71,49 @@
     int i;
     for (i = 0; i < STM_NB_SEGMENTS; i++) {
         struct stm_bag_seg_s *bs = &bag->by_segment[i];
-        while (bs->deque_left) {
-            struct deque_block_s *block = bs->deque_left;
-            bs->deque_left = block->next;
+        struct deque_block_s *block = deque_block(bs->deque_left);
+        while (block != NULL) {
+            struct deque_block_s *nextblock = block->next;
             deque_free_block(block);
+            block = nextblock;
         }
         LIST_FREE(bs->abort_list);
     }
 }
+
+void stm_bag_add(stm_bag_t *bag, object_t *newobj)
+{
+    int i = STM_SEGMENT->segment_num - 1;
+    struct stm_bag_seg_s *bs = &bag->by_segment[i];
+    struct deque_block_s *block = deque_block(bs->deque_right);
+
+    *bs->deque_right++ = (uintptr_t)newobj;
+
+    if (bs->deque_right == &block->items[DEQUE_BLOCK_SIZE]) {
+        assert(block->next == NULL);
+        block->next = deque_new_block();
+        bs->deque_right = &block->next->items[0];
+    }
+}
+
+object_t *stm_bag_try_pop(stm_bag_t *bag)
+{
+    int i = STM_SEGMENT->segment_num - 1;
+    struct stm_bag_seg_s *bs = &bag->by_segment[i];
+    if (bs->deque_left == bs->deque_right) {
+        return NULL;
+    }
+    struct deque_block_s *block = deque_block(bs->deque_left);
+    uintptr_t result = *bs->deque_left++;
+
+    if (bs->deque_left == &block->items[DEQUE_BLOCK_SIZE]) {
+        bs->deque_left = &block->next->items[0];
+        deque_free_block(block);
+    }
+    return (object_t *)result;
+}
+
+void stm_bag_tracefn(stm_bag_t *bag, void visit(object_t **))
+{
+    abort();
+}
diff --git a/c7/stm/list.c b/c7/stm/list.c
--- a/c7/stm/list.c
+++ b/c7/stm/list.c
@@ -193,3 +193,22 @@
  missing:
     return false;
 }
+
+
+/************************************************************/
+
+static struct deque_block_s *deque_new_block(void)
+{
+    void *mem;
+    struct deque_block_s *db;
+    size_t size = sizeof(struct deque_block_s);
+
+    assert((size & (size - 1)) == 0);   /* a power of two */
+
+    if (posix_memalign(&mem, size, size) != 0)
+        stm_fatalerror("out of memory in deque_new_block");   /* XXX */
+
+    db = (struct deque_block_s *)mem;
+    db->next = NULL;
+    return db;
+}
diff --git a/c7/stm/list.h b/c7/stm/list.h
--- a/c7/stm/list.h
+++ b/c7/stm/list.h
@@ -222,23 +222,27 @@
 /************************************************************/
 
 #define DEQUE_BLOCK_SIZE  31
-typedef unsigned char deque_idx_t;
 
 struct deque_block_s {
     struct deque_block_s *next;
     uintptr_t items[DEQUE_BLOCK_SIZE];
 };
 
-static inline struct deque_block_s *deque_new_block(void)
-{
-    struct deque_block_s *db = malloc(sizeof(struct deque_block_s));
-    if (db == NULL)
-        stm_fatalerror("out of memory in deque_new_block");   /* XXX */
-    db->next = NULL;
-    return db;
-}
+static struct deque_block_s *deque_new_block(void);
 
 static inline void deque_free_block(struct deque_block_s *db)
 {
     free(db);
 }
+
+static inline struct deque_block_s *deque_block(uintptr_t *inner_ptr)
+{
+    size_t size = sizeof(struct deque_block_s);
+    return (struct deque_block_s *)(((uintptr_t)inner_ptr) & ~(size - 1));
+}
+
+static inline bool deque_index_equal(uintptr_t *inner_ptr, uintptr_t index)
+{
+    struct deque_block_s *block = deque_block(inner_ptr);
+    return (inner_ptr == &block->items[index]);
+}
diff --git a/c7/stmgc.c b/c7/stmgc.c
--- a/c7/stmgc.c
+++ b/c7/stmgc.c
@@ -39,3 +39,4 @@
 #include "stm/rewind_setjmp.c"
 #include "stm/finalizer.c"
 #include "stm/hashtable.c"
+#include "stm/bag.c"
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -559,6 +559,7 @@
 void stm_bag_free(stm_bag_t *);
 void stm_bag_add(stm_bag_t *, object_t *);
 object_t *stm_bag_try_pop(stm_bag_t *);
+void stm_bag_tracefn(stm_bag_t *, void (object_t **));
 
 /* ==================== END ==================== */
 
diff --git a/c7/test/support.py b/c7/test/support.py
--- a/c7/test/support.py
+++ b/c7/test/support.py
@@ -178,6 +178,16 @@
 
 void _set_hashtable(object_t *obj, stm_hashtable_t *h);
 stm_hashtable_t *_get_hashtable(object_t *obj);
+
+typedef struct stm_bag_s stm_bag_t;
+stm_bag_t *stm_bag_create(void);
+void stm_bag_free(stm_bag_t *);
+void stm_bag_add(stm_bag_t *, object_t *);
+object_t *stm_bag_try_pop(stm_bag_t *);
+void stm_bag_tracefn(stm_bag_t *, void (object_t **));
+
+void _set_bag(object_t *obj, stm_bag_t *h);
+stm_bag_t *_get_bag(object_t *obj);
 """)
 
 
@@ -308,6 +318,20 @@
     return *(stm_hashtable_t *TLPREFIX *)field_addr;
 }
 
+void _set_bag(object_t *obj, stm_bag_t *bag)
+{
+    stm_char *field_addr = ((stm_char*)obj);
+    field_addr += SIZEOF_MYOBJ; /* header */
+    *(stm_bag_t *TLPREFIX *)field_addr = bag;
+}
+
+stm_bag_t *_get_bag(object_t *obj)
+{
+    stm_char *field_addr = ((stm_char*)obj);
+    field_addr += SIZEOF_MYOBJ; /* header */
+    return *(stm_bag_t *TLPREFIX *)field_addr;
+}
+
 void _set_ptr(object_t *obj, int n, object_t *v)
 {
     long nrefs = (long)((myobj_t*)obj)->type_id - 421420;
@@ -344,6 +368,9 @@
         if (myobj->type_id == 421418) {    /* hashtable entry */
             return sizeof(struct stm_hashtable_entry_s);
         }
+        if (myobj->type_id == 421417) {    /* bag */
+            return sizeof(struct myobj_s) + 1 * sizeof(void*);
+        }
         /* basic case: tid equals 42 plus the size of the object */
         assert(myobj->type_id >= 42 + sizeof(struct myobj_s));
         assert((myobj->type_id - 42) >= 16);
@@ -374,6 +401,12 @@
         object_t **ref = &((struct stm_hashtable_entry_s *)myobj)->object;
         visit(ref);
     }
+    if (myobj->type_id == 421417) {
+        /* bag */
+        stm_bag_t *b = *((stm_bag_t **)(myobj + 1));
+        stm_bag_tracefn(b, visit);
+        return;
+    }
     if (myobj->type_id < 421420) {
         /* basic case: no references */
         return;
@@ -394,6 +427,7 @@
     struct myobj_s *myobj = (struct myobj_s*)obj;
     assert(myobj->type_id != 421419);
     assert(myobj->type_id != 421418);
+    assert(myobj->type_id != 421417);
     if (myobj->type_id < 421420) {
         /* basic case: no references */
         return;
@@ -514,6 +548,18 @@
     assert lib._get_type_id(o) == 421419
     return lib._get_hashtable(o)
 
+def stm_allocate_bag():
+    o = lib.stm_allocate(16)
+    tid = 421417
+    lib._set_type_id(o, tid)
+    h = lib.stm_bag_create()
+    lib._set_bag(o, h)
+    return o
+
+def get_bag(o):
+    assert lib._get_type_id(o) == 421417
+    return lib._get_bag(o)
+
 def stm_get_weakref(o):
     return lib._get_weakref(o)
 
diff --git a/c7/test/test_bag.py b/c7/test/test_bag.py
new file mode 100644
--- /dev/null
+++ b/c7/test/test_bag.py
@@ -0,0 +1,69 @@
+from support import *
+import py
+
+
+class BagLooksEmpty(Exception):
+    pass
+
+def b_add(o, nvalue):
+    b = get_bag(o)
+    lib.stm_bag_add(b, nvalue)
+
+def b_pop(o):
+    b = get_bag(o)
+    r = lib.stm_bag_try_pop(b)
+    if not r:
+        raise BagLooksEmpty
+    return r
+
+
+class BaseTestBag(BaseTest):
+
+    def setup_method(self, meth):
+        BaseTest.setup_method(self, meth)
+        #
+        @ffi.callback("void(object_t *)")
+        def light_finalizer(obj):
+            print 'light_finalizer:', obj
+            try:
+                assert lib._get_type_id(obj) == 421417
+                self.seen_bags -= 1
+            except:
+                self.errors.append(sys.exc_info()[2])
+                raise
+
+        lib.stmcb_light_finalizer = light_finalizer
+        self._light_finalizer_keepalive = light_finalizer
+        self.seen_bags = 0
+        self.errors = []
+
+    def teardown_method(self, meth):
+        BaseTest.teardown_method(self, meth)
+        lib.stmcb_light_finalizer = ffi.NULL
+        assert self.errors == []
+        assert self.seen_bags == 0
+
+    def allocate_bag(self):
+        q = stm_allocate_bag()
+        lib.stm_enable_light_finalizer(q)
+        self.seen_bags += 1
+        return q
+
+
+class TestBag(BaseTestBag):
+
+    def test_small_push_pop(self):
+        self.start_transaction()
+        q = self.allocate_bag()
+        lp1 = stm_allocate(16)
+        lp2 = stm_allocate(16)
+        for i in range(4):
+            b_add(q, lp1)
+            b_add(q, lp2)
+        for j in range(4):
+            got = b_pop(q)
+            assert got == lp1
+            got = b_pop(q)
+            assert got == lp2
+        py.test.raises(BagLooksEmpty, b_pop, q)
+        py.test.raises(BagLooksEmpty, b_pop, q)


More information about the pypy-commit mailing list