diff --git a/classes/pool.h b/classes/pool.h index 6023133c..7e7d209b 100644 --- a/classes/pool.h +++ b/classes/pool.h @@ -289,13 +289,13 @@ PHP_METHOD(Pool, collect) { RETURN_LONG(0); ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(workers), worker) { - pthreads_object_t *thread = + pthreads_zend_object_t *thread = PTHREADS_FETCH_FROM(Z_OBJ_P(worker)); if (!ZEND_NUM_ARGS()) PTHREADS_WORKER_COLLECTOR_INIT(call, Z_OBJ_P(worker)); collectable += pthreads_stack_collect( &thread->std, - thread->stack, + thread->ts_obj->stack, &call, pthreads_worker_running_function, pthreads_worker_collect_function); diff --git a/classes/thread.h b/classes/thread.h index 5e5d1a62..7d7092e7 100644 --- a/classes/thread.h +++ b/classes/thread.h @@ -83,7 +83,7 @@ zend_function_entry pthreads_thread_methods[] = { $options should be a mask of inheritance constants */ PHP_METHOD(Thread, start) { - pthreads_object_t* thread = PTHREADS_FETCH; + pthreads_zend_object_t* thread = PTHREADS_FETCH; zend_long options = PTHREADS_INHERIT_ALL; if (ZEND_NUM_ARGS()) { @@ -91,7 +91,7 @@ PHP_METHOD(Thread, start) return; } - thread->options = options; + thread->ts_obj->options = options; } RETURN_BOOL(pthreads_start(thread)); @@ -101,7 +101,7 @@ PHP_METHOD(Thread, start) Will return true if a Thread has been started */ PHP_METHOD(Thread, isStarted) { - pthreads_object_t* thread = PTHREADS_FETCH; + pthreads_object_t* thread = PTHREADS_FETCH_TS; RETURN_BOOL(pthreads_monitor_check(thread->monitor, PTHREADS_MONITOR_STARTED)); } /* }}} */ @@ -110,7 +110,7 @@ PHP_METHOD(Thread, isStarted) Will return true if a Thread has been joined already */ PHP_METHOD(Thread, isJoined) { - pthreads_object_t* thread = PTHREADS_FETCH; + pthreads_object_t* thread = PTHREADS_FETCH_TS; RETURN_BOOL(pthreads_monitor_check(thread->monitor, PTHREADS_MONITOR_JOINED)); } /* }}} */ @@ -119,7 +119,7 @@ PHP_METHOD(Thread, isJoined) Will return a boolean indication of success */ PHP_METHOD(Thread, join) { - pthreads_object_t* thread = PTHREADS_FETCH; + pthreads_zend_object_t* thread = PTHREADS_FETCH; RETURN_BOOL(pthreads_join(thread)); } /* }}} */ @@ -128,7 +128,7 @@ PHP_METHOD(Thread, join) Will return the identifier of the referenced Thread */ PHP_METHOD(Thread, getThreadId) { - ZVAL_LONG(return_value, (PTHREADS_FETCH_FROM(Z_OBJ_P(getThis())))->local.id); + ZVAL_LONG(return_value, (PTHREADS_FETCH_TS_FROM(Z_OBJ_P(getThis())))->local.id); } /* }}} */ /* {{{ proto long Thread::getCurrentThreadId() @@ -149,7 +149,7 @@ PHP_METHOD(Thread, getCurrentThread) Will return the identifier of the thread ( or process ) that created the referenced Thread */ PHP_METHOD(Thread, getCreatorId) { - ZVAL_LONG(return_value, (PTHREADS_FETCH_FROM(Z_OBJ_P(getThis())))->creator.id); + ZVAL_LONG(return_value, (PTHREADS_FETCH_TS_FROM(Z_OBJ_P(getThis())))->creator.id); } /* }}} */ # endif #endif diff --git a/classes/threaded.h b/classes/threaded.h index f3dc5c02..7c5d93cb 100644 --- a/classes/threaded.h +++ b/classes/threaded.h @@ -128,7 +128,7 @@ PHP_METHOD(Threaded, getRefCount) { RETURN_LONG(Z_REFCOUNT_P(getThis())); } /* Otherwise returns a boolean indication of success */ PHP_METHOD(Threaded, wait) { - pthreads_object_t* threaded = PTHREADS_FETCH; + pthreads_object_t* threaded = PTHREADS_FETCH_TS; zend_long timeout = 0L; if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &timeout)==SUCCESS) { @@ -141,7 +141,7 @@ PHP_METHOD(Threaded, wait) Will return a boolean indication of success */ PHP_METHOD(Threaded, notify) { - pthreads_object_t* threaded = PTHREADS_FETCH; + pthreads_object_t* threaded = PTHREADS_FETCH_TS; RETURN_BOOL(pthreads_monitor_notify(threaded->monitor) == SUCCESS); } /* }}} */ @@ -151,7 +151,7 @@ PHP_METHOD(Threaded, notify) Will return a boolean indication of success */ PHP_METHOD(Threaded, notifyOne) { - pthreads_object_t* threaded = PTHREADS_FETCH; + pthreads_object_t* threaded = PTHREADS_FETCH_TS; RETURN_BOOL(pthreads_monitor_notify_one(threaded->monitor) == SUCCESS); } /* }}} */ @@ -160,7 +160,7 @@ PHP_METHOD(Threaded, notifyOne) Will return true while the referenced Threaded is being executed by a Worker */ PHP_METHOD(Threaded, isRunning) { - pthreads_object_t* threaded = PTHREADS_FETCH; + pthreads_object_t* threaded = PTHREADS_FETCH_TS; RETURN_BOOL(pthreads_monitor_check(threaded->monitor, PTHREADS_MONITOR_RUNNING)); } /* }}} */ @@ -169,7 +169,7 @@ PHP_METHOD(Threaded, isRunning) Will return true if the referenced Threaded suffered fatal errors or uncaught exceptions */ PHP_METHOD(Threaded, isTerminated) { - pthreads_object_t* threaded = PTHREADS_FETCH; + pthreads_object_t* threaded = PTHREADS_FETCH_TS; RETURN_BOOL(pthreads_monitor_check(threaded->monitor, PTHREADS_MONITOR_ERROR)); } /* }}} */ @@ -182,7 +182,7 @@ PHP_METHOD(Threaded, synchronized) pthreads_call_t call = PTHREADS_CALL_EMPTY; uint argc = 0; zval *argv = NULL; - pthreads_object_t* threaded= PTHREADS_FETCH; + pthreads_object_t* threaded= PTHREADS_FETCH_TS; if (zend_parse_parameters(ZEND_NUM_ARGS(), "f|+", &call.fci, &call.fcc, &argv, &argc) != SUCCESS) { return; diff --git a/classes/worker.h b/classes/worker.h index 5ea0cb9d..8bc9716a 100644 --- a/classes/worker.h +++ b/classes/worker.h @@ -91,10 +91,10 @@ zend_function_entry pthreads_worker_methods[] = { Pushes an item onto the stack, returns the size of stack */ PHP_METHOD(Worker, stack) { - pthreads_object_t* thread = PTHREADS_FETCH; + pthreads_zend_object_t* thread = PTHREADS_FETCH; zval *work; - if (!PTHREADS_IN_CREATOR(thread) || PTHREADS_IS_CONNECTION(thread)) { + if (!PTHREADS_IN_CREATOR(thread)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "only the creator of this %s may call stack", thread->std.ce->name->val); @@ -105,34 +105,34 @@ PHP_METHOD(Worker, stack) return; } - RETURN_LONG(pthreads_stack_add(thread->stack, work)); + RETURN_LONG(pthreads_stack_add(thread->ts_obj->stack, work)); } /* }}} */ /* {{{ proto Collectable Worker::unstack() Removes the first item from the stack */ PHP_METHOD(Worker, unstack) { - pthreads_object_t* thread = PTHREADS_FETCH; + pthreads_zend_object_t* thread = PTHREADS_FETCH; if (zend_parse_parameters_none() != SUCCESS) { return; } - if (!PTHREADS_IN_CREATOR(thread) || PTHREADS_IS_CONNECTION(thread)) { + if (!PTHREADS_IN_CREATOR(thread)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "only the creator of this %s may call unstack", thread->std.ce->name->val); return; } - pthreads_stack_del(thread->stack, return_value); + pthreads_stack_del(thread->ts_obj->stack, return_value); } /* {{{ proto int Worker::getStacked() Returns the current size of the stack */ PHP_METHOD(Worker, getStacked) { - pthreads_object_t* thread = PTHREADS_FETCH; + pthreads_object_t* thread = PTHREADS_FETCH_TS; RETURN_LONG(pthreads_stack_size(thread->stack)); } @@ -141,7 +141,7 @@ PHP_METHOD(Worker, getStacked) Will return true if the Worker has been shutdown */ PHP_METHOD(Worker, isShutdown) { - pthreads_object_t* thread = PTHREADS_FETCH; + pthreads_object_t* thread = PTHREADS_FETCH_TS; RETURN_BOOL(pthreads_monitor_check(thread->monitor, PTHREADS_MONITOR_JOINED)); } /* }}} */ @@ -150,7 +150,7 @@ PHP_METHOD(Worker, isShutdown) Will wait for execution of all Stackables to complete before shutting down the Worker */ PHP_METHOD(Worker, shutdown) { - pthreads_object_t* thread = PTHREADS_FETCH; + pthreads_zend_object_t* thread = PTHREADS_FETCH; RETURN_BOOL(pthreads_join(thread)); } /* }}} */ @@ -159,27 +159,27 @@ PHP_METHOD(Worker, shutdown) Will return the identifier of the referenced Worker */ PHP_METHOD(Worker, getThreadId) { - ZVAL_LONG(return_value, (PTHREADS_FETCH_FROM(Z_OBJ_P(getThis())))->local.id); + ZVAL_LONG(return_value, PTHREADS_FETCH_TS->local.id); } /* }}} */ /* {{{ proto long Worker::getCreatorId() Will return the identifier of the thread ( or process ) that created the referenced Worker */ PHP_METHOD(Worker, getCreatorId) { - ZVAL_LONG(return_value, (PTHREADS_FETCH_FROM(Z_OBJ_P(getThis())))->creator.id); + ZVAL_LONG(return_value, PTHREADS_FETCH_TS->creator.id); } /* }}} */ /* {{{ */ static zend_bool pthreads_worker_running_function(zend_object *std, zval *value) { - pthreads_object_t *worker = PTHREADS_FETCH_FROM(std), + pthreads_object_t *worker = PTHREADS_FETCH_TS_FROM(std), *running = NULL, *checking = NULL; zend_bool result = 0; if (pthreads_monitor_lock(worker->monitor)) { if (*worker->running) { - running = PTHREADS_FETCH_FROM(*worker->running); - checking = PTHREADS_FETCH_FROM(Z_OBJ_P(value)); + running = PTHREADS_FETCH_TS_FROM(*worker->running); + checking = PTHREADS_FETCH_TS_FROM(Z_OBJ_P(value)); if (running->monitor == checking->monitor) result = 1; @@ -232,7 +232,7 @@ PHP_METHOD(Worker, collector) { /* {{{ proto int Worker::collect([callable collector]) */ PHP_METHOD(Worker, collect) { - pthreads_object_t *thread = PTHREADS_FETCH; + pthreads_zend_object_t *thread = PTHREADS_FETCH; pthreads_call_t call = PTHREADS_CALL_EMPTY; if (!ZEND_NUM_ARGS()) { @@ -241,14 +241,14 @@ PHP_METHOD(Worker, collect) return; } - if (!PTHREADS_IN_CREATOR(thread) || PTHREADS_IS_CONNECTION(thread)) { + if (!PTHREADS_IN_CREATOR(thread)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "only the creator of this %s may call collect", thread->std.ce->name->val); return; } - RETVAL_LONG(pthreads_stack_collect(&thread->std, thread->stack, &call, pthreads_worker_running_function, pthreads_worker_collect_function)); + RETVAL_LONG(pthreads_stack_collect(&thread->std, thread->ts_obj->stack, &call, pthreads_worker_running_function, pthreads_worker_collect_function)); if (!ZEND_NUM_ARGS()) { PTHREADS_WORKER_COLLECTOR_DTOR(call); diff --git a/php_pthreads.c b/php_pthreads.c index b1d10231..c8bd2066 100644 --- a/php_pthreads.c +++ b/php_pthreads.c @@ -143,7 +143,7 @@ static inline zend_bool pthreads_verify_type(zend_execute_data *execute_data, zv } if (ZEND_TYPE_IS_CLASS(info->type)) { - pthreads_object_t *threaded; + pthreads_zend_object_t *threaded; if (!var || Z_TYPE_P(var) != IS_OBJECT || @@ -745,7 +745,7 @@ PHP_MINIT_FUNCTION(pthreads) memcpy(&pthreads_handlers, zend_handlers, sizeof(zend_object_handlers)); - pthreads_handlers.offset = XtOffsetOf(pthreads_object_t, std); + pthreads_handlers.offset = XtOffsetOf(pthreads_zend_object_t, std); pthreads_handlers.free_obj = pthreads_base_free; pthreads_handlers.cast_object = pthreads_cast_object; diff --git a/src/globals.c b/src/globals.c index ca66dd50..1dc74d05 100644 --- a/src/globals.c +++ b/src/globals.c @@ -32,8 +32,6 @@ struct _pthreads_globals pthreads_globals; # define PTHREADS_G () ? : (void***) &pthreads_globals #endif -extern int pthreads_connect(pthreads_object_t* source, pthreads_object_t* destination); - /* {{{ */ zend_bool pthreads_globals_init(){ if (!PTHREADS_G(init)&&!PTHREADS_G(failed)) { @@ -75,8 +73,8 @@ void pthreads_globals_unlock() { } /* }}} */ /* {{{ */ -void* pthreads_globals_object_alloc(size_t length) { - void *bucket = (void*) ecalloc(1, length); +pthreads_zend_object_t* pthreads_globals_object_alloc(size_t length) { + pthreads_zend_object_t *bucket = (pthreads_zend_object_t*) ecalloc(1, length); if (pthreads_globals_lock()) { zend_hash_index_update_ptr( @@ -91,59 +89,24 @@ void* pthreads_globals_object_alloc(size_t length) { } /* }}} */ /* {{{ */ -zend_bool pthreads_globals_object_connect(zend_ulong address, zend_class_entry *ce, zval *object) { +zend_bool pthreads_globals_object_valid(pthreads_zend_object_t *address) { zend_bool valid = 0; if (!address) return valid; if (pthreads_globals_lock()) { - if (zend_hash_index_exists(&PTHREADS_G(objects), address)) { + if (zend_hash_index_exists(&PTHREADS_G(objects), (zend_ulong) address)) { valid = 1; } pthreads_globals_unlock(); } - if (valid) { - pthreads_object_t *pthreads = (pthreads_object_t*) address; - - /* - * This can be done outside of a critical section because there are only two possibilities: - * We own the object: no possible pathway to fault (read free'd memory) - * We don't own the object: possibly pathway to fault whether we use critical section or not: - * We use a critical section: we create the connection knowing that address cannot be freed while doing so - * however, as soon as we leave the section, and before the conext that called this routine can reference the connection - * object the creating context may have free'd the object. - * We don't use a critical section: the object may be freed while we are creating the connection, causing a fault. - * - * As always, it's necessary for the programmer to retain the appropriate references so that this does not fault, creating connections - * in a critical section would be unecessarily slow, not to mention recursively lock mutex (which is fine, but not ideal). - */ - - if (PTHREADS_IN_CREATOR(pthreads)) { - /* we own the object in this context */ - ZVAL_OBJ(object, &pthreads->std); - Z_ADDREF_P(object); - } else { - /* we do not own the object, create a connection */ - if (!ce) { - /* we may not know the class, can't use ce directly - from zend_object because it is from another context */ - PTHREADS_ZG(hard_copy_interned_strings) = 1; - ce = pthreads_prepared_entry(pthreads, pthreads->std.ce); - PTHREADS_ZG(hard_copy_interned_strings) = 0; - } - object_init_ex(object, ce); - pthreads_connect(pthreads, PTHREADS_FETCH_FROM(Z_OBJ_P(object))); - } - } - return valid; } /* }}} */ - /* {{{ */ -zend_bool pthreads_globals_object_delete(void *address) { +zend_bool pthreads_globals_object_delete(pthreads_zend_object_t *address) { zend_bool deleted = 0; if (!address) diff --git a/src/globals.h b/src/globals.h index c9a51888..745aa505 100644 --- a/src/globals.h +++ b/src/globals.h @@ -71,13 +71,13 @@ ZEND_EXTERN_MODULE_GLOBALS(pthreads) /* }}} */ /* {{{ */ -zend_bool pthreads_globals_object_delete(void *address); /* }}} */ +zend_bool pthreads_globals_object_valid(pthreads_zend_object_t *address); /* }}} */ /* {{{ */ -zend_bool pthreads_globals_object_connect(zend_ulong address, zend_class_entry *ce, zval *object); /* }}} */ +zend_bool pthreads_globals_object_delete(pthreads_zend_object_t *address); /* }}} */ /* {{{ */ -void* pthreads_globals_object_alloc(size_t length); /* }}} */ +pthreads_zend_object_t* pthreads_globals_object_alloc(size_t length); /* }}} */ /* {{{ initialize (true) globals */ zend_bool pthreads_globals_init(); /* }}} */ diff --git a/src/handlers.c b/src/handlers.c index dc1acfc9..011b1bf5 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -47,7 +47,7 @@ int pthreads_count_properties(PTHREADS_COUNT_PASSTHRU_D) { /* {{{ */ int pthreads_count_properties_disallow(PTHREADS_COUNT_PASSTHRU_D) { - pthreads_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_zend_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); zend_throw_exception_ex(spl_ce_RuntimeException, 0, "%s objects are not allowed to have properties", @@ -59,7 +59,7 @@ int pthreads_count_properties_disallow(PTHREADS_COUNT_PASSTHRU_D) { /* {{{ */ HashTable* pthreads_read_debug(PTHREADS_READ_DEBUG_PASSTHRU_D) { HashTable *table = emalloc(sizeof(HashTable)); - pthreads_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_zend_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); zend_hash_init(table, 8, NULL, ZVAL_PTR_DTOR, 0); *is_temp = 1; @@ -73,7 +73,7 @@ HashTable* pthreads_read_debug(PTHREADS_READ_DEBUG_PASSTHRU_D) { /* {{{ */ HashTable* pthreads_read_properties(PTHREADS_READ_PROPERTIES_PASSTHRU_D) { - pthreads_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_zend_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); rebuild_object_properties(&threaded->std); @@ -85,7 +85,7 @@ HashTable* pthreads_read_properties(PTHREADS_READ_PROPERTIES_PASSTHRU_D) { /* {{{ */ HashTable* pthreads_read_properties_disallow(PTHREADS_READ_PROPERTIES_PASSTHRU_D) { - pthreads_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_zend_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); rebuild_object_properties(&threaded->std); @@ -99,7 +99,7 @@ HashTable* pthreads_read_properties_disallow(PTHREADS_READ_PROPERTIES_PASSTHRU_D /* {{{ */ zval * pthreads_read_property (PTHREADS_READ_PROPERTY_PASSTHRU_D) { zend_guard *guard = NULL; - pthreads_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_zend_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); rebuild_object_properties(&threaded->std); @@ -134,7 +134,7 @@ zval* pthreads_read_dimension(PTHREADS_READ_DIMENSION_PASSTHRU_D) { return pthre /* {{{ */ zval * pthreads_read_property_disallow (PTHREADS_READ_PROPERTY_PASSTHRU_D) { - pthreads_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_zend_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); zend_throw_exception_ex(spl_ce_RuntimeException, 0, "%s objects are not allowed to have properties", @@ -148,7 +148,7 @@ zval* pthreads_read_dimension_disallow(PTHREADS_READ_DIMENSION_PASSTHRU_D) { ret /* {{{ */ void pthreads_write_property(PTHREADS_WRITE_PROPERTY_PASSTHRU_D) { - pthreads_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_zend_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); rebuild_object_properties(&threaded->std); @@ -210,7 +210,7 @@ void pthreads_write_dimension(PTHREADS_WRITE_DIMENSION_PASSTHRU_D) { pthreads_wr /* {{{ */ void pthreads_write_property_disallow(PTHREADS_WRITE_PROPERTY_PASSTHRU_D) { - pthreads_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_zend_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); zend_throw_exception_ex(spl_ce_RuntimeException, 0, "%s objects are not allowed to have properties", @@ -224,7 +224,7 @@ void pthreads_write_dimension_disallow(PTHREADS_WRITE_DIMENSION_PASSTHRU_D) { pt int pthreads_has_property(PTHREADS_HAS_PROPERTY_PASSTHRU_D) { int isset = 0; zend_guard *guard = NULL; - pthreads_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_zend_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); cache = NULL; @@ -266,7 +266,7 @@ int pthreads_has_dimension(PTHREADS_HAS_DIMENSION_PASSTHRU_D) { return pthreads_ /* {{{ */ int pthreads_has_property_disallow(PTHREADS_HAS_PROPERTY_PASSTHRU_D) { - pthreads_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_zend_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); zend_throw_exception_ex(spl_ce_RuntimeException, 0, "%s objects are not allowed to have properties", @@ -281,7 +281,7 @@ int pthreads_has_dimension_disallow(PTHREADS_HAS_DIMENSION_PASSTHRU_D) { return /* {{{ */ void pthreads_unset_property(PTHREADS_UNSET_PROPERTY_PASSTHRU_D) { zend_guard *guard = NULL; - pthreads_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_zend_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); cache = NULL; @@ -323,7 +323,7 @@ void pthreads_unset_dimension(PTHREADS_UNSET_DIMENSION_PASSTHRU_D) { pthreads_un /* {{{ */ void pthreads_unset_property_disallow(PTHREADS_UNSET_PROPERTY_PASSTHRU_D) { - pthreads_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_zend_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); zend_throw_exception_ex(spl_ce_RuntimeException, 0, "%s objects are not allowed to have properties", @@ -334,11 +334,11 @@ void pthreads_unset_dimension_disallow(PTHREADS_UNSET_DIMENSION_PASSTHRU_D) { pt /* {{{ */ int pthreads_cast_object(PTHREADS_CAST_PASSTHRU_D) { - pthreads_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(from)); + pthreads_zend_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(from)); if (PTHREADS_IS_SOCKET(threaded)) { if (type == IS_LONG) { ZVAL_LONG(to, - (int) threaded->options); + (int) threaded->ts_obj->options); return SUCCESS; } return FAILURE; @@ -366,8 +366,8 @@ zend_object* pthreads_clone_object(PTHREADS_CLONE_PASSTHRU_D) /* {{{ */ int pthreads_compare_objects(PTHREADS_COMPARE_PASSTHRU_D) { - pthreads_object_t *left = PTHREADS_FETCH_FROM(Z_OBJ_P(op1)); - pthreads_object_t *right = PTHREADS_FETCH_FROM(Z_OBJ_P(op2)); + pthreads_object_t *left = PTHREADS_FETCH_TS_FROM(Z_OBJ_P(op1)); + pthreads_object_t *right = PTHREADS_FETCH_TS_FROM(Z_OBJ_P(op2)); /* comparing property tables is not useful or efficient for threaded objects */ /* in addition, it might be useful to know if two variables are infact the same physical threaded object */ diff --git a/src/object.c b/src/object.c index 165f2e64..1a980d09 100644 --- a/src/object.c +++ b/src/object.c @@ -38,7 +38,10 @@ extern zend_module_entry pthreads_module_entry; /* }}} */ /* {{{ */ -static void pthreads_base_ctor(pthreads_object_t* base, zend_class_entry *entry); /* }}} */ +static void pthreads_base_ctor(pthreads_zend_object_t* base, zend_class_entry *entry, uint scope); /* }}} */ + +/* {{{ */ +static void pthreads_ts_object_free(pthreads_zend_object_t* base); /* }}} */ /* {{{ */ static void * pthreads_routine(pthreads_routine_arg_t *arg); /* }}} */ @@ -113,12 +116,12 @@ zend_object_iterator* pthreads_object_iterator_create(zend_class_entry *ce, zval } /* {{{ */ -static void pthreads_routine_init(pthreads_routine_arg_t *r, pthreads_object_t *thread) { +static void pthreads_routine_init(pthreads_routine_arg_t *r, pthreads_zend_object_t *thread) { r->thread = thread; r->ready = pthreads_monitor_alloc(); pthreads_monitor_add( - r->thread->monitor, PTHREADS_MONITOR_STARTED); - pthreads_prepare_parent(thread); + r->thread->ts_obj->monitor, PTHREADS_MONITOR_STARTED); + pthreads_prepare_parent(thread->ts_obj); } static void pthreads_routine_wait(pthreads_routine_arg_t *r) { @@ -129,17 +132,16 @@ static void pthreads_routine_wait(pthreads_routine_arg_t *r) { static void pthreads_routine_free(pthreads_routine_arg_t *r) { pthreads_monitor_remove( - r->thread->monitor, PTHREADS_MONITOR_STARTED); + r->thread->ts_obj->monitor, PTHREADS_MONITOR_STARTED); pthreads_monitor_free(r->ready); } /* }}} */ /* {{{ */ zend_object* pthreads_thread_ctor(zend_class_entry *entry) { - pthreads_object_t* thread = pthreads_globals_object_alloc( - sizeof(pthreads_object_t) + zend_object_properties_size(entry)); + pthreads_zend_object_t* thread = pthreads_globals_object_alloc( + sizeof(pthreads_zend_object_t) + zend_object_properties_size(entry)); - thread->scope = PTHREADS_SCOPE_THREAD; - pthreads_base_ctor(thread, entry); + pthreads_base_ctor(thread, entry, PTHREADS_SCOPE_THREAD); thread->std.handlers = &pthreads_handlers; return &thread->std; @@ -147,11 +149,10 @@ zend_object* pthreads_thread_ctor(zend_class_entry *entry) { /* {{{ */ zend_object* pthreads_worker_ctor(zend_class_entry *entry) { - pthreads_object_t* worker = pthreads_globals_object_alloc( - sizeof(pthreads_object_t) + zend_object_properties_size(entry)); + pthreads_zend_object_t* worker = pthreads_globals_object_alloc( + sizeof(pthreads_zend_object_t) + zend_object_properties_size(entry)); - worker->scope = PTHREADS_SCOPE_WORKER; - pthreads_base_ctor(worker, entry); + pthreads_base_ctor(worker, entry, PTHREADS_SCOPE_WORKER); worker->std.handlers = &pthreads_handlers; return &worker->std; @@ -159,11 +160,10 @@ zend_object* pthreads_worker_ctor(zend_class_entry *entry) { /* {{{ */ zend_object* pthreads_threaded_ctor(zend_class_entry *entry) { - pthreads_object_t* threaded = pthreads_globals_object_alloc( - sizeof(pthreads_object_t) + zend_object_properties_size(entry)); + pthreads_zend_object_t* threaded = pthreads_globals_object_alloc( + sizeof(pthreads_zend_object_t) + zend_object_properties_size(entry)); - threaded->scope = PTHREADS_SCOPE_THREADED; - pthreads_base_ctor(threaded, entry); + pthreads_base_ctor(threaded, entry, PTHREADS_SCOPE_THREADED); threaded->std.handlers = &pthreads_handlers; return &threaded->std; @@ -171,11 +171,10 @@ zend_object* pthreads_threaded_ctor(zend_class_entry *entry) { /* {{{ */ zend_object* pthreads_socket_ctor(zend_class_entry *entry) { - pthreads_object_t* threaded = pthreads_globals_object_alloc( - sizeof(pthreads_object_t) + zend_object_properties_size(entry)); + pthreads_zend_object_t* threaded = pthreads_globals_object_alloc( + sizeof(pthreads_zend_object_t) + zend_object_properties_size(entry)); - threaded->scope = PTHREADS_SCOPE_SOCKET; - pthreads_base_ctor(threaded, entry); + pthreads_base_ctor(threaded, entry, PTHREADS_SCOPE_SOCKET); threaded->std.handlers = &pthreads_socket_handlers; return &threaded->std; @@ -183,7 +182,7 @@ zend_object* pthreads_socket_ctor(zend_class_entry *entry) { /* {{{ */ int pthreads_threaded_serialize(zval *object, unsigned char **buffer, size_t *buflen, zend_serialize_data *data) { - pthreads_object_t *address = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_zend_object_t *address = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); #ifdef _WIN64 (*buflen) = snprintf(NULL, 0, ":%I64u:", (unsigned __int64) address); #else @@ -203,7 +202,7 @@ int pthreads_threaded_serialize(zval *object, unsigned char **buffer, size_t *bu /* {{{ */ int pthreads_threaded_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buffer, size_t buflen, zend_unserialize_data *data) { - pthreads_object_t *address = NULL; + pthreads_zend_object_t *address = NULL; #ifdef _WIN64 if (!sscanf((const char*) buffer, ":%I64u:", (unsigned __int64*)&address)) { @@ -238,28 +237,14 @@ void pthreads_current_thread(zval *return_value) { } /* }}} */ /* {{{ */ -int pthreads_connect(pthreads_object_t* source, pthreads_object_t* destination) { +static inline int _pthreads_connect_nolock(pthreads_zend_object_t* source, pthreads_zend_object_t* destination) { if (source && destination) { - pthreads_ident_t destCreator = destination->creator; - - if (PTHREADS_IS_NOT_CONNECTION(destination)) { - if (!PTHREADS_IS_SOCKET(destination)) { - pthreads_store_free(destination->store.props); - if (PTHREADS_IS_WORKER(destination)) { - pthreads_stack_free(destination->stack); - } - free(destination->running); - } else { - pthreads_socket_free(destination->store.sock, 0); - } - - pthreads_monitor_free(destination->monitor); + if (destination->ts_obj && --destination->ts_obj->refcount == 0) { + pthreads_ts_object_free(destination); } - memcpy(destination, source, sizeof(pthreads_object_t) - sizeof(zend_object)); - - destination->creator = destCreator; - destination->scope |= PTHREADS_SCOPE_CONNECTION; + destination->ts_obj = source->ts_obj; + ++destination->ts_obj->refcount; if (destination->std.properties) zend_hash_clean(destination->std.properties); @@ -269,7 +254,63 @@ int pthreads_connect(pthreads_object_t* source, pthreads_object_t* destination) } /* }}} */ /* {{{ */ -static inline void pthreads_base_init(pthreads_object_t* base) { +int pthreads_connect(pthreads_zend_object_t* source, pthreads_zend_object_t* destination) { + int result = FAILURE; + if(pthreads_globals_lock()){ + result = _pthreads_connect_nolock(source, destination); + pthreads_globals_unlock(); + } + return result; +} /* }}} */ + +/* {{{ */ +//TODO: rename this +zend_bool pthreads_globals_object_connect(zend_ulong address, zend_class_entry *ce, zval *object) { + zend_bool valid = 0; + if (!pthreads_globals_lock()) { + return valid; + } + if (pthreads_globals_object_valid((pthreads_zend_object_t*) address)) { + valid = 1; + pthreads_zend_object_t *pthreads = (pthreads_zend_object_t*) address; + + /* + * This can be done outside of a critical section because there are only two possibilities: + * We own the object: no possible pathway to fault (read free'd memory) + * We don't own the object: possibly pathway to fault whether we use critical section or not: + * We use a critical section: we create the connection knowing that address cannot be freed while doing so + * however, as soon as we leave the section, and before the conext that called this routine can reference the connection + * object the creating context may have free'd the object. + * We don't use a critical section: the object may be freed while we are creating the connection, causing a fault. + * + * As always, it's necessary for the programmer to retain the appropriate references so that this does not fault, creating connections + * in a critical section would be unecessarily slow, not to mention recursively lock mutex (which is fine, but not ideal). + */ + + if (PTHREADS_THREAD_OWNS(pthreads)) { + /* we own the object in this context */ + ZVAL_OBJ(object, &pthreads->std); + Z_ADDREF_P(object); + } else { + /* we do not own the object, create a connection */ + if (!ce) { + /* we may not know the class, can't use ce directly + from zend_object because it is from another context */ + PTHREADS_ZG(hard_copy_interned_strings) = 1; + ce = pthreads_prepared_entry(pthreads->ts_obj, pthreads->std.ce); + PTHREADS_ZG(hard_copy_interned_strings) = 0; + } + object_init_ex(object, ce); + _pthreads_connect_nolock(pthreads, PTHREADS_FETCH_FROM(Z_OBJ_P(object))); + } + } + + pthreads_globals_unlock(); + return valid; +} + +/* {{{ */ +static inline void pthreads_base_init(pthreads_zend_object_t* base) { zend_property_info *info; zval tmp, key; @@ -299,63 +340,83 @@ static inline void pthreads_base_init(pthreads_object_t* base) { } /* }}} */ /* {{{ */ -static void pthreads_base_ctor(pthreads_object_t* base, zend_class_entry *entry) { - zend_object_std_init(&base->std, entry); - object_properties_init(&base->std, entry); +static pthreads_object_t* pthreads_ts_object_ctor(uint scope) { + pthreads_object_t* ts_obj = calloc(1, sizeof(pthreads_object_t)); + ts_obj->scope = scope; + ts_obj->refcount = 1; + ts_obj->monitor = pthreads_monitor_alloc(); + ts_obj->creator.ls = TSRMLS_CACHE; + ts_obj->creator.id = pthreads_self(); + ts_obj->options = PTHREADS_INHERIT_ALL; + if (!(scope & PTHREADS_SCOPE_SOCKET)) { + ts_obj->store.props = pthreads_store_alloc(); + ts_obj->running = malloc(sizeof(pthreads_zend_object_t**)); + + if (scope & PTHREADS_SCOPE_WORKER) { + ts_obj->stack = pthreads_stack_alloc(ts_obj->monitor); + } + } else { + ts_obj->store.sock = pthreads_socket_alloc(); + } + return ts_obj; +} /* }}} */ - base->creator.ls = TSRMLS_CACHE; - base->creator.id = pthreads_self(); - base->options = PTHREADS_INHERIT_ALL; +/* {{{ */ +static void pthreads_base_ctor(pthreads_zend_object_t* base, zend_class_entry *entry, uint scope) { + base->ts_obj = pthreads_ts_object_ctor(scope); + base->owner.ls = TSRMLS_CACHE; + base->owner.id = pthreads_self(); - if (PTHREADS_IS_NOT_CONNECTION(base)) { - base->monitor = pthreads_monitor_alloc(); - if (!PTHREADS_IS_SOCKET(base)) { - base->store.props = pthreads_store_alloc(); - base->running = malloc(sizeof(pthreads_object_t**)); + zend_object_std_init(&base->std, entry); + object_properties_init(&base->std, entry); + if (!(scope & PTHREADS_SCOPE_SOCKET)) { + pthreads_base_init(base); + } +} /* }}} */ +/* {{{ */ +static void pthreads_ts_object_free(pthreads_zend_object_t* base) { + pthreads_object_t *ts_obj = base->ts_obj; + if (!PTHREADS_IS_SOCKET(base)) { + if (pthreads_monitor_lock(ts_obj->monitor)) { + pthreads_store_free(ts_obj->store.props); if (PTHREADS_IS_WORKER(base)) { - base->stack = pthreads_stack_alloc(base->monitor); + pthreads_stack_free(ts_obj->stack); } - pthreads_base_init(base); - } else { - base->store.sock = pthreads_socket_alloc(); + pthreads_monitor_unlock(ts_obj->monitor); + } + + if (ts_obj->running) { + free(ts_obj->running); } + } else { + pthreads_socket_free(ts_obj->store.sock, 1); } + + pthreads_monitor_free(ts_obj->monitor); + + free(ts_obj); } /* }}} */ /* {{{ */ void pthreads_base_free(zend_object *object) { - pthreads_object_t* base = PTHREADS_FETCH_FROM(object); - - if (PTHREADS_IS_NOT_CONNECTION(base)) { - if (!PTHREADS_IS_SOCKET(base)) { - if ((PTHREADS_IS_THREAD(base)||PTHREADS_IS_WORKER(base)) && - pthreads_monitor_check(base->monitor, PTHREADS_MONITOR_STARTED) && - !pthreads_monitor_check(base->monitor, PTHREADS_MONITOR_JOINED)) { - pthreads_join(base); - } + pthreads_zend_object_t* base = PTHREADS_FETCH_FROM(object); - if (pthreads_monitor_lock(base->monitor)) { - pthreads_store_free(base->store.props); - if (PTHREADS_IS_WORKER(base)) { - pthreads_stack_free(base->stack); - } - pthreads_monitor_unlock(base->monitor); - } + if (PTHREADS_IN_CREATOR(base) && (PTHREADS_IS_THREAD(base)||PTHREADS_IS_WORKER(base)) && + pthreads_monitor_check(base->ts_obj->monitor, PTHREADS_MONITOR_STARTED) && + !pthreads_monitor_check(base->ts_obj->monitor, PTHREADS_MONITOR_JOINED)) { + pthreads_join(base); + } - if (base->running) { - free(base->running); - } - } else { - pthreads_socket_free(base->store.sock, 1); + if (pthreads_globals_lock()) { + if (--base->ts_obj->refcount == 0) { + pthreads_ts_object_free(base); } - - pthreads_monitor_free(base->monitor); + pthreads_globals_object_delete(base); + pthreads_globals_unlock(); } zend_object_std_dtor(object); - - pthreads_globals_object_delete(base); } /* }}} */ /* {{{ */ @@ -366,17 +427,18 @@ HashTable* pthreads_base_gc(zval *object, zval **table, int *n) { } /* }}} */ /* {{{ */ -zend_bool pthreads_start(pthreads_object_t* thread) { +zend_bool pthreads_start(pthreads_zend_object_t* thread) { pthreads_routine_arg_t routine; + pthreads_object_t *ts_obj = thread->ts_obj; - if (!PTHREADS_IN_CREATOR(thread) || PTHREADS_IS_CONNECTION(thread)) { + if (!PTHREADS_IN_CREATOR(thread)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "only the creator of this %s may start it", thread->std.ce->name->val); return 0; } - if (pthreads_monitor_check(thread->monitor, PTHREADS_MONITOR_STARTED)) { + if (pthreads_monitor_check(ts_obj->monitor, PTHREADS_MONITOR_STARTED)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "the creator of %s already started it", thread->std.ce->name->val); return 0; @@ -384,7 +446,7 @@ zend_bool pthreads_start(pthreads_object_t* thread) { pthreads_routine_init(&routine, thread); - switch (pthread_create(&thread->thread, NULL, (void* (*) (void*)) pthreads_routine, (void*)&routine)) { + switch (pthread_create(&ts_obj->thread, NULL, (void* (*) (void*)) pthreads_routine, (void*)&routine)) { case SUCCESS: pthreads_routine_wait(&routine); return 1; @@ -405,36 +467,36 @@ zend_bool pthreads_start(pthreads_object_t* thread) { } /* }}} */ /* {{{ */ -zend_bool pthreads_join(pthreads_object_t* thread) { +zend_bool pthreads_join(pthreads_zend_object_t* thread) { - if (!PTHREADS_IN_CREATOR(thread) || PTHREADS_IS_CONNECTION(thread)) { + if (!PTHREADS_IN_CREATOR(thread)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "only the creator of this %s may join with it", thread->std.ce->name->val); return 0; } - if (pthreads_monitor_check(thread->monitor, PTHREADS_MONITOR_JOINED)) { + if (pthreads_monitor_check(thread->ts_obj->monitor, PTHREADS_MONITOR_JOINED)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "the creator of %s already joined with it", thread->std.ce->name->val); return 0; } - if (!pthreads_monitor_check(thread->monitor, PTHREADS_MONITOR_STARTED)) { + if (!pthreads_monitor_check(thread->ts_obj->monitor, PTHREADS_MONITOR_STARTED)) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "%s has not been started", thread->std.ce->name->val); return 0; } - pthreads_monitor_add(thread->monitor, PTHREADS_MONITOR_JOINED); + pthreads_monitor_add(thread->ts_obj->monitor, PTHREADS_MONITOR_JOINED); - return (pthread_join(thread->thread, NULL) == SUCCESS); + return (pthread_join(thread->ts_obj->thread, NULL) == SUCCESS); } /* }}} */ /* {{{ */ -static inline zend_bool pthreads_routine_run_function(pthreads_object_t* object, pthreads_object_t* connection, zval *work) { +static inline zend_bool pthreads_routine_run_function(pthreads_zend_object_t* object, pthreads_zend_object_t* connection, zval *work) { zend_function *run; pthreads_call_t call = PTHREADS_CALL_EMPTY; zval zresult; @@ -443,13 +505,13 @@ static inline zend_bool pthreads_routine_run_function(pthreads_object_t* object, return 0; } - if (pthreads_monitor_check(object->monitor, PTHREADS_MONITOR_ERROR)) { + if (pthreads_monitor_check(object->ts_obj->monitor, PTHREADS_MONITOR_ERROR)) { return 0; } ZVAL_UNDEF(&zresult); - pthreads_monitor_add(object->monitor, PTHREADS_MONITOR_RUNNING); + pthreads_monitor_add(object->ts_obj->monitor, PTHREADS_MONITOR_RUNNING); if (work) pthreads_store_write(work, &PTHREADS_G(strings).worker, &PTHREADS_ZG(this)); @@ -473,37 +535,38 @@ static inline zend_bool pthreads_routine_run_function(pthreads_object_t* object, } } } zend_catch { - pthreads_monitor_add(object->monitor, PTHREADS_MONITOR_ERROR); + pthreads_monitor_add(object->ts_obj->monitor, PTHREADS_MONITOR_ERROR); } zend_end_try(); if (Z_TYPE(zresult) != IS_UNDEF) { zval_ptr_dtor(&zresult); } - pthreads_monitor_remove(object->monitor, PTHREADS_MONITOR_RUNNING); + pthreads_monitor_remove(object->ts_obj->monitor, PTHREADS_MONITOR_RUNNING); return 1; } /* }}} */ /* {{{ */ static void * pthreads_routine(pthreads_routine_arg_t *routine) { - pthreads_object_t* thread = routine->thread; + pthreads_zend_object_t* thread = routine->thread; + pthreads_object_t *ts_obj = thread->ts_obj; pthreads_monitor_t* ready = routine->ready; - if (pthreads_prepared_startup(thread, ready) == SUCCESS) { + if (pthreads_prepared_startup(ts_obj, ready, thread->std.ce) == SUCCESS) { zend_first_try { ZVAL_UNDEF(&PTHREADS_ZG(this)); - object_init_ex(&PTHREADS_ZG(this), pthreads_prepared_entry(thread, thread->std.ce)); + object_init_ex(&PTHREADS_ZG(this), pthreads_prepared_entry(ts_obj, thread->std.ce)); pthreads_routine_run_function(thread, PTHREADS_FETCH_FROM(Z_OBJ_P(&PTHREADS_ZG(this))), NULL); if (PTHREADS_IS_WORKER(thread)) { zval stacked; - while (pthreads_stack_next(thread->stack, &stacked, thread->running) != PTHREADS_MONITOR_JOINED) { + while (pthreads_stack_next(ts_obj->stack, &stacked, ts_obj->running) != PTHREADS_MONITOR_JOINED) { zval that; - pthreads_object_t* work = PTHREADS_FETCH_FROM(Z_OBJ(stacked)); - object_init_ex(&that, pthreads_prepared_entry(thread, work->std.ce)); + pthreads_zend_object_t* work = PTHREADS_FETCH_FROM(Z_OBJ(stacked)); + object_init_ex(&that, pthreads_prepared_entry(ts_obj, work->std.ce)); pthreads_routine_run_function(work, PTHREADS_FETCH_FROM(Z_OBJ(that)), &that); zval_ptr_dtor(&that); } diff --git a/src/object.h b/src/object.h index 6419d74d..bbffe445 100644 --- a/src/object.h +++ b/src/object.h @@ -42,11 +42,14 @@ int pthreads_threaded_serialize(zval *object, unsigned char **buffer, size_t *bu void pthreads_current_thread(zval *return_value); /* }}} */ /* {{{ */ -zend_bool pthreads_start(pthreads_object_t* thread); -zend_bool pthreads_join(pthreads_object_t* thread); /* }}} */ +zend_bool pthreads_start(pthreads_zend_object_t* thread); +zend_bool pthreads_join(pthreads_zend_object_t* thread); /* }}} */ /* {{{ */ -int pthreads_connect(pthreads_object_t* source, pthreads_object_t* destination); /* }}} */ +int pthreads_connect(pthreads_zend_object_t* source, pthreads_zend_object_t* destination); /* }}} */ + +/* {{{ */ +zend_bool pthreads_globals_object_connect(zend_ulong address, zend_class_entry *ce, zval *object); /* }}} */ /* {{{ */ zend_object_iterator* pthreads_object_iterator_create(zend_class_entry *ce, zval *object, int by_ref); /* }}} */ diff --git a/src/prepare.c b/src/prepare.c index 77037b66..8d4f0bcf 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -740,7 +740,7 @@ void pthreads_prepare_parent(pthreads_object_t *thread) { } /* }}} */ /* {{{ */ -int pthreads_prepared_startup(pthreads_object_t* thread, pthreads_monitor_t *ready) { +int pthreads_prepared_startup(pthreads_object_t* thread, pthreads_monitor_t *ready, zend_class_entry *thread_ce) { PTHREADS_PREPARATION_BEGIN_CRITICAL() { thread->local.id = pthreads_self(); @@ -784,7 +784,7 @@ int pthreads_prepared_startup(pthreads_object_t* thread, pthreads_monitor_t *rea if (thread->options & PTHREADS_INHERIT_CLASSES) { pthreads_prepare_classes(thread); } else { - pthreads_create_entry(thread, thread->std.ce, 0); + pthreads_create_entry(thread, thread_ce, 0); pthreads_context_late_bindings(thread); } diff --git a/src/prepare.h b/src/prepare.h index a8bb949b..db179683 100644 --- a/src/prepare.h +++ b/src/prepare.h @@ -38,7 +38,7 @@ void pthreads_context_late_bindings(pthreads_object_t* thread); /* }}} */ void pthreads_prepare_parent(pthreads_object_t *thread); /* }}} */ /* {{{ */ -int pthreads_prepared_startup(pthreads_object_t* thread, pthreads_monitor_t *ready); /* }}} */ +int pthreads_prepared_startup(pthreads_object_t* thread, pthreads_monitor_t *ready, zend_class_entry *thread_ce); /* }}} */ /* {{{ */ int pthreads_prepared_shutdown(void); /* }}} */ diff --git a/src/socket.c b/src/socket.c index 3218a926..5f9ccaf9 100644 --- a/src/socket.c +++ b/src/socket.c @@ -92,7 +92,7 @@ pthreads_socket_t* pthreads_socket_alloc(void) { void pthreads_socket_construct(zval *object, zend_long domain, zend_long type, zend_long protocol) { pthreads_object_t *threaded = - PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); threaded->store.sock->fd = socket(domain, type, protocol); @@ -109,7 +109,7 @@ void pthreads_socket_construct(zval *object, zend_long domain, zend_long type, z void pthreads_socket_set_option(zval *object, zend_long level, zend_long name, zend_long value, zval *return_value) { pthreads_object_t *threaded = - PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); PTHREADS_SOCKET_CHECK(threaded->store.sock); @@ -124,7 +124,7 @@ void pthreads_socket_set_option(zval *object, zend_long level, zend_long name, z void pthreads_socket_get_option(zval *object, zend_long level, zend_long name, zval *return_value) { pthreads_object_t *threaded = - PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); socklen_t unused = sizeof(zend_long); PTHREADS_SOCKET_CHECK(threaded->store.sock); @@ -243,7 +243,7 @@ static inline zend_bool pthreads_socket_set_inet6_addr(pthreads_socket_t *sock, void pthreads_socket_bind(zval *object, zend_string *address, zend_long port, zval *return_value) { pthreads_object_t *threaded = - PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); php_sockaddr_storage sa_storage = {0}; struct sockaddr *sock_type = (struct sockaddr*) &sa_storage; zend_long retval = 0; @@ -309,7 +309,7 @@ void pthreads_socket_bind(zval *object, zend_string *address, zend_long port, zv void pthreads_socket_listen(zval *object, zend_long backlog, zval *return_value) { pthreads_object_t *threaded = - PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); PTHREADS_SOCKET_CHECK(threaded->store.sock); @@ -324,7 +324,7 @@ void pthreads_socket_listen(zval *object, zend_long backlog, zval *return_value) void pthreads_socket_accept(zval *object, zend_class_entry *ce, zval *return_value) { pthreads_object_t *threaded = - PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); pthreads_object_t *accepted; php_sockaddr_storage sa; @@ -348,7 +348,7 @@ void pthreads_socket_accept(zval *object, zend_class_entry *ce, zval *return_val } object_init_ex(return_value, ce); - accepted = PTHREADS_FETCH_FROM(Z_OBJ_P(return_value)); + accepted = PTHREADS_FETCH_TS_FROM(Z_OBJ_P(return_value)); accepted->store.sock->fd = acceptedFd; accepted->store.sock->blocking = 1; accepted->store.sock->domain = ((struct sockaddr*) &sa)->sa_family; @@ -356,7 +356,7 @@ void pthreads_socket_accept(zval *object, zend_class_entry *ce, zval *return_val void pthreads_socket_connect(zval *object, int argc, zend_string *address, zend_long port, zval *return_value) { pthreads_object_t *threaded = - PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); int retval; PTHREADS_SOCKET_CHECK(threaded->store.sock); @@ -497,7 +497,7 @@ static int pthreads_normal_read(pthreads_object_t *threaded, void *buf, size_t m void pthreads_socket_read(zval *object, zend_long length, zend_long flags, zend_long type, zval *return_value) { pthreads_object_t *threaded = - PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); zend_string *buf; int bytes; @@ -534,7 +534,7 @@ void pthreads_socket_read(zval *object, zend_long length, zend_long flags, zend_ void pthreads_socket_write(zval *object, zend_string *buf, zend_long length, zval *return_value) { pthreads_object_t *threaded = - PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); PTHREADS_SOCKET_CHECK(threaded->store.sock); int bytes; @@ -560,7 +560,7 @@ void pthreads_socket_write(zval *object, zend_string *buf, zend_long length, zva void pthreads_socket_send(zval *object, zend_string *buf, zend_long length, zend_long flags, zval *return_value) { pthreads_object_t *threaded = - PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); int bytes; PTHREADS_SOCKET_CHECK(threaded->store.sock); @@ -578,7 +578,7 @@ void pthreads_socket_send(zval *object, zend_string *buf, zend_long length, zend void pthreads_socket_close(zval *object, zval *return_value) { pthreads_object_t *threaded = - PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); PTHREADS_SOCKET_CHECK(threaded->store.sock); @@ -593,7 +593,7 @@ void pthreads_socket_close(zval *object, zval *return_value) { void pthreads_socket_set_blocking(zval *object, zend_bool blocking, zval *return_value) { pthreads_object_t *threaded = - PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); PTHREADS_SOCKET_CHECK(threaded->store.sock); @@ -644,7 +644,7 @@ void pthreads_socket_get_sockaddr(zval *object, zend_long port, struct sockaddr void pthreads_socket_get_peer_name(zval *object, zend_bool port, zval *return_value) { pthreads_object_t *threaded = - PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); php_sockaddr_storage sa_storage; struct sockaddr *sa = (struct sockaddr *) &sa_storage; socklen_t salen = sizeof(php_sockaddr_storage); @@ -662,7 +662,7 @@ void pthreads_socket_get_peer_name(zval *object, zend_bool port, zval *return_va void pthreads_socket_get_sock_name(zval *object, zend_bool port, zval *return_value) { pthreads_object_t *threaded = - PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); php_sockaddr_storage sa_storage; struct sockaddr *sa = (struct sockaddr *) &sa_storage; socklen_t salen = sizeof(php_sockaddr_storage); @@ -695,7 +695,7 @@ static inline int pthreads_sockets_to_fd_set(zval *sockets, fd_set *fds, php_soc continue; } - threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(element)); + threaded = PTHREADS_FETCH_TS_FROM(Z_OBJ_P(element)); PTHREADS_SOCKET_CHECK_EX(threaded->store.sock, 0); @@ -732,7 +732,7 @@ static int pthreads_sockets_from_fd_set(zval *sockets, fd_set *fds) /* {{{ */ continue; } - threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(element)); + threaded = PTHREADS_FETCH_TS_FROM(Z_OBJ_P(element)); if (PHP_SAFE_FD_ISSET(threaded->store.sock->fd, fds)) { if (key) { @@ -854,7 +854,7 @@ void pthreads_socket_free(pthreads_socket_t *socket, zend_bool closing) { void pthreads_socket_recvfrom(zval *object, zval *buffer, zend_long len, zend_long flags, zval *name, zval *port, zval *return_value) { pthreads_object_t *threaded = - PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); socklen_t slen; int retval; @@ -967,7 +967,7 @@ void pthreads_socket_recvfrom(zval *object, zval *buffer, zend_long len, zend_lo void pthreads_socket_sendto(zval *object, int argc, zend_string *buf, zend_long len, zend_long flags, zend_string *addr, zend_long port, zval *return_value) { pthreads_object_t *threaded = - PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); int retval; @@ -1033,7 +1033,7 @@ void pthreads_socket_sendto(zval *object, int argc, zend_string *buf, zend_long void pthreads_socket_get_last_error(zval *object, zend_bool clear, zval *return_value) { pthreads_object_t *threaded = - PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); PTHREADS_SOCKET_CHECK(threaded->store.sock); @@ -1058,7 +1058,7 @@ void pthreads_socket_strerror(zend_long error, zval *return_value) { void pthreads_socket_clear_error(zval *object) { pthreads_object_t *threaded = - PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); PTHREADS_SOCKET_CHECK(threaded->store.sock); PTHREADS_CLEAR_SOCKET_ERROR(threaded->store.sock); diff --git a/src/store.c b/src/store.c index 0c9bde25..a11a041e 100644 --- a/src/store.c +++ b/src/store.c @@ -22,10 +22,6 @@ # include #endif -#ifndef HAVE_PTHREADS_GLOBALS_H -# include -#endif - #ifndef HAVE_PTHREADS_OBJECT_H # include #endif @@ -69,7 +65,8 @@ pthreads_store_t* pthreads_store_alloc() { } /* }}} */ void pthreads_store_sync(zval *object) { /* {{{ */ - pthreads_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_zend_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_object_t *ts_obj = threaded->ts_obj; zend_ulong idx; zend_string *name; @@ -77,10 +74,10 @@ void pthreads_store_sync(zval *object) { /* {{{ */ ZEND_HASH_FOREACH_KEY(threaded->std.properties, idx, name) { if (!name) { - if (!zend_hash_index_exists(threaded->store.props, idx)) + if (!zend_hash_index_exists(ts_obj->store.props, idx)) zend_hash_index_del(threaded->std.properties, idx); } else { - if (!zend_hash_exists(threaded->store.props, name)) + if (!zend_hash_exists(ts_obj->store.props, name)) zend_hash_del(threaded->std.properties, name); } } ZEND_HASH_FOREACH_END(); @@ -112,7 +109,7 @@ static inline zend_bool pthreads_store_coerce(HashTable *table, zval *key, zval /* {{{ */ static inline zend_bool pthreads_store_is_immutable(zval *object, zval *key) { - pthreads_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_zend_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); pthreads_storage *storage; if (IS_PTHREADS_VOLATILE(object)) { @@ -120,8 +117,8 @@ static inline zend_bool pthreads_store_is_immutable(zval *object, zval *key) { } if (Z_TYPE_P(key) == IS_LONG) { - storage = zend_hash_index_find_ptr(threaded->store.props, Z_LVAL_P(key)); - } else storage = zend_hash_find_ptr(threaded->store.props, Z_STR_P(key)); + storage = zend_hash_index_find_ptr(threaded->ts_obj->store.props, Z_LVAL_P(key)); + } else storage = zend_hash_find_ptr(threaded->ts_obj->store.props, Z_STR_P(key)); if ((storage) && (storage->type == IS_PTHREADS)) { if (Z_TYPE_P(key) == IS_LONG) { @@ -141,18 +138,19 @@ static inline zend_bool pthreads_store_is_immutable(zval *object, zval *key) { int pthreads_store_delete(zval *object, zval *key) { int result = FAILURE; zval member, *property = NULL; - pthreads_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); - zend_bool coerced = pthreads_store_coerce(threaded->store.props, key, &member); + pthreads_zend_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_object_t *ts_obj = threaded->ts_obj; + zend_bool coerced = pthreads_store_coerce(ts_obj->store.props, key, &member); rebuild_object_properties(&threaded->std); - if (pthreads_monitor_lock(threaded->monitor)) { + if (pthreads_monitor_lock(ts_obj->monitor)) { if (!pthreads_store_is_immutable(object, &member)) { if (Z_TYPE(member) == IS_LONG) { - result = zend_hash_index_del(threaded->store.props, Z_LVAL(member)); - } else result = zend_hash_del(threaded->store.props, Z_STR(member)); + result = zend_hash_index_del(ts_obj->store.props, Z_LVAL(member)); + } else result = zend_hash_del(ts_obj->store.props, Z_STR(member)); } - pthreads_monitor_unlock(threaded->monitor); + pthreads_monitor_unlock(ts_obj->monitor); } else result = FAILURE; if (result == SUCCESS) { @@ -172,15 +170,16 @@ int pthreads_store_delete(zval *object, zval *key) { zend_bool pthreads_store_isset(zval *object, zval *key, int has_set_exists) { zend_bool isset = 0; zval member; - pthreads_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); - zend_bool coerced = pthreads_store_coerce(threaded->store.props, key, &member); + pthreads_zend_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_object_t *ts_obj = threaded->ts_obj; + zend_bool coerced = pthreads_store_coerce(ts_obj->store.props, key, &member); - if (pthreads_monitor_lock(threaded->monitor)) { + if (pthreads_monitor_lock(ts_obj->monitor)) { pthreads_storage *storage; if (Z_TYPE(member) == IS_LONG) { - storage = zend_hash_index_find_ptr(threaded->store.props, Z_LVAL(member)); - } else storage = zend_hash_find_ptr(threaded->store.props, Z_STR(member)); + storage = zend_hash_index_find_ptr(ts_obj->store.props, Z_LVAL(member)); + } else storage = zend_hash_find_ptr(ts_obj->store.props, Z_STR(member)); isset = storage != NULL; @@ -225,7 +224,7 @@ zend_bool pthreads_store_isset(zval *object, zval *key, int has_set_exists) { break; } } - pthreads_monitor_unlock(threaded->monitor); + pthreads_monitor_unlock(ts_obj->monitor); } if (coerced) @@ -238,8 +237,9 @@ zend_bool pthreads_store_isset(zval *object, zval *key, int has_set_exists) { int pthreads_store_read(zval *object, zval *key, int type, zval *read) { int result = FAILURE; zval member, *property = NULL; - pthreads_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); - zend_bool coerced = pthreads_store_coerce(threaded->store.props, key, &member); + pthreads_zend_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_object_t *ts_obj = threaded->ts_obj; + zend_bool coerced = pthreads_store_coerce(ts_obj->store.props, key, &member); rebuild_object_properties(&threaded->std); @@ -248,16 +248,16 @@ int pthreads_store_read(zval *object, zval *key, int type, zval *read) { } else property = zend_hash_find(threaded->std.properties, Z_STR(member)); if (property && IS_PTHREADS_VOLATILE(object)) { - if (pthreads_monitor_lock(threaded->monitor)) { + if (pthreads_monitor_lock(ts_obj->monitor)) { pthreads_storage *storage; if (Z_TYPE(member) == IS_LONG) { - storage = zend_hash_index_find_ptr(threaded->store.props, Z_LVAL(member)); - } else storage = zend_hash_find_ptr(threaded->store.props, Z_STR(member)); + storage = zend_hash_index_find_ptr(ts_obj->store.props, Z_LVAL(member)); + } else storage = zend_hash_find_ptr(ts_obj->store.props, Z_STR(member)); if (storage && storage->type == IS_PTHREADS) { - pthreads_object_t* threadedStorage = PTHREADS_FETCH_FROM(storage->data); - pthreads_object_t *threadedProperty = PTHREADS_FETCH_FROM(Z_OBJ_P(property)); + pthreads_object_t* threadedStorage = PTHREADS_FETCH_TS_FROM(storage->data); + pthreads_object_t *threadedProperty = PTHREADS_FETCH_TS_FROM(Z_OBJ_P(property)); if (threadedStorage->monitor != threadedProperty->monitor) { property = NULL; @@ -265,7 +265,7 @@ int pthreads_store_read(zval *object, zval *key, int type, zval *read) { } else { property = NULL; } - pthreads_monitor_unlock(threaded->monitor); + pthreads_monitor_unlock(ts_obj->monitor); } } @@ -277,20 +277,20 @@ int pthreads_store_read(zval *object, zval *key, int type, zval *read) { return SUCCESS; } - if (pthreads_monitor_lock(threaded->monitor)) { + if (pthreads_monitor_lock(ts_obj->monitor)) { pthreads_storage *storage; /* synchronize property stores */ pthreads_store_sync(object); if (Z_TYPE(member) == IS_LONG) { - storage = zend_hash_index_find_ptr(threaded->store.props, Z_LVAL(member)); - } else storage = zend_hash_find_ptr(threaded->store.props, Z_STR(member)); + storage = zend_hash_index_find_ptr(ts_obj->store.props, Z_LVAL(member)); + } else storage = zend_hash_find_ptr(ts_obj->store.props, Z_STR(member)); if (storage) { result = pthreads_store_convert(storage, read); } - pthreads_monitor_unlock(threaded->monitor); + pthreads_monitor_unlock(ts_obj->monitor); } if (result != SUCCESS) { @@ -316,8 +316,9 @@ int pthreads_store_write(zval *object, zval *key, zval *write) { int result = FAILURE; pthreads_storage *storage; zval vol, member, *property = NULL, *read = NULL; - pthreads_object_t *threaded = + pthreads_zend_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_object_t *ts_obj = threaded->ts_obj; zend_bool coerced = 0; if (Z_TYPE_P(write) == IS_ARRAY) { @@ -341,23 +342,23 @@ int pthreads_store_write(zval *object, zval *key, zval *write) { storage = pthreads_store_create(write, 1); - if (pthreads_monitor_lock(threaded->monitor)) { - coerced = pthreads_store_coerce(threaded->store.props, key, &member); + if (pthreads_monitor_lock(ts_obj->monitor)) { + coerced = pthreads_store_coerce(ts_obj->store.props, key, &member); if (!pthreads_store_is_immutable(object, &member)) { if (Z_TYPE(member) == IS_LONG) { - if (zend_hash_index_update_ptr(threaded->store.props, Z_LVAL(member), storage)) + if (zend_hash_index_update_ptr(ts_obj->store.props, Z_LVAL(member), storage)) result = SUCCESS; } else { /* we can't use global strings here */ zend_string *keyed = zend_string_dup(Z_STR(member), 1); - if (zend_hash_update_ptr(threaded->store.props, keyed, storage)) { + if (zend_hash_update_ptr(ts_obj->store.props, keyed, storage)) { result = SUCCESS; } zend_string_release(keyed); } } - pthreads_monitor_unlock(threaded->monitor); + pthreads_monitor_unlock(ts_obj->monitor); } if (result != SUCCESS) { @@ -422,11 +423,11 @@ void pthreads_store_separate_zval(zval *zv) { /* {{{ */ int pthreads_store_count(zval *object, zend_long *count) { - pthreads_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_object_t* ts_obj = PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); - if (pthreads_monitor_lock(threaded->monitor)) { - (*count) = zend_hash_num_elements(threaded->store.props); - pthreads_monitor_unlock(threaded->monitor); + if (pthreads_monitor_lock(ts_obj->monitor)) { + (*count) = zend_hash_num_elements(ts_obj->store.props); + pthreads_monitor_unlock(ts_obj->monitor); } else (*count) = 0L; return SUCCESS; @@ -434,30 +435,31 @@ int pthreads_store_count(zval *object, zend_long *count) { /* {{{ */ int pthreads_store_shift(zval *object, zval *member) { - pthreads_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_zend_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_object_t *ts_obj = threaded->ts_obj; rebuild_object_properties(&threaded->std); - if (pthreads_monitor_lock(threaded->monitor)) { + if (pthreads_monitor_lock(ts_obj->monitor)) { zval key; HashPosition position; pthreads_storage *storage; - zend_hash_internal_pointer_reset_ex(threaded->store.props, &position); - if ((storage = zend_hash_get_current_data_ptr_ex(threaded->store.props, &position))) { - zend_hash_get_current_key_zval_ex(threaded->store.props, &key, &position); + zend_hash_internal_pointer_reset_ex(ts_obj->store.props, &position); + if ((storage = zend_hash_get_current_data_ptr_ex(ts_obj->store.props, &position))) { + zend_hash_get_current_key_zval_ex(ts_obj->store.props, &key, &position); if (!pthreads_store_is_immutable(object, &key)) { pthreads_store_convert(storage, member); if (Z_TYPE(key) == IS_LONG) { - zend_hash_index_del(threaded->store.props, Z_LVAL(key)); + zend_hash_index_del(ts_obj->store.props, Z_LVAL(key)); zend_hash_index_del(threaded->std.properties, Z_LVAL(key)); } else { - zend_hash_del(threaded->store.props, Z_STR(key)); + zend_hash_del(ts_obj->store.props, Z_STR(key)); zend_hash_del(threaded->std.properties, Z_STR(key)); } } } else ZVAL_NULL(member); - pthreads_monitor_unlock(threaded->monitor); + pthreads_monitor_unlock(ts_obj->monitor); return SUCCESS; } @@ -467,40 +469,41 @@ int pthreads_store_shift(zval *object, zval *member) { /* {{{ */ int pthreads_store_chunk(zval *object, zend_long size, zend_bool preserve, zval *chunk) { - pthreads_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_zend_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_object_t *ts_obj = threaded->ts_obj; rebuild_object_properties(&threaded->std); - if (pthreads_monitor_lock(threaded->monitor)) { + if (pthreads_monitor_lock(ts_obj->monitor)) { HashPosition position; pthreads_storage *storage; array_init(chunk); - zend_hash_internal_pointer_reset_ex(threaded->store.props, &position); + zend_hash_internal_pointer_reset_ex(ts_obj->store.props, &position); while((zend_hash_num_elements(Z_ARRVAL_P(chunk)) < size) && - (storage = zend_hash_get_current_data_ptr_ex(threaded->store.props, &position))) { + (storage = zend_hash_get_current_data_ptr_ex(ts_obj->store.props, &position))) { zval key, zv; - zend_hash_get_current_key_zval_ex(threaded->store.props, &key, &position); + zend_hash_get_current_key_zval_ex(ts_obj->store.props, &key, &position); if (!pthreads_store_is_immutable(object, &key)) { pthreads_store_convert(storage, &zv); if (Z_TYPE(key) == IS_LONG) { zend_hash_index_update( Z_ARRVAL_P(chunk), Z_LVAL(key), &zv); - zend_hash_index_del(threaded->store.props, Z_LVAL(key)); + zend_hash_index_del(ts_obj->store.props, Z_LVAL(key)); zend_hash_index_del(threaded->std.properties, Z_LVAL(key)); } else { zend_hash_update( Z_ARRVAL_P(chunk), Z_STR(key), &zv); - zend_hash_del(threaded->store.props, Z_STR(key)); + zend_hash_del(ts_obj->store.props, Z_STR(key)); zend_hash_del(threaded->std.properties, Z_STR(key)); } } else break; - zend_hash_internal_pointer_reset_ex(threaded->store.props, &position); + zend_hash_internal_pointer_reset_ex(ts_obj->store.props, &position); } - pthreads_monitor_unlock(threaded->monitor); + pthreads_monitor_unlock(ts_obj->monitor); return SUCCESS; } @@ -510,37 +513,38 @@ int pthreads_store_chunk(zval *object, zend_long size, zend_bool preserve, zval /* {{{ */ int pthreads_store_pop(zval *object, zval *member) { - pthreads_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_zend_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_object_t *ts_obj = threaded->ts_obj; rebuild_object_properties(&threaded->std); - if (pthreads_monitor_lock(threaded->monitor)) { + if (pthreads_monitor_lock(ts_obj->monitor)) { zval key; HashPosition position; pthreads_storage *storage; - zend_hash_internal_pointer_end_ex(threaded->store.props, &position); - if ((storage = zend_hash_get_current_data_ptr_ex(threaded->store.props, &position))) { - zend_hash_get_current_key_zval_ex(threaded->store.props, &key, &position); + zend_hash_internal_pointer_end_ex(ts_obj->store.props, &position); + if ((storage = zend_hash_get_current_data_ptr_ex(ts_obj->store.props, &position))) { + zend_hash_get_current_key_zval_ex(ts_obj->store.props, &key, &position); if (!pthreads_store_is_immutable(object, &key)) { pthreads_store_convert(storage, member); if (Z_TYPE(key) == IS_LONG) { zend_hash_index_del( - threaded->store.props, Z_LVAL(key)); + ts_obj->store.props, Z_LVAL(key)); zend_hash_index_del( threaded->std.properties, Z_LVAL(key)); } else { zend_hash_del( - threaded->store.props, Z_STR(key)); + ts_obj->store.props, Z_STR(key)); zend_hash_del( threaded->std.properties, Z_STR(key)); } } } else ZVAL_NULL(member); - pthreads_monitor_unlock(threaded->monitor); + pthreads_monitor_unlock(ts_obj->monitor); return SUCCESS; } @@ -550,18 +554,19 @@ int pthreads_store_pop(zval *object, zval *member) { /* {{{ */ void pthreads_store_tohash(zval *object, HashTable *hash) { - pthreads_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_zend_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_object_t *ts_obj = threaded->ts_obj; rebuild_object_properties(&threaded->std); - if (pthreads_monitor_lock(threaded->monitor)) { + if (pthreads_monitor_lock(ts_obj->monitor)) { zend_string *name = NULL; zend_ulong idx; pthreads_storage *storage; pthreads_store_sync(object); - ZEND_HASH_FOREACH_KEY_PTR(threaded->store.props, idx, name, storage) { + ZEND_HASH_FOREACH_KEY_PTR(ts_obj->store.props, idx, name, storage) { zval pzval; zend_string *rename; @@ -592,7 +597,7 @@ void pthreads_store_tohash(zval *object, HashTable *hash) { } } ZEND_HASH_FOREACH_END(); - pthreads_monitor_unlock(threaded->monitor); + pthreads_monitor_unlock(ts_obj->monitor); } } /* }}} */ @@ -741,7 +746,7 @@ int pthreads_store_convert(pthreads_storage *storage, zval *pzval){ } break; case IS_PTHREADS: { - pthreads_object_t* threaded = PTHREADS_FETCH_FROM(storage->data); + pthreads_zend_object_t* threaded = PTHREADS_FETCH_FROM(storage->data); if (pthreads_check_opline_ex(EG(current_execute_data), 1, ZEND_CAST, IS_OBJECT)) { ZVAL_OBJ(pzval, &threaded->std); @@ -894,7 +899,7 @@ int pthreads_store_merge(zval *destination, zval *from, zend_bool overwrite) { switch (Z_TYPE_P(from)) { case IS_OBJECT: { if (IS_PTHREADS_OBJECT(from)) { - pthreads_object_t* threaded[2] = {PTHREADS_FETCH_FROM(Z_OBJ_P(destination)), PTHREADS_FETCH_FROM(Z_OBJ_P(from))}; + pthreads_object_t* threaded[2] = {PTHREADS_FETCH_TS_FROM(Z_OBJ_P(destination)), PTHREADS_FETCH_TS_FROM(Z_OBJ_P(from))}; if (pthreads_monitor_lock(threaded[0]->monitor)) { if (pthreads_monitor_lock(threaded[1]->monitor)) { @@ -960,9 +965,9 @@ int pthreads_store_merge(zval *destination, zval *from, zend_bool overwrite) { /* fall through on purpose to handle normal objects and arrays */ default: { - pthreads_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(destination)); + pthreads_object_t* ts_obj = PTHREADS_FETCH_TS_FROM(Z_OBJ_P(destination)); - if (pthreads_monitor_lock(threaded->monitor)) { + if (pthreads_monitor_lock(ts_obj->monitor)) { HashPosition position; zval *pzval; int32_t index = 0; @@ -979,14 +984,14 @@ int pthreads_store_merge(zval *destination, zval *from, zend_bool overwrite) { switch (Z_TYPE(key)) { case IS_LONG: - if (!overwrite && zend_hash_index_exists(threaded->store.props, Z_LVAL(key))) { + if (!overwrite && zend_hash_index_exists(ts_obj->store.props, Z_LVAL(key))) { goto next; } pthreads_store_write(destination, &key, pzval); break; case IS_STRING: - if (!overwrite && zend_hash_exists(threaded->store.props, Z_STR(key))) { + if (!overwrite && zend_hash_exists(ts_obj->store.props, Z_STR(key))) { goto next; } pthreads_store_write(destination, &key, pzval); @@ -997,7 +1002,7 @@ int pthreads_store_merge(zval *destination, zval *from, zend_bool overwrite) { index++; } - pthreads_monitor_unlock(threaded->monitor); + pthreads_monitor_unlock(ts_obj->monitor); } } break; } @@ -1026,24 +1031,24 @@ void pthreads_store_storage_dtor (pthreads_storage *storage){ /* {{{ iteration helpers */ void pthreads_store_reset(zval *object, HashPosition *position) { - pthreads_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_object_t *ts_obj = PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); - if (pthreads_monitor_lock(threaded->monitor)) { - zend_hash_internal_pointer_reset_ex(threaded->store.props, position); - if (zend_hash_has_more_elements_ex(threaded->store.props, position) == FAILURE) { //empty + if (pthreads_monitor_lock(ts_obj->monitor)) { + zend_hash_internal_pointer_reset_ex(ts_obj->store.props, position); + if (zend_hash_has_more_elements_ex(ts_obj->store.props, position) == FAILURE) { //empty *position = HT_INVALID_IDX; } - pthreads_monitor_unlock(threaded->monitor); + pthreads_monitor_unlock(ts_obj->monitor); } } void pthreads_store_key(zval *object, zval *key, HashPosition *position) { - pthreads_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_object_t *ts_obj = PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); zend_string *str_key; zend_ulong num_key; - if (pthreads_monitor_lock(threaded->monitor)) { - switch (zend_hash_get_current_key_ex(threaded->store.props, &str_key, &num_key, position)) { + if (pthreads_monitor_lock(ts_obj->monitor)) { + switch (zend_hash_get_current_key_ex(ts_obj->store.props, &str_key, &num_key, position)) { case HASH_KEY_NON_EXISTENT: ZVAL_NULL(key); break; @@ -1054,35 +1059,35 @@ void pthreads_store_key(zval *object, zval *key, HashPosition *position) { ZVAL_STR(key, zend_string_dup(str_key, 0)); break; } - pthreads_monitor_unlock(threaded->monitor); + pthreads_monitor_unlock(ts_obj->monitor); } } void pthreads_store_data(zval *object, zval *value, HashPosition *position) { - pthreads_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_object_t *ts_obj = PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); - if (pthreads_monitor_lock(threaded->monitor)) { + if (pthreads_monitor_lock(ts_obj->monitor)) { pthreads_storage *storage = (pthreads_storage*) - zend_hash_get_current_data_ptr_ex(threaded->store.props, position); + zend_hash_get_current_data_ptr_ex(ts_obj->store.props, position); if (storage) { pthreads_store_convert(storage, value); } else ZVAL_UNDEF(value); - pthreads_monitor_unlock(threaded->monitor); + pthreads_monitor_unlock(ts_obj->monitor); } } void pthreads_store_forward(zval *object, HashPosition *position) { - pthreads_object_t *threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); + pthreads_object_t *ts_obj = PTHREADS_FETCH_TS_FROM(Z_OBJ_P(object)); - if (pthreads_monitor_lock(threaded->monitor)) { + if (pthreads_monitor_lock(ts_obj->monitor)) { zend_hash_move_forward_ex( - threaded->store.props, position); - if (zend_hash_has_more_elements_ex(threaded->store.props, position) == FAILURE) { + ts_obj->store.props, position); + if (zend_hash_has_more_elements_ex(ts_obj->store.props, position) == FAILURE) { *position = HT_INVALID_IDX; } - pthreads_monitor_unlock(threaded->monitor); + pthreads_monitor_unlock(ts_obj->monitor); } } /* }}} */ diff --git a/src/thread.h b/src/thread.h index e8c37d57..262819f9 100644 --- a/src/thread.h +++ b/src/thread.h @@ -41,6 +41,7 @@ typedef struct _pthreads_ident_t { /* {{{ */ typedef struct _pthreads_object_t { + zend_ulong refcount; pthread_t thread; uint scope; zend_ulong options; @@ -54,12 +55,18 @@ typedef struct _pthreads_object_t { pthreads_ident_t creator; pthreads_ident_t local; zend_object **running; - zend_object std; } pthreads_object_t; /* }}} */ +/* {{{ */ +typedef struct _pthreads_zend_object_t { + pthreads_object_t *ts_obj; + pthreads_ident_t owner; + zend_object std; +} pthreads_zend_object_t; /* }}} */ + /* {{{ */ typedef struct _pthreads_routine_arg_t { - pthreads_object_t *thread; + pthreads_zend_object_t *thread; pthreads_monitor_t *ready; } pthreads_routine_arg_t; /* }}} */ @@ -70,8 +77,8 @@ typedef struct _pthreads_iterator_t { HashPosition position; } pthreads_iterator_t; /* }}} */ -static inline pthreads_object_t* _pthreads_fetch_object(zend_object *object) { - return (pthreads_object_t*) ((char*)object - XtOffsetOf(pthreads_object_t, std)); +static inline pthreads_zend_object_t* _pthreads_fetch_object(zend_object *object) { + return (pthreads_zend_object_t*) ((char*)object - XtOffsetOf(pthreads_zend_object_t, std)); } /* {{{ fetches a PTHREAD from a specific object in the current context */ @@ -80,6 +87,12 @@ static inline pthreads_object_t* _pthreads_fetch_object(zend_object *object) { /* {{{ fetches the current PTHREAD from $this */ #define PTHREADS_FETCH PTHREADS_FETCH_FROM(Z_OBJ(EX(This))) /* }}} */ +/* {{{ fetches the internal thread-safe object from the object */ +#define PTHREADS_FETCH_TS_FROM(object) PTHREADS_FETCH_FROM(object)->ts_obj /* }}} */ + +/* {{{ fetches the internal thread-safe object from $this */ +#define PTHREADS_FETCH_TS PTHREADS_FETCH_TS_FROM(Z_OBJ(EX(This))) /* }}} */ + /* {{{ option constants */ #define PTHREADS_INHERIT_NONE 0x00000000 #define PTHREADS_INHERIT_INI 0x00000001 @@ -96,20 +109,17 @@ static inline pthreads_object_t* _pthreads_fetch_object(zend_object *object) { #define PTHREADS_SCOPE_THREADED (1<<1) #define PTHREADS_SCOPE_THREAD (1<<2) #define PTHREADS_SCOPE_WORKER (1<<3) -#define PTHREADS_SCOPE_SOCKET (1<<4) -#define PTHREADS_SCOPE_CONNECTION (1<<5) /* }}} */ +#define PTHREADS_SCOPE_SOCKET (1<<4) /* }}} */ /* {{{ scope macros */ -#define PTHREADS_IS_KNOWN_ENTRY(t) ((t)->scope) -#define PTHREADS_IS_CONNECTION(t) ((t)->scope & PTHREADS_SCOPE_CONNECTION) -#define PTHREADS_IS_NOT_CONNECTION(t) (!PTHREADS_IS_CONNECTION(t)) -#define PTHREADS_IS_SOCKET(t) ((t)->scope & PTHREADS_SCOPE_SOCKET) +#define PTHREADS_IS_KNOWN_ENTRY(t) ((t)->ts_obj->scope) +#define PTHREADS_IS_SOCKET(t) ((t)->ts_obj->scope & PTHREADS_SCOPE_SOCKET) #define PTHREADS_IS_NOT_SOCKET(t) (!PTHREADS_IS_SOCKET(t)) -#define PTHREADS_IS_THREAD(t) ((t)->scope & PTHREADS_SCOPE_THREAD) +#define PTHREADS_IS_THREAD(t) ((t)->ts_obj->scope & PTHREADS_SCOPE_THREAD) #define PTHREADS_IS_NOT_THREAD(t) (!PTHREADS_IS_THREAD(t)) -#define PTHREADS_IS_WORKER(t) ((t)->scope & PTHREADS_SCOPE_WORKER) +#define PTHREADS_IS_WORKER(t) ((t)->ts_obj->scope & PTHREADS_SCOPE_WORKER) #define PTHREADS_IS_NOT_WORKER(t) (!PTHREADS_IS_WORKER(t)) -#define PTHREADS_IS_THREADED(t) ((t)->scope & PTHREADS_SCOPE_THREADED) +#define PTHREADS_IS_THREADED(t) ((t)->ts_obj->scope & PTHREADS_SCOPE_THREADED) #define PTHREADS_IS_NOT_THREADED(t) (!PTHREADS_IS_THREADED(t)) /* }}} */ /* {{{ pthread_self wrapper */ @@ -122,10 +132,13 @@ static inline ulong pthreads_self() { } /* }}} */ /* {{{ tell if the calling thread created referenced PTHREAD */ -#define PTHREADS_IN_CREATOR(t) ((t)->creator.ls == TSRMLS_CACHE) /* }}} */ +#define PTHREADS_IN_CREATOR(t) ((t)->ts_obj->creator.ls == TSRMLS_CACHE) /* }}} */ + +/* {{{ tell if the calling thread owns this pthreads zend object */ +#define PTHREADS_THREAD_OWNS(t) ((t)->owner.ls == TSRMLS_CACHE) /* }}} */ /* {{{ tell if the referenced thread is the threading context */ -#define PTHREADS_IN_THREAD(t) ((t)->local.ls == TSRMLS_CACHE) /* }}} */ +#define PTHREADS_IN_THREAD(t) ((t)->ts_obj->local.ls == TSRMLS_CACHE) /* }}} */ #endif /* HAVE_PTHREADS_THREAD_H */ diff --git a/tests/threaded-outlive-creator-lifetime.phpt b/tests/threaded-outlive-creator-lifetime.phpt new file mode 100644 index 00000000..4634a73f --- /dev/null +++ b/tests/threaded-outlive-creator-lifetime.phpt @@ -0,0 +1,74 @@ +--TEST-- +Test that Threaded object properties and sync still works when their creator is destroyed +--DESCRIPTION-- +Previously, a Threaded object's monitor and property store would be directly destroyed when the original object went out of scope, which would lead to segfaults if other threads tried to use their refs afterwards. + +Now, we refcount the internal structures for Threaded objects, so they should continue to work after their creator has gone out of scope. + +This test verifies that locking, property write and more continue to work when the thread that created it destroys its original reference. +--FILE-- +synchronized(function() : \Threaded{ + $chan = new \Threaded; + $chan[] = 1; + $this->chan = serialize($chan); + $this->notify(); + return $chan; + }); + $this->synchronized(function() use(&$chan) : void{ + while(!$this->shutdown){ + $this->wait(); + } + $chan = null; //destroy from creator context + }); + } +}; + +$t->start(); +$chan = $t->synchronized(function() use($t) : \Threaded{ + while($t->chan === null){ + $t->wait(); + } + return unserialize($t->chan); +}); +$t->synchronized(function() use($t) : void{ + $t->shutdown = true; + $t->notify(); +}); +$t->join(); +var_dump($chan); +var_dump($chan->shift()); +var_dump($chan); +var_dump($chan->property = "test"); +var_dump($chan); +var_dump($chan->count()); +$chan->synchronized(function() : void{ + echo "sync works!\n"; +}); +echo "ok\n"; +?> +--EXPECTF-- +object(Threaded)#%d (1) { + [0]=> + int(1) +} +int(1) +object(Threaded)#%d (0) { +} +string(4) "test" +object(Threaded)#%d (1) { + ["property"]=> + string(4) "test" +} +int(1) +sync works! +ok