async possible race
[vg.git] / vg_mem_pool.h
1 #ifndef VG_MEM_POOL_H
2 #define VG_MEM_POOL_H
3
4 #include "vg_mem.h"
5 #include "stddef.h"
6 #include "vg_stdint.h"
7
8 typedef struct vg_pool vg_pool;
9 typedef struct vg_pool_node vg_pool_node;
10
11 /* this goes in your structures */
12 struct vg_pool_node {
13 u16 l, r, ref_count;
14 };
15
16 struct vg_pool {
17 void *buffer; /* array which holds the real data */
18 u16 count, head, tail;
19 size_t stride, offset;
20 };
21
22 static vg_pool_node *vg_pool_nodeptr ( vg_pool *pool, u16 id );
23 static void *vg_pool_item ( vg_pool *pool, u16 id );
24 static void vg_pool_init ( vg_pool *pool );
25 static u16 vg_pool_id ( vg_pool *pool, void *item );
26 static u16 vg_pool_lru ( vg_pool *pool );
27 static void vg_pool_watch ( vg_pool *pool, u16 id );
28 static void vg_pool_unwatch ( vg_pool *pool, u16 id );
29
30 /* implementation
31 * -------------------------------------------------------------------------- */
32
33 static vg_pool_node *vg_pool_nodeptr( vg_pool *pool, u16 id ){
34 if( !id ) return NULL;
35 else {
36 return pool->buffer + (pool->stride*(id-1)) + pool->offset;
37 }
38 }
39
40 static void *vg_pool_item( vg_pool *pool, u16 id ){
41 if( !id ) return NULL;
42 else return pool->buffer + pool->stride*(size_t)(id-1);
43 }
44
45 static void vg_pool_init( vg_pool *pool ){
46 pool->head = 1;
47 pool->tail = pool->count;
48 for( u16 ib=1; ib <= pool->count; ib++ ){
49 vg_pool_node *nb = vg_pool_nodeptr( pool, ib );
50
51 u16 ia = ib-1, ic = ib+1;
52 nb->l = ia;
53 nb->r = ic<=pool->count? ic: 0;
54 nb->ref_count = 0;
55 }
56 }
57
58 static u16 vg_pool_id( vg_pool *pool, void *item ){
59 return ((item - pool->buffer) / pool->stride) + 1;
60 }
61
62 static void vg_pool_unlink( vg_pool *pool, u16 id ){
63 vg_pool_node *node = vg_pool_nodeptr( pool, id );
64 vg_pool_node *l = vg_pool_nodeptr( pool, node->l ),
65 *r = vg_pool_nodeptr( pool, node->r );
66
67 if( pool->head == id ) pool->head = node->r;
68 if( pool->tail == id ) pool->tail = node->l;
69
70 if( l ) l->r = node->r;
71 if( r ) r->l = node->l;
72
73 node->r = 0;
74 node->l = 0;
75 }
76
77 static u16 vg_pool_lru( vg_pool *pool ){
78 u16 head = pool->head;
79 if( !head ) return 0;
80
81 vg_pool_unlink( pool, head );
82 return head;
83 }
84
85 static void vg_pool_watch( vg_pool *pool, u16 id ){
86 vg_pool_node *node = vg_pool_nodeptr( pool, id );
87
88 if( !node->ref_count ){
89 vg_pool_unlink( pool, id );
90 }
91
92 if( node->ref_count >= 128 )
93 vg_fatal_error( "pool watch missmatch (limit is 128)\n" );
94
95 node->ref_count ++;
96 }
97
98 /* if after this no more watches, places back into the volatile list */
99 static void vg_pool_unwatch( vg_pool *pool, u16 id ){
100 vg_pool_node *node = vg_pool_nodeptr( pool, id );
101
102 if( node->ref_count == 0 )
103 vg_fatal_error( "pool unwatch missmatch (no watchers)\n" );
104
105 node->ref_count --;
106 if( !node->ref_count ){
107 vg_pool_node *head = vg_pool_nodeptr( pool, pool->head ),
108 *tail = vg_pool_nodeptr( pool, pool->tail );
109
110 if( tail ) tail->r = id;
111 node->l = pool->tail;
112 pool->tail = id;
113 if( !head ) pool->head = id;
114 }
115 }
116
117 #endif /* VG_MEM_POOL_H */