pthreads_monitor_state_t pthreads_stack_next(pthreads_stack_t *stack, zval *value, zend_object **running) { pthreads_monitor_state_t state = PTHREADS_MONITOR_RUNNING; if (pthreads_monitor_lock(stack->monitor)) { #define SET_RUNNING_TO(t) *running = t do { if (!stack->head) { if (pthreads_monitor_check(stack->monitor, PTHREADS_MONITOR_JOINED)) { state = PTHREADS_MONITOR_JOINED; SET_RUNNING_TO(NULL); break; } SET_RUNNING_TO(NULL); pthreads_monitor_wait(stack->monitor, 0); } else { pthreads_stack_remove(stack, stack->head, value, PTHREADS_STACK_GARBAGE); SET_RUNNING_TO(Z_OBJ_P(value)); break; } } while (state != PTHREADS_MONITOR_JOINED); #undef SET_RUNNING_TO pthreads_monitor_unlock(stack->monitor); } return state; }
void pthreads_stack_free(pthreads_stack_t *stack) { pthreads_monitor_t *monitor = stack->monitor; if (pthreads_monitor_lock(monitor)) { pthreads_stack_item_t *item = stack->head; while (item) { pthreads_stack_item_t *r = item; zval_ptr_dtor(&item->value); item = r->next; efree(r); } if (stack->gc) { item = stack->gc->head; while (item) { pthreads_stack_item_t *r = item; zval_ptr_dtor(&item->value); item = r->next; efree(r); } } efree(stack->gc); efree(stack); pthreads_monitor_unlock(monitor); } }
zend_long pthreads_stack_size(pthreads_stack_t *stack) { zend_long size = 0; if (pthreads_monitor_lock(stack->monitor)) { size = stack->size; pthreads_monitor_unlock(stack->monitor); } return size; }
zend_long pthreads_stack_del(pthreads_stack_t *stack, zval *value) { zend_long size = 0; if (pthreads_monitor_lock(stack->monitor)) { size = pthreads_stack_remove( stack, stack->head, value, PTHREADS_STACK_FREE); pthreads_monitor_unlock(stack->monitor); } return size; }
zend_long pthreads_stack_collect(zend_object *std, pthreads_stack_t *stack, pthreads_call_t *call, pthreads_stack_running_function_t running, pthreads_stack_collect_function_t collect) { zend_long size = 0, offset = 0; if (pthreads_monitor_lock(stack->monitor)) { pthreads_stack_item_t *item; if (stack->gc) { item = stack->gc->head; while (item) { if (running(std, &item->value)) { offset++; /* we break out of gc if the worker is executing something on the stack */ /* this means gc is only performed while the worker is idle */ /* this means we avoid contention for locks on objects the programmer thinks are executing */ break; } if (collect(call, &item->value)) { pthreads_stack_item_t *garbage = item; pthreads_stack_remove( stack->gc, garbage, NULL, PTHREADS_STACK_NOTHING); item = garbage->next; zval_ptr_dtor(&garbage->value); efree(garbage); continue; } item = item->next; } size = (stack->size + stack->gc->size) + -offset; } pthreads_monitor_unlock(stack->monitor); } return size; }
zend_long pthreads_stack_add(pthreads_stack_t *stack, zval *value) { zend_long size = 0; pthreads_stack_item_t *item = (pthreads_stack_item_t*) ecalloc(1, sizeof(pthreads_stack_item_t)); ZVAL_COPY(&item->value, value); if (pthreads_monitor_lock(stack->monitor)) { size = stack->size; pthreads_stack_add_item(stack, item); if (!size) { pthreads_monitor_notify(stack->monitor); } size = stack->size; pthreads_monitor_unlock(stack->monitor); } else { zval_ptr_dtor(&item->value); efree(item); size = -1; } return size; }
void pthreads_stack_tohash(pthreads_stack_t *stack, HashTable *hash) { zval stacked; zval waiting; zval gc; array_init(&stacked); array_init(&waiting); array_init(&gc); zend_hash_str_add(Z_ARRVAL(stacked), ":stacked:", sizeof(":stacked:")-1, &waiting); zend_hash_str_add(Z_ARRVAL(stacked), ":gc:", sizeof(":gc:")-1, &gc); if (pthreads_monitor_lock(stack->monitor)) { pthreads_stack_item_t *item = stack->head; while (item) { if (add_next_index_zval( &waiting, &item->value)) { Z_ADDREF(item->value); } item = item->next; } item = stack->gc->head; while (item) { if (add_next_index_zval( &gc, &item->value)) { Z_ADDREF(item->value); } item = item->next; } pthreads_monitor_unlock(stack->monitor); } zend_hash_str_add(hash, ":stack:", sizeof(":stack:")-1, &stacked); }
/* {{{ */ zend_bool pthreads_globals_lock(){ return pthreads_monitor_lock(PTHREADS_G(monitor)); } /* }}} */
/* {{{ */ void pthreads_write_property(PTHREADS_WRITE_PROPERTY_PASSTHRU_D) { pthreads_object_t* threaded = PTHREADS_FETCH_FROM(Z_OBJ_P(object)); zend_bool nulled = 0; zval mstring; if (member == NULL || Z_TYPE_P(member) == IS_NULL) { pthreads_monitor_lock(threaded->monitor); { ZVAL_LONG( &mstring, zend_hash_next_free_element(threaded->store)); member = &mstring; } pthreads_monitor_unlock(threaded->monitor); } rebuild_object_properties(&threaded->std); switch(Z_TYPE_P(value)){ case IS_UNDEF: case IS_STRING: case IS_LONG: case IS_ARRAY: case IS_OBJECT: case IS_NULL: case IS_DOUBLE: case IS_RESOURCE: case IS_TRUE: case IS_FALSE: { zend_long *guard = NULL; if (Z_OBJCE_P(object)->__set && (guard = pthreads_get_guard(&threaded->std, member)) && !((*guard) & IN_SET)) { zend_fcall_info fci = empty_fcall_info; zend_fcall_info_cache fcc = empty_fcall_info_cache; zval rv; ZVAL_UNDEF(&rv); fci.size = sizeof(zend_fcall_info); fci.retval = &rv; fci.object = &threaded->std; zend_fcall_info_argn(&fci, 2, member, value); fcc.initialized = 1; fcc.function_handler = Z_OBJCE_P(object)->__set; fcc.object = &threaded->std; (*guard) |= IN_SET; zend_call_function(&fci, &fcc); (*guard) &= ~IN_SET; if (Z_TYPE(rv) != IS_UNDEF) zval_dtor(&rv); zend_fcall_info_args_clear(&fci, 1); } else { pthreads_store_write(object, member, value); } } break; default: { zend_throw_exception_ex( spl_ce_RuntimeException, 0, "pthreads detected an attempt to use unsupported data (%s) for %s::$%s", zend_get_type_by_const(Z_TYPE_P(value)), ZSTR_VAL(Z_OBJCE_P(object)->name), Z_STRVAL_P(member)); } } }