summaryrefslogtreecommitdiff
path: root/Zend/zend_objects_API.c
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2014-04-09 01:50:15 +0400
committerDmitry Stogov <dmitry@zend.com>2014-04-09 01:50:15 +0400
commit7402af380b3a700dda0e89470770fde15bd56204 (patch)
tree4b8c1fdd87745f9ab0ce7f4fd32f07562d8772dc /Zend/zend_objects_API.c
parent0e7d30e8d3d3b7b637e64f6f1e2430d607d01dfc (diff)
downloadphp-git-7402af380b3a700dda0e89470770fde15bd56204.tar.gz
Fixed destruction of objects and iterators on unclean request shutdown and GC (few cases are still unfixed).
Now we destroy objects it two steps. At first - object properties of all objects and only then the objects their selves.
Diffstat (limited to 'Zend/zend_objects_API.c')
-rw-r--r--Zend/zend_objects_API.c72
1 files changed, 48 insertions, 24 deletions
diff --git a/Zend/zend_objects_API.c b/Zend/zend_objects_API.c
index a65b4a993e..541b2a465f 100644
--- a/Zend/zend_objects_API.c
+++ b/Zend/zend_objects_API.c
@@ -42,12 +42,12 @@ ZEND_API void zend_objects_store_destroy(zend_objects_store *objects)
ZEND_API void zend_objects_store_call_destructors(zend_objects_store *objects TSRMLS_DC)
{
- zend_uint i = 1;
+ zend_uint i;
for (i = 1; i < objects->top ; i++) {
zend_object *obj = objects->object_buckets[i];
- if (IS_VALID(obj)) {
+ if (IS_OBJ_VALID(obj)) {
if (!(GC_FLAGS(obj) & IS_OBJ_DESTRUCTOR_CALLED)) {
GC_FLAGS(obj) |= IS_OBJ_DESTRUCTOR_CALLED;
GC_REFCOUNT(obj)++;
@@ -68,7 +68,7 @@ ZEND_API void zend_objects_store_mark_destructed(zend_objects_store *objects TSR
for (i = 1; i < objects->top ; i++) {
zend_object *obj = objects->object_buckets[i];
- if (IS_VALID(obj)) {
+ if (IS_OBJ_VALID(obj)) {
GC_FLAGS(obj) |= IS_OBJ_DESTRUCTOR_CALLED;
}
}
@@ -76,17 +76,33 @@ ZEND_API void zend_objects_store_mark_destructed(zend_objects_store *objects TSR
ZEND_API void zend_objects_store_free_object_storage(zend_objects_store *objects TSRMLS_DC)
{
- zend_uint i = 1;
+ zend_uint i;
+ /* Free object properties but don't free object their selves */
for (i = 1; i < objects->top ; i++) {
zend_object *obj = objects->object_buckets[i];
- if (IS_VALID(obj)) {
- objects->object_buckets[i] = SET_INVALID(obj);
- if (obj->handlers->free_obj) {
- obj->handlers->free_obj(obj TSRMLS_CC);
+ if (IS_OBJ_VALID(obj)) {
+ if (!(GC_FLAGS(obj) & IS_OBJ_FREE_CALLED)) {
+ GC_FLAGS(obj) |= IS_OBJ_FREE_CALLED;
+ if (obj->handlers->free_obj) {
+ GC_REFCOUNT(obj)++;
+ obj->handlers->free_obj(obj TSRMLS_CC);
+ GC_REFCOUNT(obj)--;
+ }
}
+ }
+ }
+
+ /* Now free objects theirselves */
+ for (i = 1; i < objects->top ; i++) {
+ zend_object *obj = objects->object_buckets[i];
+
+ if (IS_OBJ_VALID(obj)) {
/* Not adding to free list as we are shutting down anyway */
+ void *ptr = ((char*)obj) - obj->handlers->offset;
+ GC_REMOVE_FROM_BUFFER(obj);
+ efree(ptr);
}
}
}
@@ -100,7 +116,7 @@ ZEND_API void zend_objects_store_put(zend_object *object TSRMLS_DC)
if (EG(objects_store).free_list_head != -1) {
handle = EG(objects_store).free_list_head;
- EG(objects_store).free_list_head = GET_BUCKET_NUMBER(EG(objects_store).object_buckets[handle]);
+ EG(objects_store).free_list_head = GET_OBJ_BUCKET_NUMBER(EG(objects_store).object_buckets[handle]);
} else {
if (EG(objects_store).top == EG(objects_store).size) {
EG(objects_store).size <<= 1;
@@ -113,17 +129,16 @@ ZEND_API void zend_objects_store_put(zend_object *object TSRMLS_DC)
}
#define ZEND_OBJECTS_STORE_ADD_TO_FREE_LIST(handle) \
- SET_BUCKET_NUMBER(EG(objects_store).object_buckets[handle], EG(objects_store).free_list_head); \
+ SET_OBJ_BUCKET_NUMBER(EG(objects_store).object_buckets[handle], EG(objects_store).free_list_head); \
EG(objects_store).free_list_head = handle;
ZEND_API void zend_objects_store_free(zend_object *object TSRMLS_DC) /* {{{ */
{
- int handle = object->handle;
+ zend_uint handle = object->handle;
+ void *ptr = ((char*)object) - object->handlers->offset;
- EG(objects_store).object_buckets[handle] = SET_INVALID(object);
- if (object->handlers->free_obj) {
- object->handlers->free_obj(object TSRMLS_CC);
- }
+ GC_REMOVE_FROM_BUFFER(object);
+ efree(ptr);
ZEND_OBJECTS_STORE_ADD_TO_FREE_LIST(handle);
}
/* }}} */
@@ -135,7 +150,7 @@ ZEND_API void zend_objects_store_del(zend_object *object TSRMLS_DC) /* {{{ */
when the refcount reaches 0 a second time
*/
if (EG(objects_store).object_buckets &&
- IS_VALID(EG(objects_store).object_buckets[object->handle])) {
+ IS_OBJ_VALID(EG(objects_store).object_buckets[object->handle])) {
if (GC_REFCOUNT(object) == 0) {
int failure = 0;
@@ -155,15 +170,24 @@ ZEND_API void zend_objects_store_del(zend_object *object TSRMLS_DC) /* {{{ */
if (GC_REFCOUNT(object) == 0) {
zend_uint handle = object->handle;
-
- EG(objects_store).object_buckets[handle] = SET_INVALID(object);
- if (object->handlers->free_obj) {
- zend_try {
- object->handlers->free_obj(object TSRMLS_CC);
- } zend_catch {
- failure = 1;
- } zend_end_try();
+ void *ptr;
+
+ EG(objects_store).object_buckets[handle] = SET_OBJ_INVALID(object);
+ if (!(GC_FLAGS(object) & IS_OBJ_FREE_CALLED)) {
+ GC_FLAGS(object) |= IS_OBJ_FREE_CALLED;
+ if (object->handlers->free_obj) {
+ zend_try {
+ GC_REFCOUNT(object)++;
+ object->handlers->free_obj(object TSRMLS_CC);
+ GC_REFCOUNT(object)++;
+ } zend_catch {
+ failure = 1;
+ } zend_end_try();
+ }
}
+ ptr = ((char*)object) - object->handlers->offset;
+ GC_REMOVE_FROM_BUFFER(object);
+ efree(ptr);
ZEND_OBJECTS_STORE_ADD_TO_FREE_LIST(handle);
}