diff options
-rw-r--r-- | src/Makefile_Evas.am | 1 | ||||
-rw-r--r-- | src/bin/evas/evas_cserve2.h | 43 | ||||
-rw-r--r-- | src/bin/evas/evas_cserve2_index.c | 878 | ||||
-rw-r--r-- | src/bin/evas/evas_cserve2_main.c | 14 |
4 files changed, 925 insertions, 11 deletions
diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am index 29bea4b603..de3636bf7d 100644 --- a/src/Makefile_Evas.am +++ b/src/Makefile_Evas.am | |||
@@ -1013,6 +1013,7 @@ bin/evas/evas_cserve2_requests.c \ | |||
1013 | bin/evas/evas_cserve2_fonts.c \ | 1013 | bin/evas/evas_cserve2_fonts.c \ |
1014 | bin/evas/evas_cserve2_scale.c \ | 1014 | bin/evas/evas_cserve2_scale.c \ |
1015 | bin/evas/evas_cserve2_main_loop_linux.c \ | 1015 | bin/evas/evas_cserve2_main_loop_linux.c \ |
1016 | bin/evas/evas_cserve2_index.c \ | ||
1016 | lib/evas/cserve2/evas_cs2_utils.h \ | 1017 | lib/evas/cserve2/evas_cs2_utils.h \ |
1017 | lib/evas/cserve2/evas_cs2_utils.c | 1018 | lib/evas/cserve2/evas_cs2_utils.c |
1018 | 1019 | ||
diff --git a/src/bin/evas/evas_cserve2.h b/src/bin/evas/evas_cserve2.h index e7e53f3774..b6bdff3e63 100644 --- a/src/bin/evas/evas_cserve2.h +++ b/src/bin/evas/evas_cserve2.h | |||
@@ -316,4 +316,47 @@ void *cserve2_font_slave_cb(Slave_Thread_Data *sd, Slave_Command *cmd, const voi | |||
316 | void cserve2_font_source_ft_free(void *fontsource); | 316 | void cserve2_font_source_ft_free(void *fontsource); |
317 | void cserve2_font_ft_free(void *fontinfo); | 317 | void cserve2_font_ft_free(void *fontinfo); |
318 | 318 | ||
319 | // Shared buffers & indexes | ||
320 | void cserve2_shared_index_init(void); | ||
321 | void cserve2_shared_index_shutdown(void); | ||
322 | |||
323 | typedef struct _Shared_Array Shared_Array; | ||
324 | typedef struct _Shared_Mempool Shared_Mempool; | ||
325 | typedef Eina_Bool (* Shared_Array_Repack_Skip_Cb) (Shared_Array *, const void *); | ||
326 | |||
327 | // Shared arrays (arrays of fixed size object) | ||
328 | Shared_Array *cserve2_shared_array_new(int tag, int elemsize, int initcount); | ||
329 | const char *cserve2_shared_array_name_get(Shared_Array *sa); | ||
330 | void cserve2_shared_array_del(Shared_Array *sa); | ||
331 | int cserve2_shared_array_size_get(Shared_Array *sa); | ||
332 | int cserve2_shared_array_count_get(Shared_Array *sa); | ||
333 | int cserve2_shared_array_item_size_get(Shared_Array *sa); | ||
334 | int cserve2_shared_array_generation_id_get(Shared_Array *sa); | ||
335 | int cserve2_shared_array_size_set(Shared_Array *sa, int newcount); | ||
336 | int cserve2_shared_array_item_new(Shared_Array *sa); | ||
337 | void *cserve2_shared_array_item_data_get(Shared_Array *sa, int elemid); | ||
338 | Shared_Array *cserve2_shared_array_repack(Shared_Array *sa, | ||
339 | Shared_Array_Repack_Skip_Cb skip, | ||
340 | Eina_Compare_Cb cmp); | ||
341 | int cserve2_shared_array_item_find(Shared_Array *sa, void *data, | ||
342 | Eina_Compare_Cb cmp); | ||
343 | void *cserve2_shared_array_item_data_find(Shared_Array *sa, void *data, | ||
344 | Eina_Compare_Cb cmp); | ||
345 | int cserve2_shared_array_foreach(Shared_Array *sa, Eina_Each_Cb cb, void *data); | ||
346 | |||
347 | // Shared buffers and memory pools | ||
348 | Shared_Mempool *cserve2_shared_mempool_new(int initsize); | ||
349 | void cserve2_shared_mempool_del(Shared_Mempool *sm); | ||
350 | int cserve2_shared_mempool_buffer_new(Shared_Mempool *sm, int size); | ||
351 | int cserve2_shared_mempool_buffer_ref(Shared_Mempool *sm, int bufferid); | ||
352 | void cserve2_shared_mempool_buffer_del(Shared_Mempool *sm, int bufferid); | ||
353 | void *cserve2_shared_mempool_buffer_get(Shared_Mempool *sm, int bufferid); | ||
354 | |||
355 | |||
356 | // Shared strings | ||
357 | int cserve2_shared_string_add(const char *str); | ||
358 | int cserve2_shared_string_ref(int id); | ||
359 | void cserve2_shared_string_del(int id); | ||
360 | const char *cserve2_shared_string_get(int id); | ||
361 | |||
319 | #endif /* _EVAS_CSERVE2_H */ | 362 | #endif /* _EVAS_CSERVE2_H */ |
diff --git a/src/bin/evas/evas_cserve2_index.c b/src/bin/evas/evas_cserve2_index.c new file mode 100644 index 0000000000..2579104a7f --- /dev/null +++ b/src/bin/evas/evas_cserve2_index.c | |||
@@ -0,0 +1,878 @@ | |||
1 | /* Shared index for cserve2. | ||
2 | * EXPERIMENTAL WORK. | ||
3 | */ | ||
4 | |||
5 | #ifdef HAVE_CONFIG_H | ||
6 | # include "config.h" | ||
7 | #endif | ||
8 | |||
9 | #include "evas_cserve2.h" | ||
10 | #include "evas_cs2_utils.h" | ||
11 | |||
12 | #include <stdint.h> | ||
13 | |||
14 | typedef struct _Data_Shm Data_Shm; | ||
15 | typedef struct _Index_Entry Index_Entry; | ||
16 | typedef struct _Block Block; | ||
17 | typedef struct _Shared_Array_Header Shared_Array_Header; | ||
18 | typedef struct _Shared_Index Shared_Index; | ||
19 | |||
20 | static int _instances = 0; | ||
21 | |||
22 | // Static memory pool used for storing strings | ||
23 | static Shared_Mempool *_string_mempool = NULL; | ||
24 | |||
25 | // Map const char* --> buffer id (valid in _string_mempool) | ||
26 | static Eina_Hash *_string_entries = NULL; | ||
27 | |||
28 | struct _Data_Shm | ||
29 | { | ||
30 | Shm_Handle *shm; | ||
31 | char *data; | ||
32 | }; | ||
33 | |||
34 | struct _Shared_Array_Header | ||
35 | { | ||
36 | int32_t tag; | ||
37 | int32_t elemsize; | ||
38 | int32_t count; | ||
39 | int32_t generation_id; | ||
40 | int32_t emptyidx; | ||
41 | int32_t _reserved1; | ||
42 | int32_t _reserved2; | ||
43 | int32_t _reserved3; | ||
44 | }; | ||
45 | |||
46 | struct _Shared_Array | ||
47 | { | ||
48 | Data_Shm *ds; | ||
49 | Shared_Array_Header *header; | ||
50 | }; | ||
51 | |||
52 | struct _Shared_Index | ||
53 | { | ||
54 | // Random buffer index | ||
55 | Shared_Array *sa; | ||
56 | int32_t lastid; | ||
57 | }; | ||
58 | |||
59 | struct _Shared_Mempool | ||
60 | { | ||
61 | Data_Shm *ds; | ||
62 | Shared_Index *index; | ||
63 | int empty_size; | ||
64 | Block *empty_blocks; | ||
65 | }; | ||
66 | |||
67 | // Used for empty blocks. RB tree ordered by length. | ||
68 | struct _Block | ||
69 | { | ||
70 | EINA_RBTREE; | ||
71 | int32_t length; | ||
72 | int32_t offset; | ||
73 | int32_t shmid; | ||
74 | }; | ||
75 | |||
76 | struct _Index_Entry | ||
77 | { | ||
78 | int32_t id; // Write last, can't be 0 | ||
79 | int32_t refcount; | ||
80 | // Block entry | ||
81 | int32_t length; | ||
82 | int32_t offset; | ||
83 | int32_t shmid; | ||
84 | }; | ||
85 | |||
86 | |||
87 | // Data blocks will be aligned to blocks of DATA_BLOCKSIZE bytes to reduce | ||
88 | // fragmentation (after del). 16 is convenient for debugging with hd :) | ||
89 | #define DATA_BLOCKSIZE 8 | ||
90 | |||
91 | static inline int | ||
92 | _data_blocksize_roundup(int len) | ||
93 | { | ||
94 | return ((len + DATA_BLOCKSIZE - 1) / DATA_BLOCKSIZE) * DATA_BLOCKSIZE; | ||
95 | } | ||
96 | |||
97 | static Eina_Rbtree_Direction | ||
98 | _block_rbtree_cmp(const Eina_Rbtree *l, const Eina_Rbtree *r, | ||
99 | void *data EINA_UNUSED) | ||
100 | { | ||
101 | const Block *left = (Block *) l; | ||
102 | const Block *right = (Block *) r; | ||
103 | |||
104 | if (!left) | ||
105 | return EINA_RBTREE_RIGHT; | ||
106 | |||
107 | if (!right) | ||
108 | return EINA_RBTREE_LEFT; | ||
109 | |||
110 | if (left->length <= right->length) | ||
111 | return EINA_RBTREE_LEFT; | ||
112 | else | ||
113 | return EINA_RBTREE_RIGHT; | ||
114 | } | ||
115 | |||
116 | static inline int | ||
117 | _block_rbtree_empty_spot_find(const Block *node, const void *key, | ||
118 | int key_length EINA_UNUSED, | ||
119 | void *data EINA_UNUSED) | ||
120 | { | ||
121 | int32_t length = (int32_t) (intptr_t) key; | ||
122 | |||
123 | // Found best spot | ||
124 | if (node->length == length) | ||
125 | return 0; | ||
126 | |||
127 | // We're good, can we find better? | ||
128 | if (node->length > length) | ||
129 | { | ||
130 | Block *lson = (Block *) node->__rbtree.son[0]; | ||
131 | |||
132 | if (lson && lson->length >= length) | ||
133 | return -1; | ||
134 | |||
135 | // This is the best we can do... | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | // Keep calm and carry on | ||
140 | return 1; | ||
141 | } | ||
142 | |||
143 | static inline int | ||
144 | _block_rbtree_block_find(const Block *node, const void *key, | ||
145 | int key_length EINA_UNUSED, | ||
146 | void *data EINA_UNUSED) | ||
147 | { | ||
148 | const Index_Entry *ie = key; | ||
149 | |||
150 | // Found best spot | ||
151 | if ((node->length == ie->length) | ||
152 | && (node->offset == ie->offset) | ||
153 | && (node->shmid == ie->shmid)) | ||
154 | return 0; | ||
155 | |||
156 | // We're good, can we find better? | ||
157 | if (node->length > ie->length) | ||
158 | { | ||
159 | Block *lson = (Block *) node->__rbtree.son[0]; | ||
160 | |||
161 | if (lson && lson->length >= ie->length) | ||
162 | return -1; | ||
163 | |||
164 | // This is the best we can do... | ||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | // Keep calm and carry on | ||
169 | return 1; | ||
170 | } | ||
171 | |||
172 | |||
173 | // Data shm | ||
174 | |||
175 | Data_Shm * | ||
176 | _shared_data_shm_new(int size) | ||
177 | { | ||
178 | Data_Shm *ds; | ||
179 | size_t mapping_size; | ||
180 | |||
181 | if (size <= 0) | ||
182 | return NULL; | ||
183 | |||
184 | ds = calloc(1, sizeof(Data_Shm)); | ||
185 | if (!ds) return NULL; | ||
186 | |||
187 | mapping_size = cserve2_shm_size_normalize((size_t) size); | ||
188 | |||
189 | ds->shm = cserve2_shm_request("data", mapping_size); | ||
190 | if (!ds->shm) | ||
191 | { | ||
192 | ERR("Could not create shm of size %u", (unsigned) mapping_size); | ||
193 | free(ds); | ||
194 | return NULL; | ||
195 | } | ||
196 | |||
197 | ds->data = cserve2_shm_map(ds->shm); | ||
198 | if (!ds->data) | ||
199 | { | ||
200 | ERR("Could not map shm of size %u", (unsigned) mapping_size); | ||
201 | cserve2_shm_unref(ds->shm); | ||
202 | free(ds); | ||
203 | return NULL; | ||
204 | } | ||
205 | |||
206 | DBG("Created data shm of size %d: %d", size, cserve2_shm_id_get(ds->shm)); | ||
207 | return ds; | ||
208 | } | ||
209 | |||
210 | void | ||
211 | _shared_data_shm_del(Data_Shm *ds) | ||
212 | { | ||
213 | if (!ds) return; | ||
214 | cserve2_shm_unref(ds->shm); | ||
215 | free(ds); | ||
216 | } | ||
217 | |||
218 | int | ||
219 | _shared_data_shm_resize(Data_Shm *ds, size_t newsize) | ||
220 | { | ||
221 | Shm_Handle *shm; | ||
222 | size_t mapping_size; | ||
223 | |||
224 | if (newsize <= 0) | ||
225 | return -1; | ||
226 | |||
227 | mapping_size = cserve2_shm_size_normalize(newsize); | ||
228 | cserve2_shm_unmap(ds->shm); | ||
229 | ds->data = NULL; | ||
230 | |||
231 | shm = cserve2_shm_resize(ds->shm, mapping_size); | ||
232 | if (!shm) | ||
233 | { | ||
234 | ERR("Could not resize shm %d to %u", | ||
235 | cserve2_shm_id_get(ds->shm), (unsigned) newsize); | ||
236 | return -1; | ||
237 | } | ||
238 | |||
239 | ds->shm = shm; | ||
240 | ds->data = cserve2_shm_map(ds->shm); | ||
241 | if (!ds->data) | ||
242 | { | ||
243 | ERR("Failed to remap shm %d after resizing to %u bytes", | ||
244 | cserve2_shm_id_get(ds->shm), (unsigned) mapping_size); | ||
245 | return -1; | ||
246 | } | ||
247 | |||
248 | return mapping_size; | ||
249 | } | ||
250 | |||
251 | |||
252 | // Arrays | ||
253 | |||
254 | Shared_Array * | ||
255 | cserve2_shared_array_new(int tag, int elemsize, int initcount) | ||
256 | { | ||
257 | Shared_Array *sa; | ||
258 | Data_Shm *ds; | ||
259 | int mapping_size; | ||
260 | |||
261 | if (elemsize <= 0 || initcount < 0) | ||
262 | return NULL; | ||
263 | |||
264 | sa = calloc(1, sizeof(Shared_Array)); | ||
265 | if (!sa) return NULL; | ||
266 | |||
267 | if (!initcount) initcount = 1; | ||
268 | mapping_size = cserve2_shm_size_normalize(elemsize * initcount | ||
269 | + sizeof(Shared_Array_Header)); | ||
270 | ds = _shared_data_shm_new(mapping_size); | ||
271 | if (!ds) | ||
272 | { | ||
273 | free(sa); | ||
274 | return NULL; | ||
275 | } | ||
276 | |||
277 | sa->ds = ds; | ||
278 | sa->header = (Shared_Array_Header *) ds->data; | ||
279 | sa->header->count = (mapping_size - sizeof(Shared_Array_Header)) / elemsize; | ||
280 | sa->header->elemsize = elemsize; | ||
281 | sa->header->generation_id = 1; | ||
282 | sa->header->emptyidx = 0; | ||
283 | sa->header->tag = tag; | ||
284 | memset(&sa->header->_reserved1, 0, sizeof(int32_t) * 3); | ||
285 | |||
286 | return sa; | ||
287 | } | ||
288 | |||
289 | const char * | ||
290 | cserve2_shared_array_name_get(Shared_Array *sa) | ||
291 | { | ||
292 | if (!sa) return NULL; | ||
293 | return cserve2_shm_name_get(sa->ds->shm); | ||
294 | } | ||
295 | |||
296 | void | ||
297 | cserve2_shared_array_del(Shared_Array *sa) | ||
298 | { | ||
299 | if (!sa) return; | ||
300 | _shared_data_shm_del(sa->ds); | ||
301 | free(sa); | ||
302 | } | ||
303 | |||
304 | int | ||
305 | cserve2_shared_array_size_get(Shared_Array *sa) | ||
306 | { | ||
307 | if (!sa) return -1; | ||
308 | return sa->header->count; | ||
309 | } | ||
310 | |||
311 | int | ||
312 | cserve2_shared_array_count_get(Shared_Array *sa) | ||
313 | { | ||
314 | if (!sa) return -1; | ||
315 | return sa->header->emptyidx; | ||
316 | } | ||
317 | |||
318 | int | ||
319 | cserve2_shared_array_item_size_get(Shared_Array *sa) | ||
320 | { | ||
321 | if (!sa) return -1; | ||
322 | return sa->header->elemsize; | ||
323 | } | ||
324 | |||
325 | int | ||
326 | cserve2_shared_array_generation_id_get(Shared_Array *sa) | ||
327 | { | ||
328 | if (!sa) return -1; | ||
329 | return sa->header->generation_id; | ||
330 | } | ||
331 | |||
332 | int | ||
333 | cserve2_shared_array_size_set(Shared_Array *sa, int newcount) | ||
334 | { | ||
335 | int mapping_size; | ||
336 | |||
337 | if (!sa) return -1; | ||
338 | mapping_size = cserve2_shm_size_normalize(sa->header->elemsize * newcount | ||
339 | + sizeof(Shared_Array_Header)); | ||
340 | if (_shared_data_shm_resize(sa->ds, mapping_size) < 0) | ||
341 | { | ||
342 | sa->header = NULL; | ||
343 | return -1; | ||
344 | } | ||
345 | sa->header = (Shared_Array_Header *) sa->ds->data; | ||
346 | sa->header->count = (mapping_size - sizeof(Shared_Array_Header)) | ||
347 | / sa->header->elemsize; | ||
348 | |||
349 | return sa->header->count; | ||
350 | } | ||
351 | |||
352 | int | ||
353 | cserve2_shared_array_item_new(Shared_Array *sa) | ||
354 | { | ||
355 | if (!sa) return -1; | ||
356 | if (sa->header->emptyidx >= sa->header->count) | ||
357 | { | ||
358 | int newcount = cserve2_shared_array_size_set(sa, sa->header->count + 1); | ||
359 | if (newcount < 0) return -1; | ||
360 | } | ||
361 | |||
362 | return sa->header->emptyidx++; | ||
363 | } | ||
364 | |||
365 | const void * | ||
366 | cserve2_shared_array_item_data(Shared_Array *sa) | ||
367 | { | ||
368 | return cserve2_shared_array_item_data_get(sa, 0); | ||
369 | } | ||
370 | |||
371 | void * | ||
372 | cserve2_shared_array_item_data_get(Shared_Array *sa, int elemid) | ||
373 | { | ||
374 | char *ptr; | ||
375 | |||
376 | if (!sa) return NULL; | ||
377 | if (elemid < 0 || elemid >= sa->header->count) | ||
378 | return NULL; | ||
379 | |||
380 | ptr = (char *) sa->header; | ||
381 | ptr += sizeof(Shared_Array_Header); | ||
382 | ptr += elemid * sa->header->elemsize; | ||
383 | |||
384 | return ptr; | ||
385 | } | ||
386 | |||
387 | int | ||
388 | cserve2_shared_array_foreach(Shared_Array *sa, Eina_Each_Cb cb, void *data) | ||
389 | { | ||
390 | char *ptr; | ||
391 | int k; | ||
392 | |||
393 | if (!sa || !cb) return -1; | ||
394 | ptr = sa->ds->data + sizeof(Shared_Array_Header); | ||
395 | |||
396 | for (k = 0; k < sa->header->emptyidx; k++) | ||
397 | { | ||
398 | if (!cb(sa, ptr, data)) | ||
399 | break; | ||
400 | ptr += sa->header->elemsize; | ||
401 | } | ||
402 | |||
403 | return k; | ||
404 | } | ||
405 | |||
406 | Shared_Array * | ||
407 | cserve2_shared_array_repack(Shared_Array *sa, | ||
408 | Shared_Array_Repack_Skip_Cb skip, | ||
409 | Eina_Compare_Cb cmp) | ||
410 | { | ||
411 | Eina_List *l = NULL; | ||
412 | Shared_Array *sa2; | ||
413 | const char *srcdata; | ||
414 | char *dstdata; | ||
415 | int k, elemsize, newcount = 0; | ||
416 | |||
417 | if (!sa || !skip || !cmp) return NULL; | ||
418 | srcdata = sa->ds->data + sizeof(Shared_Array_Header); | ||
419 | elemsize = sa->header->elemsize; | ||
420 | |||
421 | // Build ordered list of pointers | ||
422 | for (k = 0; k < sa->header->emptyidx; k++) | ||
423 | { | ||
424 | const char *data = srcdata + k * elemsize; | ||
425 | if (skip(sa, data)) continue; | ||
426 | l = eina_list_sorted_insert(l, cmp, data); | ||
427 | newcount++; | ||
428 | } | ||
429 | |||
430 | // Create new array | ||
431 | sa2 = cserve2_shared_array_new(0, elemsize, newcount); | ||
432 | if (!sa) | ||
433 | { | ||
434 | ERR("Can not repack array: failed to create new array"); | ||
435 | return NULL; | ||
436 | } | ||
437 | sa2->header->generation_id = sa->header->generation_id + 1; | ||
438 | |||
439 | // Write data | ||
440 | dstdata = sa2->ds->data + sizeof(Shared_Array_Header); | ||
441 | while (l) | ||
442 | { | ||
443 | const char *data = eina_list_data_get(l); | ||
444 | l = eina_list_remove_list(l, l); | ||
445 | memcpy(dstdata, data, elemsize); | ||
446 | } | ||
447 | |||
448 | // Finalize & return | ||
449 | sa2->header->emptyidx = newcount; | ||
450 | sa2->header->tag = sa->header->tag; | ||
451 | return sa2; | ||
452 | } | ||
453 | |||
454 | int | ||
455 | cserve2_shared_array_item_find(Shared_Array *sa, void *data, | ||
456 | Eina_Compare_Cb cmp) | ||
457 | { | ||
458 | int k; | ||
459 | const char *ptr; | ||
460 | |||
461 | if (!sa || !cmp) return -1; | ||
462 | |||
463 | // TODO: Fast search in the sorted zone | ||
464 | |||
465 | ptr = sa->ds->data; | ||
466 | |||
467 | // Linear search O(n) | ||
468 | for (k = 0; k < sa->header->emptyidx; k++) | ||
469 | { | ||
470 | if (!cmp(ptr, data)) | ||
471 | return k; | ||
472 | ptr += sa->header->elemsize; | ||
473 | } | ||
474 | |||
475 | return -1; | ||
476 | } | ||
477 | |||
478 | void * | ||
479 | cserve2_shared_array_item_data_find(Shared_Array *sa, void *data, | ||
480 | Eina_Compare_Cb cmp) | ||
481 | { | ||
482 | int elemid; | ||
483 | |||
484 | elemid = cserve2_shared_array_item_find(sa, data, cmp); | ||
485 | if (elemid < 0) return NULL; | ||
486 | |||
487 | return cserve2_shared_array_item_data_get(sa, elemid); | ||
488 | } | ||
489 | |||
490 | |||
491 | // Shared index (used by the random mempool) | ||
492 | |||
493 | static Index_Entry * | ||
494 | _shared_index_entry_new(Shared_Index *si) | ||
495 | { | ||
496 | Index_Entry *ie; | ||
497 | int id; | ||
498 | |||
499 | if (!si) return NULL; | ||
500 | |||
501 | id = cserve2_shared_array_item_new(si->sa); | ||
502 | if (id < 0) return NULL; | ||
503 | |||
504 | ie = cserve2_shared_array_item_data_get(si->sa, id); | ||
505 | ie->id = si->lastid++; | ||
506 | return ie; | ||
507 | } | ||
508 | |||
509 | static Index_Entry * | ||
510 | _shared_index_entry_find(Shared_Index *si, int id) | ||
511 | { | ||
512 | int k, count; | ||
513 | |||
514 | if (!si) return NULL; | ||
515 | count = cserve2_shared_array_count_get(si->sa); | ||
516 | |||
517 | // FIXME: Linear search O(n) | ||
518 | for (k = 0; k < count; k++) | ||
519 | { | ||
520 | Index_Entry *ie; | ||
521 | ie = cserve2_shared_array_item_data_get(si->sa, k); | ||
522 | if (!ie) break; | ||
523 | if (ie->id == id) | ||
524 | return ie; | ||
525 | } | ||
526 | |||
527 | return NULL; | ||
528 | } | ||
529 | |||
530 | static Shared_Index * | ||
531 | _shared_index_new() | ||
532 | { | ||
533 | Shared_Index *si; | ||
534 | Index_Entry *ie; | ||
535 | int tag = 1234; // FIXME? | ||
536 | |||
537 | si = calloc(1, sizeof(Shared_Index)); | ||
538 | if (!si) return NULL; | ||
539 | |||
540 | si->sa = cserve2_shared_array_new(tag, sizeof(Index_Entry), 1); | ||
541 | if (!si->sa) | ||
542 | { | ||
543 | free(si); | ||
544 | return NULL; | ||
545 | } | ||
546 | |||
547 | si->lastid = 0; | ||
548 | ie = _shared_index_entry_new(si); | ||
549 | if (!ie) | ||
550 | { | ||
551 | cserve2_shared_array_del(si->sa); | ||
552 | free(si); | ||
553 | return NULL; | ||
554 | } | ||
555 | |||
556 | return si; | ||
557 | } | ||
558 | |||
559 | void | ||
560 | _shared_index_del(Shared_Index *si) | ||
561 | { | ||
562 | if (!si) return; | ||
563 | cserve2_shared_array_del(si->sa); | ||
564 | free(si); | ||
565 | } | ||
566 | |||
567 | |||
568 | // Shared memory pool | ||
569 | |||
570 | Shared_Mempool * | ||
571 | cserve2_shared_mempool_new(int initsize) | ||
572 | { | ||
573 | Shared_Mempool *sm; | ||
574 | size_t mapping_size; | ||
575 | |||
576 | if (initsize < 0) return NULL; | ||
577 | |||
578 | sm = calloc(1, sizeof(Shared_Mempool)); | ||
579 | if (!sm) return NULL; | ||
580 | |||
581 | if (!initsize) initsize = 1; | ||
582 | mapping_size = cserve2_shm_size_normalize((size_t) initsize); | ||
583 | |||
584 | sm->ds = _shared_data_shm_new(mapping_size); | ||
585 | if (!sm->ds) | ||
586 | { | ||
587 | free(sm); | ||
588 | return NULL; | ||
589 | } | ||
590 | |||
591 | sm->index = _shared_index_new(); | ||
592 | if (!sm->index) | ||
593 | { | ||
594 | _shared_data_shm_del(sm->ds); | ||
595 | free(sm); | ||
596 | return NULL; | ||
597 | } | ||
598 | |||
599 | sm->empty_size = mapping_size; | ||
600 | return sm; | ||
601 | } | ||
602 | |||
603 | static void | ||
604 | _shared_mempool_block_del(Eina_Rbtree *node, void *data EINA_UNUSED) | ||
605 | { | ||
606 | Block *blk = (Block *) node; | ||
607 | free(blk); | ||
608 | } | ||
609 | |||
610 | void | ||
611 | cserve2_shared_mempool_del(Shared_Mempool *sm) | ||
612 | { | ||
613 | if (!sm) return; | ||
614 | eina_rbtree_delete(EINA_RBTREE_GET(sm->empty_blocks), | ||
615 | EINA_RBTREE_FREE_CB(_shared_mempool_block_del), sm); | ||
616 | _shared_data_shm_del(sm->ds); | ||
617 | _shared_index_del(sm->index); | ||
618 | free(sm); | ||
619 | } | ||
620 | |||
621 | static Index_Entry * | ||
622 | _shared_mempool_buffer_new(Shared_Mempool *sm, int size) | ||
623 | { | ||
624 | |||
625 | Index_Entry *ie; | ||
626 | Block *blk; | ||
627 | int mapping_size, new_mapping_size; | ||
628 | int rsize = _data_blocksize_roundup(size); | ||
629 | |||
630 | if (!sm) return NULL; | ||
631 | if (size <= 0) return NULL; | ||
632 | |||
633 | mapping_size = cserve2_shm_map_size_get(sm->ds->shm); | ||
634 | |||
635 | ie = _shared_index_entry_new(sm->index); | ||
636 | if (!ie) return NULL; | ||
637 | |||
638 | // Append if possible | ||
639 | if (rsize <= sm->empty_size) | ||
640 | { | ||
641 | ie->length = rsize; | ||
642 | ie->offset = mapping_size - sm->empty_size; | ||
643 | ie->shmid = cserve2_shm_id_get(sm->ds->shm); | ||
644 | ie->refcount = 1; | ||
645 | sm->empty_size -= rsize; | ||
646 | return ie; | ||
647 | } | ||
648 | |||
649 | // Find empty spot | ||
650 | blk = (Block *) eina_rbtree_inline_lookup( | ||
651 | EINA_RBTREE_GET(sm->empty_blocks), (void *) (intptr_t) rsize, 0, | ||
652 | EINA_RBTREE_CMP_KEY_CB(_block_rbtree_empty_spot_find), NULL); | ||
653 | if (blk && blk->length >= rsize) | ||
654 | { | ||
655 | ie->length = blk->length; | ||
656 | ie->offset = blk->offset; | ||
657 | ie->shmid = cserve2_shm_id_get(sm->ds->shm); | ||
658 | ie->refcount = 1; | ||
659 | |||
660 | sm->empty_blocks = (Block *) eina_rbtree_inline_remove( | ||
661 | EINA_RBTREE_GET(sm->empty_blocks), EINA_RBTREE_GET(blk), | ||
662 | EINA_RBTREE_CMP_NODE_CB(_block_rbtree_cmp), NULL); | ||
663 | if (blk->length == rsize) | ||
664 | free(blk); | ||
665 | else | ||
666 | { | ||
667 | blk->length -= rsize; | ||
668 | blk->offset += rsize; | ||
669 | sm->empty_blocks = (Block *) eina_rbtree_inline_insert( | ||
670 | EINA_RBTREE_GET(sm->empty_blocks), EINA_RBTREE_GET(blk), | ||
671 | EINA_RBTREE_CMP_NODE_CB(_block_rbtree_cmp), NULL); | ||
672 | } | ||
673 | |||
674 | return ie; | ||
675 | } | ||
676 | |||
677 | // Grow mempool | ||
678 | new_mapping_size = _shared_data_shm_resize( | ||
679 | sm->ds, mapping_size + rsize - sm->empty_size); | ||
680 | if (new_mapping_size < 0) | ||
681 | { | ||
682 | memset(ie, 0, sizeof(Index_Entry)); | ||
683 | return NULL; | ||
684 | } | ||
685 | ie->length = rsize; | ||
686 | ie->offset = mapping_size - sm->empty_size; | ||
687 | ie->shmid = cserve2_shm_id_get(sm->ds->shm); | ||
688 | ie->refcount = 1; | ||
689 | sm->empty_size += (new_mapping_size - mapping_size) - rsize; | ||
690 | return ie; | ||
691 | } | ||
692 | |||
693 | int | ||
694 | cserve2_shared_mempool_buffer_new(Shared_Mempool *sm, int size) | ||
695 | { | ||
696 | Index_Entry *ie; | ||
697 | |||
698 | ie = _shared_mempool_buffer_new(sm, size); | ||
699 | if (!ie) return -1; | ||
700 | |||
701 | return ie->id; | ||
702 | } | ||
703 | |||
704 | int | ||
705 | cserve2_shared_mempool_buffer_ref(Shared_Mempool *sm, int bufferid) | ||
706 | { | ||
707 | Index_Entry *ie; | ||
708 | |||
709 | if (!sm) return -1; | ||
710 | ie = _shared_index_entry_find(sm->index, bufferid); | ||
711 | if (!ie) return -1; | ||
712 | |||
713 | if (!ie->refcount) | ||
714 | { | ||
715 | Block *blk = (Block *) | ||
716 | eina_rbtree_inline_lookup(EINA_RBTREE_GET(sm->empty_blocks), | ||
717 | ie, sizeof(Index_Entry), | ||
718 | EINA_RBTREE_CMP_KEY_CB( | ||
719 | _block_rbtree_block_find), | ||
720 | sm); | ||
721 | if (blk && (blk->length == ie->length) | ||
722 | && (blk->offset == ie->offset) | ||
723 | && (blk->shmid == ie->shmid)) | ||
724 | { | ||
725 | sm->empty_blocks = (Block *) eina_rbtree_inline_remove( | ||
726 | EINA_RBTREE_GET(sm->empty_blocks), EINA_RBTREE_GET(blk), | ||
727 | EINA_RBTREE_CMP_NODE_CB(_block_rbtree_cmp), NULL); | ||
728 | free(blk); | ||
729 | } | ||
730 | } | ||
731 | |||
732 | ie->refcount++; | ||
733 | return ie->id; | ||
734 | } | ||
735 | |||
736 | void | ||
737 | cserve2_shared_mempool_buffer_del(Shared_Mempool *sm, int bufferid) | ||
738 | { | ||
739 | Index_Entry *ie; | ||
740 | |||
741 | if (!sm || !bufferid) return; | ||
742 | ie = _shared_index_entry_find(sm->index, bufferid); | ||
743 | if (!ie || ie->refcount <= 0) | ||
744 | { | ||
745 | CRIT("Tried to delete invalid buffer or with refcount 0"); | ||
746 | return; | ||
747 | } | ||
748 | |||
749 | ie->refcount--; | ||
750 | if (!ie->refcount) | ||
751 | { | ||
752 | Block *newblk = calloc(1, sizeof(Block)); | ||
753 | newblk->length = ie->length; | ||
754 | newblk->offset = ie->offset; | ||
755 | newblk->shmid = ie->shmid; | ||
756 | sm->empty_blocks = (Block *) eina_rbtree_inline_insert( | ||
757 | EINA_RBTREE_GET(sm->empty_blocks), EINA_RBTREE_GET(newblk), | ||
758 | EINA_RBTREE_CMP_NODE_CB(_block_rbtree_cmp), NULL); | ||
759 | } | ||
760 | } | ||
761 | |||
762 | void * | ||
763 | cserve2_shared_mempool_buffer_get(Shared_Mempool *sm, int bufferid) | ||
764 | { | ||
765 | Index_Entry *ie; | ||
766 | char *data; | ||
767 | |||
768 | if (!sm) return NULL; | ||
769 | ie = _shared_index_entry_find(sm->index, bufferid); | ||
770 | if (!ie || ie->refcount <= 0) | ||
771 | { | ||
772 | CRIT("Tried to access invalid buffer or with refcount 0"); | ||
773 | return NULL; | ||
774 | } | ||
775 | |||
776 | data = sm->ds->data + ie->offset; | ||
777 | return data; | ||
778 | } | ||
779 | |||
780 | |||
781 | // Shared strings | ||
782 | |||
783 | int | ||
784 | cserve2_shared_string_add(const char *str) | ||
785 | { | ||
786 | Index_Entry *ie; | ||
787 | char *data; | ||
788 | int len, id; | ||
789 | |||
790 | if (!str) return -1; | ||
791 | |||
792 | // Find in known strings | ||
793 | id = (int) (intptr_t) eina_hash_find(_string_entries, str); | ||
794 | if (id > 0) | ||
795 | { | ||
796 | ie = _shared_index_entry_find(_string_mempool->index, id); | ||
797 | if (!ie || ie->refcount <= 0) | ||
798 | { | ||
799 | CRIT("String found in hash but not in mempool!"); | ||
800 | eina_hash_del(_string_entries, str, (void *) (intptr_t) id); | ||
801 | goto new_entry; | ||
802 | } | ||
803 | ie->refcount++; | ||
804 | return ie->id; | ||
805 | } | ||
806 | |||
807 | // Add new entry | ||
808 | new_entry: | ||
809 | len = strlen(str) + 1; | ||
810 | ie = _shared_mempool_buffer_new(_string_mempool, len); | ||
811 | if (!ie) | ||
812 | { | ||
813 | ERR("Could not store new string in shm"); | ||
814 | return -1; | ||
815 | } | ||
816 | |||
817 | eina_hash_add(_string_entries, str, (void *) (intptr_t) ie->id); | ||
818 | data = _string_mempool->ds->data + ie->offset; | ||
819 | memcpy(data, str, len); | ||
820 | return ie->id; | ||
821 | } | ||
822 | |||
823 | int | ||
824 | cserve2_shared_string_ref(int id) | ||
825 | { | ||
826 | if (!id) return 0; | ||
827 | return cserve2_shared_mempool_buffer_ref(_string_mempool, id); | ||
828 | } | ||
829 | |||
830 | void | ||
831 | cserve2_shared_string_del(int id) | ||
832 | { | ||
833 | if (!id) return; | ||
834 | if (_shared_mempool_buffer_del(_string_mempool, id)) | ||
835 | { | ||
836 | if (!eina_hash_del_by_data(_string_entries, (void *) (intptr_t) id)) | ||
837 | CRIT("Invalid free"); | ||
838 | } | ||
839 | } | ||
840 | |||
841 | const char * | ||
842 | cserve2_shared_string_get(int id) | ||
843 | { | ||
844 | if (!id) return NULL; | ||
845 | return cserve2_shared_mempool_buffer_get(_string_mempool, id); | ||
846 | } | ||
847 | |||
848 | |||
849 | |||
850 | // Init/destroy | ||
851 | |||
852 | void | ||
853 | cserve2_shared_index_init(void) | ||
854 | { | ||
855 | if (!_instances) | ||
856 | { | ||
857 | DBG("Initializing shared index"); | ||
858 | _string_mempool = cserve2_shared_mempool_new(4096); | ||
859 | _string_entries = eina_hash_string_djb2_new(NULL); | ||
860 | } | ||
861 | _instances++; | ||
862 | } | ||
863 | |||
864 | void | ||
865 | cserve2_shared_index_shutdown(void) | ||
866 | { | ||
867 | _instances--; | ||
868 | if (!_instances) | ||
869 | { | ||
870 | DBG("Destroying shared index"); | ||
871 | cserve2_shared_mempool_del(_string_mempool); | ||
872 | eina_hash_free(_string_entries); | ||
873 | |||
874 | _string_mempool = NULL; | ||
875 | _string_entries = NULL; | ||
876 | } | ||
877 | } | ||
878 | |||
diff --git a/src/bin/evas/evas_cserve2_main.c b/src/bin/evas/evas_cserve2_main.c index a2bb9c402d..e77eba2f14 100644 --- a/src/bin/evas/evas_cserve2_main.c +++ b/src/bin/evas/evas_cserve2_main.c | |||
@@ -327,34 +327,26 @@ main(int argc EINA_UNUSED, const char *argv[]) | |||
327 | goto error; | 327 | goto error; |
328 | } | 328 | } |
329 | 329 | ||
330 | cserve2_shm_init(); | ||
331 | cserve2_shared_index_init(); | ||
330 | cserve2_requests_init(); | 332 | cserve2_requests_init(); |
331 | |||
332 | cserve2_scale_init(); | 333 | cserve2_scale_init(); |
333 | |||
334 | cserve2_font_init(); | 334 | cserve2_font_init(); |
335 | |||
336 | cserve2_cache_init(); | 335 | cserve2_cache_init(); |
337 | |||
338 | cserve2_shm_init(); | ||
339 | |||
340 | _clients_setup(); | 336 | _clients_setup(); |
341 | 337 | ||
342 | cserve2_main_loop_run(); | 338 | cserve2_main_loop_run(); |
343 | 339 | ||
344 | _clients_finish(); | 340 | _clients_finish(); |
345 | |||
346 | cserve2_cache_shutdown(); | 341 | cserve2_cache_shutdown(); |
347 | |||
348 | cserve2_font_shutdown(); | 342 | cserve2_font_shutdown(); |
349 | |||
350 | cserve2_scale_shutdown(); | 343 | cserve2_scale_shutdown(); |
351 | |||
352 | cserve2_requests_shutdown(); | 344 | cserve2_requests_shutdown(); |
353 | |||
354 | cserve2_slaves_shutdown(); | 345 | cserve2_slaves_shutdown(); |
355 | 346 | ||
356 | cserve2_main_loop_finish(); | 347 | cserve2_main_loop_finish(); |
357 | 348 | ||
349 | cserve2_shared_index_shutdown(); | ||
358 | cserve2_shm_shutdown(); | 350 | cserve2_shm_shutdown(); |
359 | 351 | ||
360 | eina_prefix_free(_evas_cserve2_pfx); | 352 | eina_prefix_free(_evas_cserve2_pfx); |