diff --git a/array/iarray_allocate.c b/array/iarray_allocate.c index 9618820..bddd53b 100644 --- a/array/iarray_allocate.c +++ b/array/iarray_allocate.c @@ -18,24 +18,35 @@ static iarray_page* new_page(size_t pagesize) { void* iarray_allocate(iarray* ia,size_t pos) { size_t index,prevlen=ia->len; + /* first, find the linked list of pages */ iarray_page** p=&ia->pages[pos%(sizeof(ia->pages)/sizeof(ia->pages[0]))]; + /* this is here so we don't munmap and then re-mmap pages when a + * certain path makes it necessary to mmap several pages into the + * linked list and we are competing with another thread that does the + * same thing */ iarray_page* newpage=0; - for (index=0; poselemperpage; index+=ia->elemperpage) { + /* since we have a fan-out of 16, on page 0 the elements are 0, 16, 32, ... + * so we divide pos by the fan-out here */ + size_t realpos=pos; + pos /= sizeof(ia->pages)/sizeof(ia->pages[0]); + /* now walk the linked list of pages until we reach the one we want */ + for (index=0; ; index+=ia->elemperpage) { if (!*p) { if (!newpage) if (!(newpage=new_page(ia->bytesperpage))) return 0; if (__CAS(p,0,newpage)==0) newpage=0; } - if (index+ia->elemperpage>pos) { - size_t l; - if (newpage) munmap(newpage,ia->bytesperpage); - do { - l=__CAS(&ia->len,prevlen,pos); - } while (ldata[(pos-index)*ia->elemsize]; - } + if (index+ia->elemperpage>pos) + break; p=&(*p)->next; } - return 0; // can't happen + if (newpage) munmap(newpage,ia->bytesperpage); + { + size_t l; + do { + l=__CAS(&ia->len,prevlen,realpos); + } while (ldata[(pos-index)*ia->elemsize]; } diff --git a/array/iarray_get.c b/array/iarray_get.c index 026abc4..66b730d 100644 --- a/array/iarray_get.c +++ b/array/iarray_get.c @@ -3,6 +3,7 @@ void* iarray_get(iarray* ia,size_t pos) { size_t index; iarray_page* p=ia->pages[pos%(sizeof(ia->pages)/sizeof(ia->pages[0]))]; + pos /= sizeof(ia->pages)/sizeof(ia->pages[0]); for (index=0; p; p=p->next, index+=ia->elemperpage) { if (pos>=index && poselemperpage) return &p->data[(pos-index)*ia->elemsize]; diff --git a/iarray.h b/iarray.h index 6a6a35e..12b0e0f 100644 --- a/iarray.h +++ b/iarray.h @@ -17,6 +17,18 @@ #include #endif +/* The basic data structure is a static array of pointers to pages. + * Each page also contains a next pointer to form a linked list. + * To get to element n, you take n % the number of elements in the + * static array (iarray->pages) to get to the list of pages that + * contains it. Then keep going to the next page until you are on the + * right page. + * Note: The elements on each page are not contiguous. If the fanout is + * 16, the indices on page 0 are 0, 16, 32, ... + * To get to element 0, you'd go to iarray->pages[0].data, + * to get to element 1, you'd go to iarray->pages[1].data, + * to get to element 16, you'd go to iarray->pages[0].data+iarray->elemsize. + */ typedef struct _iarray_page { struct _iarray_page* next; char data[];