1 : /*
2 : +----------------------------------------------------------------------+
3 : | Zend Engine |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1998-2009 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 through the world-wide-web at the following url: |
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: David Wang <planetbeing@gmail.com> |
16 : | Dmitry Stogov <dmitry@zend.com> |
17 : +----------------------------------------------------------------------+
18 : */
19 :
20 : /* $Id: zend_gc.h 272615 2009-01-02 20:36:30Z felipe $ */
21 :
22 : #ifndef ZEND_GC_H
23 : #define ZEND_GC_H
24 :
25 : #ifndef GC_BENCH
26 : # define GC_BENCH 0
27 : #endif
28 :
29 : #if GC_BENCH
30 : # define GC_BENCH_INC(counter) GC_G(counter)++
31 : # define GC_BENCH_DEC(counter) GC_G(counter)--
32 : # define GC_BENCH_PEAK(peak, counter) do { \
33 : if (GC_G(counter) > GC_G(peak)) { \
34 : GC_G(peak) = GC_G(counter); \
35 : } \
36 : } while (0)
37 : #else
38 : # define GC_BENCH_INC(counter)
39 : # define GC_BENCH_DEC(counter)
40 : # define GC_BENCH_PEAK(peak, counter)
41 : #endif
42 :
43 : #define GC_COLOR 0x03
44 :
45 : #define GC_BLACK 0x00
46 : #define GC_WHITE 0x01
47 : #define GC_GREY 0x02
48 : #define GC_PURPLE 0x03
49 :
50 : #define GC_ADDRESS(v) \
51 : ((gc_root_buffer*)(((zend_uintptr_t)(v)) & ~GC_COLOR))
52 : #define GC_SET_ADDRESS(v, a) \
53 : (v) = ((gc_root_buffer*)((((zend_uintptr_t)(v)) & GC_COLOR) | ((zend_uintptr_t)(a))))
54 : #define GC_GET_COLOR(v) \
55 : (((zend_uintptr_t)(v)) & GC_COLOR)
56 : #define GC_SET_COLOR(v, c) \
57 : (v) = ((gc_root_buffer*)((((zend_uintptr_t)(v)) & ~GC_COLOR) | (c)))
58 : #define GC_SET_BLACK(v) \
59 : (v) = ((gc_root_buffer*)(((zend_uintptr_t)(v)) & ~GC_COLOR))
60 : #define GC_SET_PURPLE(v) \
61 : (v) = ((gc_root_buffer*)(((zend_uintptr_t)(v)) | GC_PURPLE))
62 :
63 : #define GC_ZVAL_INIT(z) \
64 : ((zval_gc_info*)(z))->u.buffered = NULL
65 : #define GC_ZVAL_ADDRESS(v) \
66 : GC_ADDRESS(((zval_gc_info*)(v))->u.buffered)
67 : #define GC_ZVAL_SET_ADDRESS(v, a) \
68 : GC_SET_ADDRESS(((zval_gc_info*)(v))->u.buffered, (a))
69 : #define GC_ZVAL_GET_COLOR(v) \
70 : GC_GET_COLOR(((zval_gc_info*)(v))->u.buffered)
71 : #define GC_ZVAL_SET_COLOR(v, c) \
72 : GC_SET_COLOR(((zval_gc_info*)(v))->u.buffered, (c))
73 : #define GC_ZVAL_SET_BLACK(v) \
74 : GC_SET_BLACK(((zval_gc_info*)(v))->u.buffered)
75 : #define GC_ZVAL_SET_PURPLE(v) \
76 : GC_SET_PURPLE(((zval_gc_info*)(v))->u.buffered)
77 :
78 : #define GC_OBJ_INIT(z) \
79 : (z)->buffered = NULL
80 :
81 : typedef struct _gc_root_buffer {
82 : struct _gc_root_buffer *prev; /* double-linked list */
83 : struct _gc_root_buffer *next;
84 : zend_object_handle handle; /* must be 0 for zval */
85 : union {
86 : zval *pz;
87 : zend_object_handlers *handlers;
88 : } u;
89 : } gc_root_buffer;
90 :
91 : typedef struct _zval_gc_info {
92 : zval z;
93 : union {
94 : gc_root_buffer *buffered;
95 : struct _zval_gc_info *next;
96 : } u;
97 : } zval_gc_info;
98 :
99 : typedef struct _zend_gc_globals {
100 : zend_bool gc_enabled;
101 : zend_bool gc_active;
102 :
103 : gc_root_buffer *buf; /* preallocated arrays of buffers */
104 : gc_root_buffer roots; /* list of possible roots of cycles */
105 : gc_root_buffer *unused; /* list of unused buffers */
106 : gc_root_buffer *first_unused; /* pointer to first unused buffer */
107 : gc_root_buffer *last_unused; /* pointer to last unused buffer */
108 :
109 : zval_gc_info *zval_to_free; /* temporaryt list of zvals to free */
110 : zval_gc_info *free_list;
111 : zval_gc_info *next_to_free;
112 :
113 : zend_uint gc_runs;
114 : zend_uint collected;
115 :
116 : #if GC_BENCH
117 : zend_uint root_buf_length;
118 : zend_uint root_buf_peak;
119 : zend_uint zval_possible_root;
120 : zend_uint zobj_possible_root;
121 : zend_uint zval_buffered;
122 : zend_uint zobj_buffered;
123 : zend_uint zval_remove_from_buffer;
124 : zend_uint zobj_remove_from_buffer;
125 : zend_uint zval_marked_grey;
126 : zend_uint zobj_marked_grey;
127 : #endif
128 :
129 : } zend_gc_globals;
130 :
131 : #ifdef ZTS
132 : BEGIN_EXTERN_C()
133 : ZEND_API extern int gc_globals_id;
134 : END_EXTERN_C()
135 : #define GC_G(v) TSRMG(gc_globals_id, zend_gc_globals *, v)
136 : #else
137 : #define GC_G(v) (gc_globals.v)
138 : extern ZEND_API zend_gc_globals gc_globals;
139 : #endif
140 :
141 : BEGIN_EXTERN_C()
142 : ZEND_API int gc_collect_cycles(TSRMLS_D);
143 : ZEND_API void gc_zval_possible_root(zval *zv TSRMLS_DC);
144 : ZEND_API void gc_zobj_possible_root(zval *zv TSRMLS_DC);
145 : ZEND_API void gc_remove_zval_from_buffer(zval *zv TSRMLS_DC);
146 : ZEND_API void gc_globals_ctor(TSRMLS_D);
147 : ZEND_API void gc_globals_dtor(TSRMLS_D);
148 : ZEND_API void gc_init(TSRMLS_D);
149 : ZEND_API void gc_reset(TSRMLS_D);
150 : END_EXTERN_C()
151 :
152 : #define GC_ZVAL_CHECK_POSSIBLE_ROOT(z) \
153 : gc_zval_check_possible_root((z) TSRMLS_CC)
154 :
155 : #define GC_REMOVE_FROM_BUFFER(current) \
156 : gc_remove_from_buffer((current) TSRMLS_CC)
157 :
158 : #define GC_REMOVE_ZVAL_FROM_BUFFER(z) \
159 : if (GC_ADDRESS(((zval_gc_info*)z)->u.buffered)) { \
160 : gc_remove_zval_from_buffer(z TSRMLS_CC); \
161 : }
162 :
163 : #define GC_ZOBJ_CHECK_POSSIBLE_ROOT(zobject) \
164 : do { \
165 : if (EXPECTED(EG(objects_store).object_buckets != NULL) && \
166 : EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zobject)].valid) { \
167 : gc_zobj_possible_root(zobject TSRMLS_CC); \
168 : } \
169 : } while (0)
170 :
171 : #define GC_REMOVE_ZOBJ_FROM_BUFFER(obj) \
172 : do { \
173 : if (GC_ADDRESS((obj)->buffered) && !GC_G(gc_active)) { \
174 : GC_BENCH_INC(zobj_remove_from_buffer); \
175 : GC_REMOVE_FROM_BUFFER(GC_ADDRESS((obj)->buffered)); \
176 : (obj)->buffered = NULL; \
177 : } \
178 : } while (0)
179 :
180 : static zend_always_inline void gc_zval_check_possible_root(zval *z TSRMLS_DC)
181 0 : {
182 0 : if (z->type == IS_ARRAY || z->type == IS_OBJECT) {
183 0 : gc_zval_possible_root(z TSRMLS_CC);
184 : }
185 0 : }
186 :
187 : static zend_always_inline void gc_remove_from_buffer(gc_root_buffer *root TSRMLS_DC)
188 0 : {
189 0 : root->next->prev = root->prev;
190 0 : root->prev->next = root->next;
191 0 : root->prev = GC_G(unused);
192 0 : GC_G(unused) = root;
193 : GC_BENCH_DEC(root_buf_length);
194 0 : }
195 :
196 : #define ALLOC_PERMANENT_ZVAL(z) \
197 : do { \
198 : (z) = (zval*)malloc(sizeof(zval_gc_info)); \
199 : GC_ZVAL_INIT(z); \
200 : } while (0)
201 :
202 : /* The following macroses override macroses from zend_alloc.h */
203 : #undef ALLOC_ZVAL
204 : #define ALLOC_ZVAL(z) \
205 : do { \
206 : (z) = (zval*)emalloc(sizeof(zval_gc_info)); \
207 : GC_ZVAL_INIT(z); \
208 : } while (0)
209 :
210 : #undef FREE_ZVAL
211 : #define FREE_ZVAL(z) \
212 : do { \
213 : GC_REMOVE_ZVAL_FROM_BUFFER(z); \
214 : efree(z); \
215 : } while (0)
216 :
217 : #undef ALLOC_ZVAL_REL
218 : #define ALLOC_ZVAL_REL(z) \
219 : do { \
220 : (z) = (zval*)emalloc_rel(sizeof(zval_gc_info)); \
221 : GC_ZVAL_INIT(z); \
222 : } while (0)
223 :
224 : #undef FREE_ZVAL_REL
225 : #define FREE_ZVAL_REL(z) \
226 : do { \
227 : GC_REMOVE_ZVAL_FROM_BUFFER(z); \
228 : efree_rel(z); \
229 : } while (0)
230 :
231 : #define FREE_ZVAL_EX(z) \
232 : efree(z)
233 :
234 : #define FREE_ZVAL_REL_EX(z) \
235 : efree_rel(z)
236 :
237 : #endif /* ZEND_GC_H */
238 :
239 : /*
240 : * Local variables:
241 : * tab-width: 4
242 : * c-basic-offset: 4
243 : * indent-tabs-mode: t
244 : * End:
245 : */
|