Skip to content

Commit d5e64b2

Browse files
author
Harald Radi
committed
added thread safe hashtable which allows concurrent
reads but only exclusive writes
1 parent 4586665 commit d5e64b2

File tree

4 files changed

+464
-1
lines changed

4 files changed

+464
-1
lines changed

Zend/ZendTS.dsp

Lines changed: 9 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Zend/zend.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ typedef unsigned short zend_ushort;
180180

181181

182182
#include "zend_hash.h"
183+
#include "zend_ts_hash.h"
183184
#include "zend_llist.h"
184185

185186
#define INTERNAL_FUNCTION_PARAMETERS int ht, zval *return_value, zval *this_ptr, int return_value_used TSRMLS_DC

Zend/zend_ts_hash.c

Lines changed: 339 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,339 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| Zend Engine |
4+
+----------------------------------------------------------------------+
5+
| Copyright (c) 1998-2002 Zend Technologies Ltd. (http://www.zend.com) |
6+
+----------------------------------------------------------------------+
7+
| This source file is subject to version 2.00 of the Zend license, |
8+
| that is bundled with this package in the file LICENSE, and is |
9+
| available at through the world-wide-web at |
10+
| http://www.zend.com/license/2_00.txt. |
11+
| If you did not receive a copy of the Zend license and are unable to |
12+
| obtain it through the world-wide-web, please send a note to |
13+
| license@zend.com so we can mail you a copy immediately. |
14+
+----------------------------------------------------------------------+
15+
| Authors: Harald Radi <harald.radi@nme.at> |
16+
+----------------------------------------------------------------------+
17+
*/
18+
19+
#include "zend_ts_hash.h"
20+
21+
22+
/* ts management functions */
23+
static void begin_read(TsHashTable *ht)
24+
{
25+
tsrm_mutex_lock(ht->mx_reader);
26+
if ((++(ht->reader)) == 1) {
27+
tsrm_mutex_lock(ht->mx_writer);
28+
}
29+
tsrm_mutex_unlock(ht->mx_reader);
30+
}
31+
32+
static void end_read(TsHashTable *ht)
33+
{
34+
tsrm_mutex_lock(ht->mx_reader);
35+
if ((--(ht->reader)) == 0) {
36+
tsrm_mutex_unlock(ht->mx_writer);
37+
}
38+
tsrm_mutex_unlock(ht->mx_reader);
39+
}
40+
41+
static void begin_write(TsHashTable *ht)
42+
{
43+
tsrm_mutex_lock(ht->mx_writer);
44+
}
45+
46+
static void end_write(TsHashTable *ht)
47+
{
48+
tsrm_mutex_unlock(ht->mx_writer);
49+
}
50+
51+
/* delegates */
52+
ZEND_API int zend_ts_hash_init(TsHashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, int persistent)
53+
{
54+
ht->mx_reader = tsrm_mutex_alloc();
55+
ht->mx_writer = tsrm_mutex_alloc();
56+
ht->reader = 0;
57+
return zend_hash_init(&(ht->hash), nSize, pHashFunction, pDestructor, persistent);
58+
}
59+
60+
ZEND_API int zend_ts_hash_init_ex(TsHashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, int persistent, zend_bool bApplyProtection)
61+
{
62+
ht->mx_reader = tsrm_mutex_alloc();
63+
ht->mx_writer = tsrm_mutex_alloc();
64+
ht->reader = 0;
65+
return zend_hash_init_ex(&(ht->hash), nSize, pHashFunction, pDestructor, persistent, bApplyProtection);
66+
}
67+
68+
ZEND_API void zend_ts_hash_destroy(TsHashTable *ht)
69+
{
70+
tsrm_mutex_free(ht->mx_reader);
71+
tsrm_mutex_free(ht->mx_reader);
72+
zend_hash_destroy(&(ht->hash));
73+
}
74+
75+
ZEND_API void zend_ts_hash_clean(TsHashTable *ht)
76+
{
77+
ht->reader = 0;
78+
zend_hash_clean(&(ht->hash));
79+
}
80+
81+
ZEND_API int zend_ts_hash_add_or_update(TsHashTable *ht, char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest, int flag)
82+
{
83+
int retval;
84+
85+
begin_write(ht);
86+
retval = zend_hash_add_or_update(&(ht->hash), arKey, nKeyLength, pData, nDataSize, pDest, flag);
87+
end_write(ht);
88+
89+
return retval;
90+
}
91+
92+
ZEND_API int zend_ts_hash_quick_add_or_update(TsHashTable *ht, char *arKey, uint nKeyLength, ulong h, void *pData, uint nDataSize, void **pDest, int flag)
93+
{
94+
int retval;
95+
96+
begin_write(ht);
97+
retval = zend_hash_quick_add_or_update(&(ht->hash), arKey, nKeyLength, h, pData, nDataSize, pDest, flag);
98+
end_write(ht);
99+
100+
return retval;
101+
}
102+
103+
ZEND_API int zend_ts_hash_index_update_or_next_insert(TsHashTable *ht, ulong h, void *pData, uint nDataSize, void **pDest, int flag)
104+
{
105+
int retval;
106+
107+
begin_write(ht);
108+
retval = zend_hash_index_update_or_next_insert(&(ht->hash), h, pData, nDataSize, pDest, flag);
109+
end_write(ht);
110+
111+
return retval;
112+
}
113+
114+
ZEND_API int zend_ts_hash_add_empty_element(TsHashTable *ht, char *arKey, uint nKeyLength)
115+
{
116+
int retval;
117+
118+
begin_write(ht);
119+
retval = zend_hash_add_empty_element(&(ht->hash), arKey, nKeyLength);
120+
end_write(ht);
121+
122+
return retval;
123+
}
124+
125+
ZEND_API void zend_ts_hash_graceful_destroy(TsHashTable *ht)
126+
{
127+
tsrm_mutex_free(ht->mx_reader);
128+
tsrm_mutex_free(ht->mx_reader);
129+
zend_hash_graceful_destroy(&(ht->hash));
130+
}
131+
132+
ZEND_API void zend_ts_hash_apply(TsHashTable *ht, apply_func_t apply_func TSRMLS_DC)
133+
{
134+
begin_write(ht);
135+
zend_hash_apply(&(ht->hash), apply_func TSRMLS_CC);
136+
end_write(ht);
137+
}
138+
139+
ZEND_API void zend_ts_hash_apply_with_argument(TsHashTable *ht, apply_func_arg_t apply_func, void *argument TSRMLS_DC)
140+
{
141+
begin_write(ht);
142+
zend_hash_apply_with_argument(&(ht->hash), apply_func, argument TSRMLS_CC);
143+
end_write(ht);
144+
}
145+
146+
ZEND_API void zend_ts_hash_apply_with_arguments(TsHashTable *ht, apply_func_args_t apply_func, int num_args, ...)
147+
{
148+
va_list args;
149+
150+
va_start(args, num_args);
151+
begin_write(ht);
152+
zend_hash_apply_with_arguments(&(ht->hash), apply_func, num_args, args);
153+
end_write(ht);
154+
va_end(args);
155+
}
156+
157+
ZEND_API void zend_ts_hash_reverse_apply(TsHashTable *ht, apply_func_t apply_func TSRMLS_DC)
158+
{
159+
begin_write(ht);
160+
zend_hash_reverse_apply(&(ht->hash), apply_func TSRMLS_CC);
161+
end_write(ht);
162+
}
163+
164+
ZEND_API int zend_ts_hash_del_key_or_index(TsHashTable *ht, char *arKey, uint nKeyLength, ulong h, int flag)
165+
{
166+
int retval;
167+
168+
begin_write(ht);
169+
retval = zend_hash_del_key_or_index(&(ht->hash), arKey, nKeyLength, h, flag);
170+
end_write(ht);
171+
172+
return retval;
173+
}
174+
175+
ZEND_API ulong zend_ts_get_hash_value(TsHashTable *ht, char *arKey, uint nKeyLength)
176+
{
177+
ulong retval;
178+
179+
begin_read(ht);
180+
retval = zend_get_hash_value(&(ht->hash), arKey, nKeyLength);
181+
end_read(ht);
182+
183+
return retval;
184+
}
185+
186+
ZEND_API int zend_ts_hash_find(TsHashTable *ht, char *arKey, uint nKeyLength, void **pData)
187+
{
188+
int retval;
189+
190+
begin_read(ht);
191+
retval = zend_hash_find(&(ht->hash), arKey, nKeyLength, pData);
192+
end_read(ht);
193+
194+
return retval;
195+
}
196+
197+
ZEND_API int zend_ts_hash_quick_find(TsHashTable *ht, char *arKey, uint nKeyLength, ulong h, void **pData)
198+
{
199+
int retval;
200+
201+
begin_read(ht);
202+
retval = zend_hash_quick_find(&(ht->hash), arKey, nKeyLength, h, pData);
203+
end_read(ht);
204+
205+
return retval;
206+
}
207+
208+
ZEND_API int zend_ts_hash_index_find(TsHashTable *ht, ulong h, void **pData)
209+
{
210+
int retval;
211+
212+
begin_read(ht);
213+
retval = zend_hash_index_find(&(ht->hash), h, pData);
214+
end_read(ht);
215+
216+
return retval;
217+
}
218+
219+
ZEND_API int zend_ts_hash_exists(TsHashTable *ht, char *arKey, uint nKeyLength)
220+
{
221+
int retval;
222+
223+
begin_read(ht);
224+
retval = zend_hash_exists(&(ht->hash), arKey, nKeyLength);
225+
end_read(ht);
226+
227+
return retval;
228+
}
229+
230+
ZEND_API int zend_ts_hash_index_exists(TsHashTable *ht, ulong h)
231+
{
232+
int retval;
233+
234+
begin_read(ht);
235+
retval = zend_hash_index_exists(&(ht->hash), h);
236+
end_read(ht);
237+
238+
return retval;
239+
}
240+
241+
ZEND_API void zend_ts_hash_copy(TsHashTable *target, TsHashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size)
242+
{
243+
begin_read(source);
244+
begin_write(target);
245+
zend_hash_copy(&(target->hash), &(source->hash), pCopyConstructor, tmp, size);
246+
end_write(target);
247+
end_read(source);
248+
}
249+
250+
ZEND_API void zend_ts_hash_merge(TsHashTable *target, TsHashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size, int overwrite)
251+
{
252+
begin_read(source);
253+
begin_write(target);
254+
zend_hash_merge(&(target->hash), &(source->hash), pCopyConstructor, tmp, size, overwrite);
255+
end_write(target);
256+
end_read(source);
257+
}
258+
259+
ZEND_API void zend_ts_hash_merge_ex(TsHashTable *target, TsHashTable *source, copy_ctor_func_t pCopyConstructor, uint size, zend_bool (*pReplaceOrig)(void *orig, void *p_new))
260+
{
261+
begin_read(source);
262+
begin_write(target);
263+
zend_hash_merge_ex(&(target->hash), &(source->hash), pCopyConstructor, size, pReplaceOrig);
264+
end_write(target);
265+
end_read(source);
266+
}
267+
268+
ZEND_API int zend_ts_hash_sort(TsHashTable *ht, sort_func_t sort_func, compare_func_t compare_func, int renumber TSRMLS_DC)
269+
{
270+
int retval;
271+
272+
begin_write(ht);
273+
retval = zend_hash_sort(&(ht->hash), sort_func, compare_func, renumber TSRMLS_CC);
274+
end_write(ht);
275+
276+
return retval;
277+
}
278+
279+
ZEND_API int zend_ts_hash_compare(TsHashTable *ht1, TsHashTable *ht2, compare_func_t compar, zend_bool ordered TSRMLS_DC)
280+
{
281+
int retval;
282+
283+
begin_read(ht1);
284+
begin_read(ht2);
285+
retval = zend_hash_compare(&(ht1->hash), &(ht2->hash), compar, ordered TSRMLS_CC);
286+
end_read(ht2);
287+
end_read(ht1);
288+
289+
return retval;
290+
}
291+
292+
ZEND_API int zend_ts_hash_minmax(TsHashTable *ht, compare_func_t compar, int flag, void **pData TSRMLS_DC)
293+
{
294+
int retval;
295+
296+
begin_read(ht);
297+
retval = zend_hash_minmax(&(ht->hash), compar, flag, pData TSRMLS_CC);
298+
end_read(ht);
299+
300+
return retval;
301+
}
302+
303+
ZEND_API int zend_ts_hash_num_elements(TsHashTable *ht)
304+
{
305+
int retval;
306+
307+
begin_read(ht);
308+
retval = zend_hash_num_elements(&(ht->hash));
309+
end_read(ht);
310+
311+
return retval;
312+
}
313+
314+
ZEND_API int zend_ts_hash_rehash(TsHashTable *ht)
315+
{
316+
int retval;
317+
318+
begin_write(ht);
319+
retval = zend_hash_rehash(&(ht->hash));
320+
end_write(ht);
321+
322+
return retval;
323+
}
324+
325+
#if ZEND_DEBUG
326+
void zend_ts_hash_display_pListTail(TsHashTable *ht)
327+
{
328+
begin_read(ht);
329+
zend_hash_display_pListTail(&(ht->hash));
330+
end_read(ht);
331+
}
332+
333+
void zend_ts_hash_display(TsHashTable *ht)
334+
{
335+
begin_read(ht);
336+
zend_hash_display(&(ht->hash));
337+
end_read(ht);
338+
}
339+
#endif

0 commit comments

Comments
 (0)