forked from enlightenment/efl
evas/cserve2: Implement shared index and buffers
Only import the C file for now. Implement the following features: - Shared Arrays Store arrays of elements of fixed size in shm. - Shared Mempool Store random sized buffers in shm. These buffers are indexed in a Shared Array and are referred to using their index only. - Shared Strings Store strings in a shm in a way similar to Eina_Stringshare (except strings are referred to using an int index). - Include evas_cserve2_index.c to the compilation. - Declare shared index functions in header file. - Call init() and shutdown() on the shared index subsystem. - Add find and foreach functions
This commit is contained in:
parent
deb8776de5
commit
07fb7172d5
|
@ -1013,6 +1013,7 @@ bin/evas/evas_cserve2_requests.c \
|
||||||
bin/evas/evas_cserve2_fonts.c \
|
bin/evas/evas_cserve2_fonts.c \
|
||||||
bin/evas/evas_cserve2_scale.c \
|
bin/evas/evas_cserve2_scale.c \
|
||||||
bin/evas/evas_cserve2_main_loop_linux.c \
|
bin/evas/evas_cserve2_main_loop_linux.c \
|
||||||
|
bin/evas/evas_cserve2_index.c \
|
||||||
lib/evas/cserve2/evas_cs2_utils.h \
|
lib/evas/cserve2/evas_cs2_utils.h \
|
||||||
lib/evas/cserve2/evas_cs2_utils.c
|
lib/evas/cserve2/evas_cs2_utils.c
|
||||||
|
|
||||||
|
|
|
@ -316,4 +316,47 @@ void *cserve2_font_slave_cb(Slave_Thread_Data *sd, Slave_Command *cmd, const voi
|
||||||
void cserve2_font_source_ft_free(void *fontsource);
|
void cserve2_font_source_ft_free(void *fontsource);
|
||||||
void cserve2_font_ft_free(void *fontinfo);
|
void cserve2_font_ft_free(void *fontinfo);
|
||||||
|
|
||||||
|
// Shared buffers & indexes
|
||||||
|
void cserve2_shared_index_init(void);
|
||||||
|
void cserve2_shared_index_shutdown(void);
|
||||||
|
|
||||||
|
typedef struct _Shared_Array Shared_Array;
|
||||||
|
typedef struct _Shared_Mempool Shared_Mempool;
|
||||||
|
typedef Eina_Bool (* Shared_Array_Repack_Skip_Cb) (Shared_Array *, const void *);
|
||||||
|
|
||||||
|
// Shared arrays (arrays of fixed size object)
|
||||||
|
Shared_Array *cserve2_shared_array_new(int tag, int elemsize, int initcount);
|
||||||
|
const char *cserve2_shared_array_name_get(Shared_Array *sa);
|
||||||
|
void cserve2_shared_array_del(Shared_Array *sa);
|
||||||
|
int cserve2_shared_array_size_get(Shared_Array *sa);
|
||||||
|
int cserve2_shared_array_count_get(Shared_Array *sa);
|
||||||
|
int cserve2_shared_array_item_size_get(Shared_Array *sa);
|
||||||
|
int cserve2_shared_array_generation_id_get(Shared_Array *sa);
|
||||||
|
int cserve2_shared_array_size_set(Shared_Array *sa, int newcount);
|
||||||
|
int cserve2_shared_array_item_new(Shared_Array *sa);
|
||||||
|
void *cserve2_shared_array_item_data_get(Shared_Array *sa, int elemid);
|
||||||
|
Shared_Array *cserve2_shared_array_repack(Shared_Array *sa,
|
||||||
|
Shared_Array_Repack_Skip_Cb skip,
|
||||||
|
Eina_Compare_Cb cmp);
|
||||||
|
int cserve2_shared_array_item_find(Shared_Array *sa, void *data,
|
||||||
|
Eina_Compare_Cb cmp);
|
||||||
|
void *cserve2_shared_array_item_data_find(Shared_Array *sa, void *data,
|
||||||
|
Eina_Compare_Cb cmp);
|
||||||
|
int cserve2_shared_array_foreach(Shared_Array *sa, Eina_Each_Cb cb, void *data);
|
||||||
|
|
||||||
|
// Shared buffers and memory pools
|
||||||
|
Shared_Mempool *cserve2_shared_mempool_new(int initsize);
|
||||||
|
void cserve2_shared_mempool_del(Shared_Mempool *sm);
|
||||||
|
int cserve2_shared_mempool_buffer_new(Shared_Mempool *sm, int size);
|
||||||
|
int cserve2_shared_mempool_buffer_ref(Shared_Mempool *sm, int bufferid);
|
||||||
|
void cserve2_shared_mempool_buffer_del(Shared_Mempool *sm, int bufferid);
|
||||||
|
void *cserve2_shared_mempool_buffer_get(Shared_Mempool *sm, int bufferid);
|
||||||
|
|
||||||
|
|
||||||
|
// Shared strings
|
||||||
|
int cserve2_shared_string_add(const char *str);
|
||||||
|
int cserve2_shared_string_ref(int id);
|
||||||
|
void cserve2_shared_string_del(int id);
|
||||||
|
const char *cserve2_shared_string_get(int id);
|
||||||
|
|
||||||
#endif /* _EVAS_CSERVE2_H */
|
#endif /* _EVAS_CSERVE2_H */
|
||||||
|
|
|
@ -0,0 +1,878 @@
|
||||||
|
/* Shared index for cserve2.
|
||||||
|
* EXPERIMENTAL WORK.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "evas_cserve2.h"
|
||||||
|
#include "evas_cs2_utils.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct _Data_Shm Data_Shm;
|
||||||
|
typedef struct _Index_Entry Index_Entry;
|
||||||
|
typedef struct _Block Block;
|
||||||
|
typedef struct _Shared_Array_Header Shared_Array_Header;
|
||||||
|
typedef struct _Shared_Index Shared_Index;
|
||||||
|
|
||||||
|
static int _instances = 0;
|
||||||
|
|
||||||
|
// Static memory pool used for storing strings
|
||||||
|
static Shared_Mempool *_string_mempool = NULL;
|
||||||
|
|
||||||
|
// Map const char* --> buffer id (valid in _string_mempool)
|
||||||
|
static Eina_Hash *_string_entries = NULL;
|
||||||
|
|
||||||
|
struct _Data_Shm
|
||||||
|
{
|
||||||
|
Shm_Handle *shm;
|
||||||
|
char *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _Shared_Array_Header
|
||||||
|
{
|
||||||
|
int32_t tag;
|
||||||
|
int32_t elemsize;
|
||||||
|
int32_t count;
|
||||||
|
int32_t generation_id;
|
||||||
|
int32_t emptyidx;
|
||||||
|
int32_t _reserved1;
|
||||||
|
int32_t _reserved2;
|
||||||
|
int32_t _reserved3;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _Shared_Array
|
||||||
|
{
|
||||||
|
Data_Shm *ds;
|
||||||
|
Shared_Array_Header *header;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _Shared_Index
|
||||||
|
{
|
||||||
|
// Random buffer index
|
||||||
|
Shared_Array *sa;
|
||||||
|
int32_t lastid;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _Shared_Mempool
|
||||||
|
{
|
||||||
|
Data_Shm *ds;
|
||||||
|
Shared_Index *index;
|
||||||
|
int empty_size;
|
||||||
|
Block *empty_blocks;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Used for empty blocks. RB tree ordered by length.
|
||||||
|
struct _Block
|
||||||
|
{
|
||||||
|
EINA_RBTREE;
|
||||||
|
int32_t length;
|
||||||
|
int32_t offset;
|
||||||
|
int32_t shmid;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _Index_Entry
|
||||||
|
{
|
||||||
|
int32_t id; // Write last, can't be 0
|
||||||
|
int32_t refcount;
|
||||||
|
// Block entry
|
||||||
|
int32_t length;
|
||||||
|
int32_t offset;
|
||||||
|
int32_t shmid;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Data blocks will be aligned to blocks of DATA_BLOCKSIZE bytes to reduce
|
||||||
|
// fragmentation (after del). 16 is convenient for debugging with hd :)
|
||||||
|
#define DATA_BLOCKSIZE 8
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
_data_blocksize_roundup(int len)
|
||||||
|
{
|
||||||
|
return ((len + DATA_BLOCKSIZE - 1) / DATA_BLOCKSIZE) * DATA_BLOCKSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Eina_Rbtree_Direction
|
||||||
|
_block_rbtree_cmp(const Eina_Rbtree *l, const Eina_Rbtree *r,
|
||||||
|
void *data EINA_UNUSED)
|
||||||
|
{
|
||||||
|
const Block *left = (Block *) l;
|
||||||
|
const Block *right = (Block *) r;
|
||||||
|
|
||||||
|
if (!left)
|
||||||
|
return EINA_RBTREE_RIGHT;
|
||||||
|
|
||||||
|
if (!right)
|
||||||
|
return EINA_RBTREE_LEFT;
|
||||||
|
|
||||||
|
if (left->length <= right->length)
|
||||||
|
return EINA_RBTREE_LEFT;
|
||||||
|
else
|
||||||
|
return EINA_RBTREE_RIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
_block_rbtree_empty_spot_find(const Block *node, const void *key,
|
||||||
|
int key_length EINA_UNUSED,
|
||||||
|
void *data EINA_UNUSED)
|
||||||
|
{
|
||||||
|
int32_t length = (int32_t) (intptr_t) key;
|
||||||
|
|
||||||
|
// Found best spot
|
||||||
|
if (node->length == length)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// We're good, can we find better?
|
||||||
|
if (node->length > length)
|
||||||
|
{
|
||||||
|
Block *lson = (Block *) node->__rbtree.son[0];
|
||||||
|
|
||||||
|
if (lson && lson->length >= length)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// This is the best we can do...
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep calm and carry on
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
_block_rbtree_block_find(const Block *node, const void *key,
|
||||||
|
int key_length EINA_UNUSED,
|
||||||
|
void *data EINA_UNUSED)
|
||||||
|
{
|
||||||
|
const Index_Entry *ie = key;
|
||||||
|
|
||||||
|
// Found best spot
|
||||||
|
if ((node->length == ie->length)
|
||||||
|
&& (node->offset == ie->offset)
|
||||||
|
&& (node->shmid == ie->shmid))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// We're good, can we find better?
|
||||||
|
if (node->length > ie->length)
|
||||||
|
{
|
||||||
|
Block *lson = (Block *) node->__rbtree.son[0];
|
||||||
|
|
||||||
|
if (lson && lson->length >= ie->length)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// This is the best we can do...
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep calm and carry on
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Data shm
|
||||||
|
|
||||||
|
Data_Shm *
|
||||||
|
_shared_data_shm_new(int size)
|
||||||
|
{
|
||||||
|
Data_Shm *ds;
|
||||||
|
size_t mapping_size;
|
||||||
|
|
||||||
|
if (size <= 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ds = calloc(1, sizeof(Data_Shm));
|
||||||
|
if (!ds) return NULL;
|
||||||
|
|
||||||
|
mapping_size = cserve2_shm_size_normalize((size_t) size);
|
||||||
|
|
||||||
|
ds->shm = cserve2_shm_request("data", mapping_size);
|
||||||
|
if (!ds->shm)
|
||||||
|
{
|
||||||
|
ERR("Could not create shm of size %u", (unsigned) mapping_size);
|
||||||
|
free(ds);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ds->data = cserve2_shm_map(ds->shm);
|
||||||
|
if (!ds->data)
|
||||||
|
{
|
||||||
|
ERR("Could not map shm of size %u", (unsigned) mapping_size);
|
||||||
|
cserve2_shm_unref(ds->shm);
|
||||||
|
free(ds);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG("Created data shm of size %d: %d", size, cserve2_shm_id_get(ds->shm));
|
||||||
|
return ds;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_shared_data_shm_del(Data_Shm *ds)
|
||||||
|
{
|
||||||
|
if (!ds) return;
|
||||||
|
cserve2_shm_unref(ds->shm);
|
||||||
|
free(ds);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_shared_data_shm_resize(Data_Shm *ds, size_t newsize)
|
||||||
|
{
|
||||||
|
Shm_Handle *shm;
|
||||||
|
size_t mapping_size;
|
||||||
|
|
||||||
|
if (newsize <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
mapping_size = cserve2_shm_size_normalize(newsize);
|
||||||
|
cserve2_shm_unmap(ds->shm);
|
||||||
|
ds->data = NULL;
|
||||||
|
|
||||||
|
shm = cserve2_shm_resize(ds->shm, mapping_size);
|
||||||
|
if (!shm)
|
||||||
|
{
|
||||||
|
ERR("Could not resize shm %d to %u",
|
||||||
|
cserve2_shm_id_get(ds->shm), (unsigned) newsize);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ds->shm = shm;
|
||||||
|
ds->data = cserve2_shm_map(ds->shm);
|
||||||
|
if (!ds->data)
|
||||||
|
{
|
||||||
|
ERR("Failed to remap shm %d after resizing to %u bytes",
|
||||||
|
cserve2_shm_id_get(ds->shm), (unsigned) mapping_size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mapping_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Arrays
|
||||||
|
|
||||||
|
Shared_Array *
|
||||||
|
cserve2_shared_array_new(int tag, int elemsize, int initcount)
|
||||||
|
{
|
||||||
|
Shared_Array *sa;
|
||||||
|
Data_Shm *ds;
|
||||||
|
int mapping_size;
|
||||||
|
|
||||||
|
if (elemsize <= 0 || initcount < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
sa = calloc(1, sizeof(Shared_Array));
|
||||||
|
if (!sa) return NULL;
|
||||||
|
|
||||||
|
if (!initcount) initcount = 1;
|
||||||
|
mapping_size = cserve2_shm_size_normalize(elemsize * initcount
|
||||||
|
+ sizeof(Shared_Array_Header));
|
||||||
|
ds = _shared_data_shm_new(mapping_size);
|
||||||
|
if (!ds)
|
||||||
|
{
|
||||||
|
free(sa);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sa->ds = ds;
|
||||||
|
sa->header = (Shared_Array_Header *) ds->data;
|
||||||
|
sa->header->count = (mapping_size - sizeof(Shared_Array_Header)) / elemsize;
|
||||||
|
sa->header->elemsize = elemsize;
|
||||||
|
sa->header->generation_id = 1;
|
||||||
|
sa->header->emptyidx = 0;
|
||||||
|
sa->header->tag = tag;
|
||||||
|
memset(&sa->header->_reserved1, 0, sizeof(int32_t) * 3);
|
||||||
|
|
||||||
|
return sa;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
cserve2_shared_array_name_get(Shared_Array *sa)
|
||||||
|
{
|
||||||
|
if (!sa) return NULL;
|
||||||
|
return cserve2_shm_name_get(sa->ds->shm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cserve2_shared_array_del(Shared_Array *sa)
|
||||||
|
{
|
||||||
|
if (!sa) return;
|
||||||
|
_shared_data_shm_del(sa->ds);
|
||||||
|
free(sa);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cserve2_shared_array_size_get(Shared_Array *sa)
|
||||||
|
{
|
||||||
|
if (!sa) return -1;
|
||||||
|
return sa->header->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cserve2_shared_array_count_get(Shared_Array *sa)
|
||||||
|
{
|
||||||
|
if (!sa) return -1;
|
||||||
|
return sa->header->emptyidx;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cserve2_shared_array_item_size_get(Shared_Array *sa)
|
||||||
|
{
|
||||||
|
if (!sa) return -1;
|
||||||
|
return sa->header->elemsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cserve2_shared_array_generation_id_get(Shared_Array *sa)
|
||||||
|
{
|
||||||
|
if (!sa) return -1;
|
||||||
|
return sa->header->generation_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cserve2_shared_array_size_set(Shared_Array *sa, int newcount)
|
||||||
|
{
|
||||||
|
int mapping_size;
|
||||||
|
|
||||||
|
if (!sa) return -1;
|
||||||
|
mapping_size = cserve2_shm_size_normalize(sa->header->elemsize * newcount
|
||||||
|
+ sizeof(Shared_Array_Header));
|
||||||
|
if (_shared_data_shm_resize(sa->ds, mapping_size) < 0)
|
||||||
|
{
|
||||||
|
sa->header = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sa->header = (Shared_Array_Header *) sa->ds->data;
|
||||||
|
sa->header->count = (mapping_size - sizeof(Shared_Array_Header))
|
||||||
|
/ sa->header->elemsize;
|
||||||
|
|
||||||
|
return sa->header->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cserve2_shared_array_item_new(Shared_Array *sa)
|
||||||
|
{
|
||||||
|
if (!sa) return -1;
|
||||||
|
if (sa->header->emptyidx >= sa->header->count)
|
||||||
|
{
|
||||||
|
int newcount = cserve2_shared_array_size_set(sa, sa->header->count + 1);
|
||||||
|
if (newcount < 0) return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sa->header->emptyidx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void *
|
||||||
|
cserve2_shared_array_item_data(Shared_Array *sa)
|
||||||
|
{
|
||||||
|
return cserve2_shared_array_item_data_get(sa, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
cserve2_shared_array_item_data_get(Shared_Array *sa, int elemid)
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
if (!sa) return NULL;
|
||||||
|
if (elemid < 0 || elemid >= sa->header->count)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ptr = (char *) sa->header;
|
||||||
|
ptr += sizeof(Shared_Array_Header);
|
||||||
|
ptr += elemid * sa->header->elemsize;
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cserve2_shared_array_foreach(Shared_Array *sa, Eina_Each_Cb cb, void *data)
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
int k;
|
||||||
|
|
||||||
|
if (!sa || !cb) return -1;
|
||||||
|
ptr = sa->ds->data + sizeof(Shared_Array_Header);
|
||||||
|
|
||||||
|
for (k = 0; k < sa->header->emptyidx; k++)
|
||||||
|
{
|
||||||
|
if (!cb(sa, ptr, data))
|
||||||
|
break;
|
||||||
|
ptr += sa->header->elemsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
Shared_Array *
|
||||||
|
cserve2_shared_array_repack(Shared_Array *sa,
|
||||||
|
Shared_Array_Repack_Skip_Cb skip,
|
||||||
|
Eina_Compare_Cb cmp)
|
||||||
|
{
|
||||||
|
Eina_List *l = NULL;
|
||||||
|
Shared_Array *sa2;
|
||||||
|
const char *srcdata;
|
||||||
|
char *dstdata;
|
||||||
|
int k, elemsize, newcount = 0;
|
||||||
|
|
||||||
|
if (!sa || !skip || !cmp) return NULL;
|
||||||
|
srcdata = sa->ds->data + sizeof(Shared_Array_Header);
|
||||||
|
elemsize = sa->header->elemsize;
|
||||||
|
|
||||||
|
// Build ordered list of pointers
|
||||||
|
for (k = 0; k < sa->header->emptyidx; k++)
|
||||||
|
{
|
||||||
|
const char *data = srcdata + k * elemsize;
|
||||||
|
if (skip(sa, data)) continue;
|
||||||
|
l = eina_list_sorted_insert(l, cmp, data);
|
||||||
|
newcount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new array
|
||||||
|
sa2 = cserve2_shared_array_new(0, elemsize, newcount);
|
||||||
|
if (!sa)
|
||||||
|
{
|
||||||
|
ERR("Can not repack array: failed to create new array");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
sa2->header->generation_id = sa->header->generation_id + 1;
|
||||||
|
|
||||||
|
// Write data
|
||||||
|
dstdata = sa2->ds->data + sizeof(Shared_Array_Header);
|
||||||
|
while (l)
|
||||||
|
{
|
||||||
|
const char *data = eina_list_data_get(l);
|
||||||
|
l = eina_list_remove_list(l, l);
|
||||||
|
memcpy(dstdata, data, elemsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finalize & return
|
||||||
|
sa2->header->emptyidx = newcount;
|
||||||
|
sa2->header->tag = sa->header->tag;
|
||||||
|
return sa2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cserve2_shared_array_item_find(Shared_Array *sa, void *data,
|
||||||
|
Eina_Compare_Cb cmp)
|
||||||
|
{
|
||||||
|
int k;
|
||||||
|
const char *ptr;
|
||||||
|
|
||||||
|
if (!sa || !cmp) return -1;
|
||||||
|
|
||||||
|
// TODO: Fast search in the sorted zone
|
||||||
|
|
||||||
|
ptr = sa->ds->data;
|
||||||
|
|
||||||
|
// Linear search O(n)
|
||||||
|
for (k = 0; k < sa->header->emptyidx; k++)
|
||||||
|
{
|
||||||
|
if (!cmp(ptr, data))
|
||||||
|
return k;
|
||||||
|
ptr += sa->header->elemsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
cserve2_shared_array_item_data_find(Shared_Array *sa, void *data,
|
||||||
|
Eina_Compare_Cb cmp)
|
||||||
|
{
|
||||||
|
int elemid;
|
||||||
|
|
||||||
|
elemid = cserve2_shared_array_item_find(sa, data, cmp);
|
||||||
|
if (elemid < 0) return NULL;
|
||||||
|
|
||||||
|
return cserve2_shared_array_item_data_get(sa, elemid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Shared index (used by the random mempool)
|
||||||
|
|
||||||
|
static Index_Entry *
|
||||||
|
_shared_index_entry_new(Shared_Index *si)
|
||||||
|
{
|
||||||
|
Index_Entry *ie;
|
||||||
|
int id;
|
||||||
|
|
||||||
|
if (!si) return NULL;
|
||||||
|
|
||||||
|
id = cserve2_shared_array_item_new(si->sa);
|
||||||
|
if (id < 0) return NULL;
|
||||||
|
|
||||||
|
ie = cserve2_shared_array_item_data_get(si->sa, id);
|
||||||
|
ie->id = si->lastid++;
|
||||||
|
return ie;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Index_Entry *
|
||||||
|
_shared_index_entry_find(Shared_Index *si, int id)
|
||||||
|
{
|
||||||
|
int k, count;
|
||||||
|
|
||||||
|
if (!si) return NULL;
|
||||||
|
count = cserve2_shared_array_count_get(si->sa);
|
||||||
|
|
||||||
|
// FIXME: Linear search O(n)
|
||||||
|
for (k = 0; k < count; k++)
|
||||||
|
{
|
||||||
|
Index_Entry *ie;
|
||||||
|
ie = cserve2_shared_array_item_data_get(si->sa, k);
|
||||||
|
if (!ie) break;
|
||||||
|
if (ie->id == id)
|
||||||
|
return ie;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Shared_Index *
|
||||||
|
_shared_index_new()
|
||||||
|
{
|
||||||
|
Shared_Index *si;
|
||||||
|
Index_Entry *ie;
|
||||||
|
int tag = 1234; // FIXME?
|
||||||
|
|
||||||
|
si = calloc(1, sizeof(Shared_Index));
|
||||||
|
if (!si) return NULL;
|
||||||
|
|
||||||
|
si->sa = cserve2_shared_array_new(tag, sizeof(Index_Entry), 1);
|
||||||
|
if (!si->sa)
|
||||||
|
{
|
||||||
|
free(si);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
si->lastid = 0;
|
||||||
|
ie = _shared_index_entry_new(si);
|
||||||
|
if (!ie)
|
||||||
|
{
|
||||||
|
cserve2_shared_array_del(si->sa);
|
||||||
|
free(si);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return si;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_shared_index_del(Shared_Index *si)
|
||||||
|
{
|
||||||
|
if (!si) return;
|
||||||
|
cserve2_shared_array_del(si->sa);
|
||||||
|
free(si);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Shared memory pool
|
||||||
|
|
||||||
|
Shared_Mempool *
|
||||||
|
cserve2_shared_mempool_new(int initsize)
|
||||||
|
{
|
||||||
|
Shared_Mempool *sm;
|
||||||
|
size_t mapping_size;
|
||||||
|
|
||||||
|
if (initsize < 0) return NULL;
|
||||||
|
|
||||||
|
sm = calloc(1, sizeof(Shared_Mempool));
|
||||||
|
if (!sm) return NULL;
|
||||||
|
|
||||||
|
if (!initsize) initsize = 1;
|
||||||
|
mapping_size = cserve2_shm_size_normalize((size_t) initsize);
|
||||||
|
|
||||||
|
sm->ds = _shared_data_shm_new(mapping_size);
|
||||||
|
if (!sm->ds)
|
||||||
|
{
|
||||||
|
free(sm);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sm->index = _shared_index_new();
|
||||||
|
if (!sm->index)
|
||||||
|
{
|
||||||
|
_shared_data_shm_del(sm->ds);
|
||||||
|
free(sm);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sm->empty_size = mapping_size;
|
||||||
|
return sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_shared_mempool_block_del(Eina_Rbtree *node, void *data EINA_UNUSED)
|
||||||
|
{
|
||||||
|
Block *blk = (Block *) node;
|
||||||
|
free(blk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cserve2_shared_mempool_del(Shared_Mempool *sm)
|
||||||
|
{
|
||||||
|
if (!sm) return;
|
||||||
|
eina_rbtree_delete(EINA_RBTREE_GET(sm->empty_blocks),
|
||||||
|
EINA_RBTREE_FREE_CB(_shared_mempool_block_del), sm);
|
||||||
|
_shared_data_shm_del(sm->ds);
|
||||||
|
_shared_index_del(sm->index);
|
||||||
|
free(sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Index_Entry *
|
||||||
|
_shared_mempool_buffer_new(Shared_Mempool *sm, int size)
|
||||||
|
{
|
||||||
|
|
||||||
|
Index_Entry *ie;
|
||||||
|
Block *blk;
|
||||||
|
int mapping_size, new_mapping_size;
|
||||||
|
int rsize = _data_blocksize_roundup(size);
|
||||||
|
|
||||||
|
if (!sm) return NULL;
|
||||||
|
if (size <= 0) return NULL;
|
||||||
|
|
||||||
|
mapping_size = cserve2_shm_map_size_get(sm->ds->shm);
|
||||||
|
|
||||||
|
ie = _shared_index_entry_new(sm->index);
|
||||||
|
if (!ie) return NULL;
|
||||||
|
|
||||||
|
// Append if possible
|
||||||
|
if (rsize <= sm->empty_size)
|
||||||
|
{
|
||||||
|
ie->length = rsize;
|
||||||
|
ie->offset = mapping_size - sm->empty_size;
|
||||||
|
ie->shmid = cserve2_shm_id_get(sm->ds->shm);
|
||||||
|
ie->refcount = 1;
|
||||||
|
sm->empty_size -= rsize;
|
||||||
|
return ie;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find empty spot
|
||||||
|
blk = (Block *) eina_rbtree_inline_lookup(
|
||||||
|
EINA_RBTREE_GET(sm->empty_blocks), (void *) (intptr_t) rsize, 0,
|
||||||
|
EINA_RBTREE_CMP_KEY_CB(_block_rbtree_empty_spot_find), NULL);
|
||||||
|
if (blk && blk->length >= rsize)
|
||||||
|
{
|
||||||
|
ie->length = blk->length;
|
||||||
|
ie->offset = blk->offset;
|
||||||
|
ie->shmid = cserve2_shm_id_get(sm->ds->shm);
|
||||||
|
ie->refcount = 1;
|
||||||
|
|
||||||
|
sm->empty_blocks = (Block *) eina_rbtree_inline_remove(
|
||||||
|
EINA_RBTREE_GET(sm->empty_blocks), EINA_RBTREE_GET(blk),
|
||||||
|
EINA_RBTREE_CMP_NODE_CB(_block_rbtree_cmp), NULL);
|
||||||
|
if (blk->length == rsize)
|
||||||
|
free(blk);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
blk->length -= rsize;
|
||||||
|
blk->offset += rsize;
|
||||||
|
sm->empty_blocks = (Block *) eina_rbtree_inline_insert(
|
||||||
|
EINA_RBTREE_GET(sm->empty_blocks), EINA_RBTREE_GET(blk),
|
||||||
|
EINA_RBTREE_CMP_NODE_CB(_block_rbtree_cmp), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ie;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grow mempool
|
||||||
|
new_mapping_size = _shared_data_shm_resize(
|
||||||
|
sm->ds, mapping_size + rsize - sm->empty_size);
|
||||||
|
if (new_mapping_size < 0)
|
||||||
|
{
|
||||||
|
memset(ie, 0, sizeof(Index_Entry));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ie->length = rsize;
|
||||||
|
ie->offset = mapping_size - sm->empty_size;
|
||||||
|
ie->shmid = cserve2_shm_id_get(sm->ds->shm);
|
||||||
|
ie->refcount = 1;
|
||||||
|
sm->empty_size += (new_mapping_size - mapping_size) - rsize;
|
||||||
|
return ie;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cserve2_shared_mempool_buffer_new(Shared_Mempool *sm, int size)
|
||||||
|
{
|
||||||
|
Index_Entry *ie;
|
||||||
|
|
||||||
|
ie = _shared_mempool_buffer_new(sm, size);
|
||||||
|
if (!ie) return -1;
|
||||||
|
|
||||||
|
return ie->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cserve2_shared_mempool_buffer_ref(Shared_Mempool *sm, int bufferid)
|
||||||
|
{
|
||||||
|
Index_Entry *ie;
|
||||||
|
|
||||||
|
if (!sm) return -1;
|
||||||
|
ie = _shared_index_entry_find(sm->index, bufferid);
|
||||||
|
if (!ie) return -1;
|
||||||
|
|
||||||
|
if (!ie->refcount)
|
||||||
|
{
|
||||||
|
Block *blk = (Block *)
|
||||||
|
eina_rbtree_inline_lookup(EINA_RBTREE_GET(sm->empty_blocks),
|
||||||
|
ie, sizeof(Index_Entry),
|
||||||
|
EINA_RBTREE_CMP_KEY_CB(
|
||||||
|
_block_rbtree_block_find),
|
||||||
|
sm);
|
||||||
|
if (blk && (blk->length == ie->length)
|
||||||
|
&& (blk->offset == ie->offset)
|
||||||
|
&& (blk->shmid == ie->shmid))
|
||||||
|
{
|
||||||
|
sm->empty_blocks = (Block *) eina_rbtree_inline_remove(
|
||||||
|
EINA_RBTREE_GET(sm->empty_blocks), EINA_RBTREE_GET(blk),
|
||||||
|
EINA_RBTREE_CMP_NODE_CB(_block_rbtree_cmp), NULL);
|
||||||
|
free(blk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ie->refcount++;
|
||||||
|
return ie->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cserve2_shared_mempool_buffer_del(Shared_Mempool *sm, int bufferid)
|
||||||
|
{
|
||||||
|
Index_Entry *ie;
|
||||||
|
|
||||||
|
if (!sm || !bufferid) return;
|
||||||
|
ie = _shared_index_entry_find(sm->index, bufferid);
|
||||||
|
if (!ie || ie->refcount <= 0)
|
||||||
|
{
|
||||||
|
CRIT("Tried to delete invalid buffer or with refcount 0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ie->refcount--;
|
||||||
|
if (!ie->refcount)
|
||||||
|
{
|
||||||
|
Block *newblk = calloc(1, sizeof(Block));
|
||||||
|
newblk->length = ie->length;
|
||||||
|
newblk->offset = ie->offset;
|
||||||
|
newblk->shmid = ie->shmid;
|
||||||
|
sm->empty_blocks = (Block *) eina_rbtree_inline_insert(
|
||||||
|
EINA_RBTREE_GET(sm->empty_blocks), EINA_RBTREE_GET(newblk),
|
||||||
|
EINA_RBTREE_CMP_NODE_CB(_block_rbtree_cmp), NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
cserve2_shared_mempool_buffer_get(Shared_Mempool *sm, int bufferid)
|
||||||
|
{
|
||||||
|
Index_Entry *ie;
|
||||||
|
char *data;
|
||||||
|
|
||||||
|
if (!sm) return NULL;
|
||||||
|
ie = _shared_index_entry_find(sm->index, bufferid);
|
||||||
|
if (!ie || ie->refcount <= 0)
|
||||||
|
{
|
||||||
|
CRIT("Tried to access invalid buffer or with refcount 0");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = sm->ds->data + ie->offset;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Shared strings
|
||||||
|
|
||||||
|
int
|
||||||
|
cserve2_shared_string_add(const char *str)
|
||||||
|
{
|
||||||
|
Index_Entry *ie;
|
||||||
|
char *data;
|
||||||
|
int len, id;
|
||||||
|
|
||||||
|
if (!str) return -1;
|
||||||
|
|
||||||
|
// Find in known strings
|
||||||
|
id = (int) (intptr_t) eina_hash_find(_string_entries, str);
|
||||||
|
if (id > 0)
|
||||||
|
{
|
||||||
|
ie = _shared_index_entry_find(_string_mempool->index, id);
|
||||||
|
if (!ie || ie->refcount <= 0)
|
||||||
|
{
|
||||||
|
CRIT("String found in hash but not in mempool!");
|
||||||
|
eina_hash_del(_string_entries, str, (void *) (intptr_t) id);
|
||||||
|
goto new_entry;
|
||||||
|
}
|
||||||
|
ie->refcount++;
|
||||||
|
return ie->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new entry
|
||||||
|
new_entry:
|
||||||
|
len = strlen(str) + 1;
|
||||||
|
ie = _shared_mempool_buffer_new(_string_mempool, len);
|
||||||
|
if (!ie)
|
||||||
|
{
|
||||||
|
ERR("Could not store new string in shm");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
eina_hash_add(_string_entries, str, (void *) (intptr_t) ie->id);
|
||||||
|
data = _string_mempool->ds->data + ie->offset;
|
||||||
|
memcpy(data, str, len);
|
||||||
|
return ie->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cserve2_shared_string_ref(int id)
|
||||||
|
{
|
||||||
|
if (!id) return 0;
|
||||||
|
return cserve2_shared_mempool_buffer_ref(_string_mempool, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cserve2_shared_string_del(int id)
|
||||||
|
{
|
||||||
|
if (!id) return;
|
||||||
|
if (_shared_mempool_buffer_del(_string_mempool, id))
|
||||||
|
{
|
||||||
|
if (!eina_hash_del_by_data(_string_entries, (void *) (intptr_t) id))
|
||||||
|
CRIT("Invalid free");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
cserve2_shared_string_get(int id)
|
||||||
|
{
|
||||||
|
if (!id) return NULL;
|
||||||
|
return cserve2_shared_mempool_buffer_get(_string_mempool, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Init/destroy
|
||||||
|
|
||||||
|
void
|
||||||
|
cserve2_shared_index_init(void)
|
||||||
|
{
|
||||||
|
if (!_instances)
|
||||||
|
{
|
||||||
|
DBG("Initializing shared index");
|
||||||
|
_string_mempool = cserve2_shared_mempool_new(4096);
|
||||||
|
_string_entries = eina_hash_string_djb2_new(NULL);
|
||||||
|
}
|
||||||
|
_instances++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cserve2_shared_index_shutdown(void)
|
||||||
|
{
|
||||||
|
_instances--;
|
||||||
|
if (!_instances)
|
||||||
|
{
|
||||||
|
DBG("Destroying shared index");
|
||||||
|
cserve2_shared_mempool_del(_string_mempool);
|
||||||
|
eina_hash_free(_string_entries);
|
||||||
|
|
||||||
|
_string_mempool = NULL;
|
||||||
|
_string_entries = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -327,34 +327,26 @@ main(int argc EINA_UNUSED, const char *argv[])
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
cserve2_requests_init();
|
|
||||||
|
|
||||||
cserve2_scale_init();
|
|
||||||
|
|
||||||
cserve2_font_init();
|
|
||||||
|
|
||||||
cserve2_cache_init();
|
|
||||||
|
|
||||||
cserve2_shm_init();
|
cserve2_shm_init();
|
||||||
|
cserve2_shared_index_init();
|
||||||
|
cserve2_requests_init();
|
||||||
|
cserve2_scale_init();
|
||||||
|
cserve2_font_init();
|
||||||
|
cserve2_cache_init();
|
||||||
_clients_setup();
|
_clients_setup();
|
||||||
|
|
||||||
cserve2_main_loop_run();
|
cserve2_main_loop_run();
|
||||||
|
|
||||||
_clients_finish();
|
_clients_finish();
|
||||||
|
|
||||||
cserve2_cache_shutdown();
|
cserve2_cache_shutdown();
|
||||||
|
|
||||||
cserve2_font_shutdown();
|
cserve2_font_shutdown();
|
||||||
|
|
||||||
cserve2_scale_shutdown();
|
cserve2_scale_shutdown();
|
||||||
|
|
||||||
cserve2_requests_shutdown();
|
cserve2_requests_shutdown();
|
||||||
|
|
||||||
cserve2_slaves_shutdown();
|
cserve2_slaves_shutdown();
|
||||||
|
|
||||||
cserve2_main_loop_finish();
|
cserve2_main_loop_finish();
|
||||||
|
|
||||||
|
cserve2_shared_index_shutdown();
|
||||||
cserve2_shm_shutdown();
|
cserve2_shm_shutdown();
|
||||||
|
|
||||||
eina_prefix_free(_evas_cserve2_pfx);
|
eina_prefix_free(_evas_cserve2_pfx);
|
||||||
|
|
Loading…
Reference in New Issue