Commit a46480cfd06 by Armin Rigo

First tests pass

--HG--
branch : bag
parent 82bbe5ad5e6
......@@ -42,8 +42,7 @@ is done with careful compare-and-swaps.
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 @@ stm_bag_t *stm_bag_create(void)
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 @@ void stm_bag_free(stm_bag_t *bag)
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();
}
......@@ -193,3 +193,22 @@ static bool tree_delete_item(struct tree_s *tree, uintptr_t addr)
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;
}
......@@ -222,23 +222,27 @@ static inline bool tree_contains(struct tree_s *tree, uintptr_t addr)
/************************************************************/
#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]);
}
......@@ -39,3 +39,4 @@
#include "stm/rewind_setjmp.c"
#include "stm/finalizer.c"
#include "stm/hashtable.c"
#include "stm/bag.c"
......@@ -559,6 +559,7 @@ 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 **));
/* ==================== END ==================== */
......
......@@ -178,6 +178,16 @@ void stm_hashtable_tracefn(stm_hashtable_t *, void (object_t **));
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 @@ stm_hashtable_t *_get_hashtable(object_t *obj)
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 @@ ssize_t stmcb_size_rounded_up(struct object_s *obj)
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 @@ void stmcb_trace(struct object_s *obj, void visit(object_t **))
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 @@ void stmcb_trace_cards(struct object_s *obj, void visit(object_t **),
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 @@ def get_hashtable(o):
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)
......
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)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment