Files
archived-pecl-networking-ge…/php_gearman_client.c
Rasmus Lerdorf f92a3297ca Support PHP 8.6
2026-03-10 23:04:04 -04:00

1279 lines
44 KiB
C

/*
* Gearman PHP Extension
*
* Copyright (C) 2008 James M. Luedke <contact@jamesluedke.com>,
* Eric Day <eday@oddments.org>
* All rights reserved.
*
* Use and distribution licensed under the PHP license. See
* the LICENSE file in this directory for full text.
*/
#include "php_gearman_task.h"
#include "php_gearman_client.h"
inline gearman_client_obj *gearman_client_fetch_object(zend_object *obj) {
return (gearman_client_obj *)((char*)(obj) - XtOffsetOf(gearman_client_obj, std));
}
static void gearman_client_ctor(INTERNAL_FUNCTION_PARAMETERS) {
gearman_client_obj *client;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
client = Z_GEARMAN_CLIENT_P(return_value);
if (gearman_client_create(&(client->client)) == NULL) {
GEARMAN_EXCEPTION("Memory allocation failure", 0);
}
client->flags |= GEARMAN_CLIENT_OBJ_CREATED;
gearman_client_add_options(&(client->client), GEARMAN_CLIENT_FREE_TASKS);
gearman_client_set_workload_malloc_fn(&(client->client), _php_malloc, NULL);
gearman_client_set_workload_free_fn(&(client->client), _php_free, NULL);
gearman_client_set_task_context_free_fn(&(client->client), _php_task_free);
}
/* {{{ proto false|object gearman_client_create()
Returns a GearmanClient object */
PHP_FUNCTION(gearman_client_create) {
if (object_init_ex(return_value, gearman_client_ce) != SUCCESS) {
php_error_docref(NULL, E_WARNING, "Object creation failure.");
RETURN_FALSE;
}
gearman_client_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
inline zend_object *gearman_client_obj_new(zend_class_entry *ce) {
gearman_client_obj *intern = ecalloc(1,
sizeof(gearman_client_obj) +
zend_object_properties_size(ce));
zend_object_std_init(&(intern->std), ce);
object_properties_init(&intern->std, ce);
array_init(&intern->task_list);
intern->created_tasks = 0;
intern->std.handlers = &gearman_client_obj_handlers;
return &intern->std;
}
/* {{{ proto object GearmanClient::__construct()
Returns a GearmanClient object */
PHP_METHOD(GearmanClient, __construct)
{
return_value = getThis();
gearman_client_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
/* {{{ proto object GearmanClient::__destruct()
cleans up GearmanClient object */
PHP_METHOD(GearmanClient, __destruct)
{
char *context = NULL;
gearman_client_obj *intern = Z_GEARMAN_CLIENT_P(getThis());
if (!intern) {
return;
}
if (intern->flags & GEARMAN_CLIENT_OBJ_CREATED) {
context = gearman_client_context(&(intern->client));
if (context) {
efree(context);
}
gearman_client_free(&intern->client);
intern->flags &= ~GEARMAN_CLIENT_OBJ_CREATED;
}
}
/* }}} */
void gearman_client_free_obj(zend_object *object) {
gearman_client_obj *intern = gearman_client_fetch_object(object);
if (!intern) {
return;
}
// Clear Callbacks
zval_ptr_dtor_nogc(&intern->zworkload_fn);
zval_ptr_dtor_nogc(&intern->zcreated_fn);
zval_ptr_dtor_nogc(&intern->zdata_fn);
zval_ptr_dtor_nogc(&intern->zwarning_fn);
zval_ptr_dtor_nogc(&intern->zstatus_fn);
zval_ptr_dtor_nogc(&intern->zcomplete_fn);
zval_ptr_dtor_nogc(&intern->zexception_fn);
zval_ptr_dtor_nogc(&intern->zfail_fn);
zval_ptr_dtor_nogc(&intern->task_list);
zend_object_std_dtor(&intern->std);
}
/* {{{ proto int gearman_client_return_code()
get last gearman_return_t */
PHP_FUNCTION(gearman_client_return_code)
{
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &zobj, gearman_client_ce) == FAILURE) {
RETURN_NULL();
}
obj = Z_GEARMAN_CLIENT_P(zobj);
RETURN_LONG(obj->ret);
}
/* }}} */
/* {{{ proto false|string gearman_client_error()
Return an error string for the last error encountered. */
PHP_FUNCTION(gearman_client_error) {
char *error = NULL;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &zobj, gearman_client_ce) == FAILURE) {
RETURN_NULL();
}
obj = Z_GEARMAN_CLIENT_P(zobj);
error = (char *)gearman_client_error(&(obj->client));
if (error) {
RETURN_STRING(error);
}
RETURN_FALSE;
}
/* }}} */
/* {{{ proto int gearman_client_get_errno()
Value of errno in the case of a GEARMAN_ERRNO return value. */
PHP_FUNCTION(gearman_client_get_errno) {
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &zobj, gearman_client_ce) == FAILURE) {
RETURN_NULL();
}
obj = Z_GEARMAN_CLIENT_P(zobj);
RETURN_LONG(gearman_client_errno(&(obj->client)));
}
/* }}} */
/* {{{ proto int gearman_client_options()
Get options for a client structure. */
PHP_FUNCTION(gearman_client_options) {
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &zobj, gearman_client_ce) == FAILURE) {
RETURN_NULL();
}
obj = Z_GEARMAN_CLIENT_P(zobj);
RETURN_LONG(gearman_client_options(&(obj->client)));
}
/* }}} */
/* {{{ proto bool gearman_client_set_options(constant option)
Set options for a client structure.
NOTE: this is deprecated in gearmand */
PHP_FUNCTION(gearman_client_set_options) {
zend_long options;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &zobj, gearman_client_ce, &options) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
gearman_client_set_options(&(obj->client), options);
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool GearmanClient::addOptions(constant option)
Set options for a client structure. */
PHP_FUNCTION(gearman_client_add_options) {
zend_long options;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &zobj, gearman_client_ce, &options) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
gearman_client_add_options(&(obj->client), options);
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool GearmanClient::removeOptions(constant option)
Set options for a client structure. */
PHP_FUNCTION(gearman_client_remove_options) {
zend_long options;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &zobj, gearman_client_ce, &options) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
gearman_client_remove_options(&(obj->client), options);
RETURN_TRUE;
}
/* }}} */
/* {{{ proto int GearmanClient::timeout()
Get current socket I/O activity timeout value */
PHP_FUNCTION(gearman_client_timeout) {
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &zobj, gearman_client_ce) == FAILURE) {
RETURN_NULL();
}
obj = Z_GEARMAN_CLIENT_P(zobj);
RETURN_LONG(gearman_client_timeout(&(obj->client)));
}
/* }}} */
/* {{{ proto bool gearman_client_set_timeout(object, constant timeout)
Set timeout for a client structure. */
PHP_FUNCTION(gearman_client_set_timeout) {
zend_long timeout;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Ol", &zobj, gearman_client_ce, &timeout) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
gearman_client_set_timeout(&(obj->client), timeout);
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool gearman_client_add_server(object client [, ?string host = null [, int port [, bool setupExceptionHandler ]]])
Add a job server to a client. This goes into a list of servers than can be used to run tasks. No socket I/O happens here, it is just added to a list. */
PHP_FUNCTION(gearman_client_add_server) {
char *host = NULL;
size_t host_len = 0;
zend_long port = 0;
zend_bool setupExceptionHandler = 1;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|slb",
&zobj,
gearman_client_ce,
&host,
&host_len,
&port,
&setupExceptionHandler) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
obj->ret = gearman_client_add_server(&(obj->client), host, port);
if (obj->ret != GEARMAN_SUCCESS) {
php_error_docref(NULL, E_WARNING, "%s",
gearman_client_error(&(obj->client)));
RETURN_FALSE;
}
if (setupExceptionHandler && !gearman_client_set_server_option(&(obj->client), "exceptions", (sizeof("exceptions") - 1))) {
GEARMAN_EXCEPTION("Failed to set exception option", 0);
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool gearman_client_add_servers(object client [, ?string servers = null [, bool setupExceptionHandler ]])
Add a list of job servers to a client. This goes into a list of servers that can be used to run tasks. No socket I/O happens here, it is just added to a list. */
PHP_FUNCTION(gearman_client_add_servers) {
char *servers = NULL;
size_t servers_len = 0;
zend_bool setupExceptionHandler = 1;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|sb",
&zobj,
gearman_client_ce,
&servers,
&servers_len,
&setupExceptionHandler) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
obj->ret = gearman_client_add_servers(&(obj->client), servers);
if (obj->ret != GEARMAN_SUCCESS) {
php_error_docref(NULL, E_WARNING, "%s",
gearman_client_error(&(obj->client)));
RETURN_FALSE;
}
if (setupExceptionHandler && !gearman_client_set_server_option(&(obj->client), "exceptions", (sizeof("exceptions") - 1))) {
GEARMAN_EXCEPTION("Failed to set exception option", 0);
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool GearmanClient::wait()
Wait for I/O activity on all connections in a client. */
PHP_FUNCTION(gearman_client_wait) {
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &zobj, gearman_client_ce) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
obj->ret = gearman_client_wait(&(obj->client));
if (! PHP_GEARMAN_CLIENT_RET_OK(obj->ret)) {
if (obj->ret != GEARMAN_TIMEOUT) {
php_error_docref(NULL, E_WARNING, "%s",
gearman_client_error(&(obj->client)));
}
RETURN_FALSE;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto string gearman_client_do_work_handler(void *add_task_func, object client, string function, zval workload [, string unique ])
Run a task, high/normal/low dependent upon do_work_func */
static void gearman_client_do_work_handler(void* (*do_work_func)(
gearman_client_st *client,
const char *function_name,
const char *unique,
const void *workload,
size_t workload_size,
size_t *result_size,
gearman_return_t *ret_ptr
),
INTERNAL_FUNCTION_PARAMETERS) {
char *function_name;
size_t function_name_len;
char *workload;
size_t workload_len;
char *unique = NULL;
size_t unique_len = 0;
void *result;
size_t result_size = 0;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oss|s", &zobj, gearman_client_ce,
&function_name, &function_name_len,
&workload, &workload_len,
&unique, &unique_len) == FAILURE) {
RETURN_EMPTY_STRING();
}
obj = Z_GEARMAN_CLIENT_P(zobj);
result = (char *)(*do_work_func)(
&(obj->client),
function_name,
unique,
workload,
(size_t)workload_len,
&result_size,
&(obj)->ret
);
if (! PHP_GEARMAN_CLIENT_RET_OK(obj->ret)) {
php_error_docref(NULL, E_WARNING, "%s", gearman_client_error(&(obj->client)));
RETURN_EMPTY_STRING();
}
/* NULL results are valid */
if (! result) {
RETURN_EMPTY_STRING();
}
ZVAL_STRINGL(return_value, (char *)result, result_size);
efree(result);
}
/* }}} */
/* {{{ proto string GearmanClient::doNormal(string function, string workload [, string unique ])
Run a single task and return an allocated result. */
PHP_FUNCTION(gearman_client_do_normal) {
gearman_client_do_work_handler(gearman_client_do, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
/* {{{ proto string GearmanClient::doHigh(object client, string function, string workload [, string unique ])
Run a high priority task and return an allocated result. */
PHP_FUNCTION(gearman_client_do_high) {
gearman_client_do_work_handler(gearman_client_do_high, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
/* {{{ proto string GearmanClient::doLow(object client, string function, string workload [, string unique ])
Run a low priority task and return an allocated result. */
PHP_FUNCTION(gearman_client_do_low) {
gearman_client_do_work_handler(gearman_client_do_low, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
/* {{{ proto string gearman_client_do_background_work_handler(void *add_task_func, object client, string function, zval workload [, string unique ])
Run a task in the background, high/normal/low dependent upon do_work_func */
static void gearman_client_do_background_work_handler(gearman_return_t (*do_background_work_func)(
gearman_client_st *client,
const char *function_name,
const char *unique,
const void *workload,
size_t workload_size,
gearman_job_handle_t job_handle
),
INTERNAL_FUNCTION_PARAMETERS) {
char *function_name;
size_t function_name_len;
char *workload;
size_t workload_len;
char *unique = NULL;
size_t unique_len = 0;
zend_string *job_handle;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oss|s!", &zobj, gearman_client_ce,
&function_name, &function_name_len,
&workload, &workload_len,
&unique, &unique_len) == FAILURE) {
RETURN_EMPTY_STRING();
}
obj = Z_GEARMAN_CLIENT_P(zobj);
job_handle = zend_string_alloc(GEARMAN_JOB_HANDLE_SIZE-1, 0);
obj->ret = (*do_background_work_func)(
&(obj->client),
(char *)function_name,
(char *)unique,
(void *)workload,
(size_t)workload_len,
job_handle->val
);
ZSTR_LEN(job_handle) = strnlen(ZSTR_VAL(job_handle), GEARMAN_JOB_HANDLE_SIZE-1);
if (! PHP_GEARMAN_CLIENT_RET_OK(obj->ret)) {
php_error_docref(NULL, E_WARNING, "%s",
gearman_client_error(&(obj->client)));
zend_string_release(job_handle);
RETURN_EMPTY_STRING();
}
RETURN_STR(job_handle);
}
/* }}} */
/* {{{ proto string GearmanClient::doBackground(string function, string workload [, string unique ])
Run a task in the background. */
PHP_FUNCTION(gearman_client_do_background) {
gearman_client_do_background_work_handler(gearman_client_do_background, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
/* {{{ proto string GearmanClient::doHighBackground(string function, string workload [, string unique ])
Run a high priority task in the background. */
PHP_FUNCTION(gearman_client_do_high_background) {
gearman_client_do_background_work_handler(gearman_client_do_high_background, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
/* {{{ proto string GearmanClient::doLowBackground(string function, string workload [, string unique ])
Run a low priority task in the background. */
PHP_FUNCTION(gearman_client_do_low_background) {
gearman_client_do_background_work_handler(gearman_client_do_low_background, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
/* {{{ proto string GearmanClient::doJobHandle()
Get the job handle for the running task. This should be used between repeated gearman_client_do_normal() and gearman_client_do_high() calls to get information. */
PHP_FUNCTION(gearman_client_do_job_handle) {
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &zobj, gearman_client_ce) == FAILURE) {
RETURN_EMPTY_STRING();
}
obj = Z_GEARMAN_CLIENT_P(zobj);
RETURN_STRING((char *)gearman_client_do_job_handle(&(obj->client)));
}
/* }}} */
/* {{{ proto array GearmanClient::doStatus()
Get the status for the running task. This should be used between repeated gearman_client_do() and gearman_client_do_high() calls to get information. */
PHP_FUNCTION(gearman_client_do_status) {
uint32_t numerator;
uint32_t denominator;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &zobj, gearman_client_ce) == FAILURE) {
RETURN_EMPTY_ARRAY();
}
obj = Z_GEARMAN_CLIENT_P(zobj);
gearman_client_do_status(&(obj->client), &numerator, &denominator);
array_init(return_value);
add_next_index_long(return_value, (long) numerator);
add_next_index_long(return_value, (long) denominator);
}
/* }}} */
/* {{{ proto array GearmanClient::jobStatus(string job_handle)
Get the status for a backgound job. */
PHP_FUNCTION(gearman_client_job_status) {
char *job_handle;
size_t job_handle_len;
bool is_known;
bool is_running;
uint32_t numerator;
uint32_t denominator;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &zobj, gearman_client_ce,
&job_handle, &job_handle_len) == FAILURE) {
RETURN_EMPTY_ARRAY();
}
obj = Z_GEARMAN_CLIENT_P(zobj);
obj->ret = gearman_client_job_status(&(obj->client), job_handle,
&is_known, &is_running,
&numerator, &denominator);
if (obj->ret != GEARMAN_SUCCESS && obj->ret != GEARMAN_IO_WAIT) {
php_error_docref(NULL, E_WARNING, "%s",
gearman_client_error(&(obj->client)));
}
array_init(return_value);
add_next_index_bool(return_value, is_known);
add_next_index_bool(return_value, is_running);
add_next_index_long(return_value, (long) numerator);
add_next_index_long(return_value, (long) denominator);
}
/* }}} */
/* {{{ proto array GearmanClient::jobStatusByUniqueKey(string unique_key)
Get the status for a backgound job using the unique key passed in during job submission, rather than job handle. */
PHP_FUNCTION(gearman_client_job_status_by_unique_key) {
char *unique_key;
size_t unique_key_len;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &zobj, gearman_client_ce,
&unique_key, &unique_key_len) == FAILURE) {
RETURN_EMPTY_ARRAY();
}
obj = Z_GEARMAN_CLIENT_P(zobj);
gearman_status_t status = gearman_client_unique_status(&(obj->client), unique_key, unique_key_len);
gearman_return_t rc = gearman_status_return(status);
if (rc != GEARMAN_SUCCESS && rc != GEARMAN_IO_WAIT) {
php_error_docref(NULL, E_WARNING, "%s",
gearman_client_error(&(obj->client)));
}
array_init(return_value);
add_next_index_bool(return_value, gearman_status_is_known(status));
add_next_index_bool(return_value, gearman_status_is_running(status));
add_next_index_long(return_value, (long) gearman_status_numerator(status));
add_next_index_long(return_value, (long) gearman_status_denominator(status));
}
/* }}} */
/* {{{ proto bool GearmanClient::ping(string workload)
Send data to all job servers to see if they send it back. */
PHP_FUNCTION(gearman_client_ping) {
char *workload;
size_t workload_len;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &zobj, gearman_client_ce, &workload, &workload_len) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
obj->ret = gearman_client_echo(&(obj->client), workload, (size_t)workload_len);
if (obj->ret != GEARMAN_SUCCESS && obj->ret != GEARMAN_IO_WAIT) {
php_error_docref(NULL, E_WARNING, "%s",
gearman_client_error(&(obj->client)));
RETURN_FALSE;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto false|object gearman_client_add_task_handler(void *add_task_func, object client, string function, zval workload [, string unique ])
Add a task to be run in parallel, background or not, high/normal/low dependent upon add_task_func. */
static void gearman_client_add_task_handler(gearman_task_st* (*add_task_func)(
gearman_client_st *client,
gearman_task_st *task,
void *context,
const char *function_name,
const char *unique,
const void *workload,
size_t workload_size,
gearman_return_t *ret_ptr),
INTERNAL_FUNCTION_PARAMETERS) {
zval *zworkload;
zval *zdata = NULL;
gearman_task_obj *task;
char *unique;
char *function_name;
size_t unique_len = 0;
size_t function_name_len = 0;
gearman_client_obj *obj;
zval *zobj;
// TODO - the documentation on php.net differs from this
// As found, this doesn't allow for user to pass in context.
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Osz|zs", &zobj, gearman_client_ce,
&function_name, &function_name_len,
&zworkload,
&zdata,
&unique, &unique_len
) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
if (unique_len == 0) {
unique = NULL;
}
if (Z_TYPE_P(zworkload) != IS_STRING) {
convert_to_string(zworkload);
}
/* get a task object, and prepare it for return */
if (object_init_ex(return_value, gearman_task_ce) != SUCCESS) {
php_error_docref(NULL, E_WARNING, "GearmanTask Object creation failure.");
RETURN_FALSE;
}
task = Z_GEARMAN_TASK_P(return_value);
if (zdata) {
ZVAL_COPY(&task->zdata, zdata);
}
ZVAL_COPY(&task->zworkload, zworkload);
/* need to store a ref to the client for later access to cb's */
ZVAL_COPY(&task->zclient, zobj);
/* add the task */
task->task = (*add_task_func)(
&(obj->client),
task->task,
(void *)task,
function_name,
unique,
Z_STRVAL_P(zworkload),
(size_t) Z_STRLEN_P(zworkload),
&obj->ret
);
if (obj->ret != GEARMAN_SUCCESS) {
php_error_docref(NULL, E_WARNING, "%s",
gearman_client_error(&(obj->client)));
RETURN_FALSE;
}
task->flags |= GEARMAN_TASK_OBJ_CREATED;
task->task_id = ++obj->created_tasks;
// prepend task to list of tasks on client obj
Z_ADDREF_P(return_value);
add_index_zval(&obj->task_list, task->task_id, return_value);
}
/* }}} */
/* {{{ proto false|object GearmanClient::addTask(string function, zval workload [, string unique ])
Add a task to be run in parallel. */
PHP_FUNCTION(gearman_client_add_task) {
gearman_client_add_task_handler(gearman_client_add_task, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
/* {{{ proto false|object GearmanClient::addTaskHigh(string function, zval workload [, string unique ])
Add a high priority task to be run in parallel. */
PHP_FUNCTION(gearman_client_add_task_high) {
gearman_client_add_task_handler(gearman_client_add_task_high, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
/* {{{ proto false|object GearmanClient::addTaskLow(string function, zval workload [, string unique ])
Add a low priority task to be run in parallel. */
PHP_FUNCTION(gearman_client_add_task_low) {
gearman_client_add_task_handler(gearman_client_add_task_low, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
/* {{{ proto false|object GearmanClient::addTaskBackground(string function, zval workload [, string unique ])
Add a background task to be run in parallel. */
PHP_FUNCTION(gearman_client_add_task_background) {
gearman_client_add_task_handler(gearman_client_add_task_background, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
/* {{{ proto false|object GearmanClient::addTaskHighBackground(string function, zval workload [, string unique ])
Add a high priority background task to be run in parallel. */
PHP_FUNCTION(gearman_client_add_task_high_background) {
gearman_client_add_task_handler(gearman_client_add_task_high_background, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
/* {{{ proto false|object GearmanClient::addTaskLowBackground(string function, zval workload [, string unique ])
Add a low priority background task to be run in parallel. */
PHP_FUNCTION(gearman_client_add_task_low_background) {
gearman_client_add_task_handler(gearman_client_add_task_low_background, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
/* {{{ proto bool gearman_client_run_tasks(object client)
Run tasks that have been added in parallel */
PHP_FUNCTION(gearman_client_run_tasks) {
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &zobj, gearman_client_ce) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
obj->ret = gearman_client_run_tasks(&(obj->client));
if (! PHP_GEARMAN_CLIENT_RET_OK(obj->ret)) {
php_error_docref(NULL, E_WARNING, "%s",
gearman_client_error(&(obj->client)));
RETURN_FALSE;
}
RETURN_TRUE;
}
/* }}} */
/* this function is used to request status information from the gearmand
* server. it will then call your predefined status callback, passing
* zdata/context to it */
/* {{{ proto false|object gearman_client_add_task_status(object client, string job_handle [, zval data])
Add task to get the status for a backgound task in parallel. */
PHP_FUNCTION(gearman_client_add_task_status) {
zval *zdata = NULL;
char *job_handle;
size_t job_handle_len = 0;
gearman_client_obj *obj;
zval *zobj;
gearman_task_obj *task;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os|z", &zobj, gearman_client_ce,
&job_handle, &job_handle_len,
&zdata
) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
/* get a task object, and prepare it for return */
if (object_init_ex(return_value, gearman_task_ce) != SUCCESS) {
php_error_docref(NULL, E_WARNING, "GearmanTask Object creation failure.");
RETURN_FALSE;
}
task = Z_GEARMAN_TASK_P(return_value);
if (zdata) {
ZVAL_COPY(&task->zdata, zdata);
}
/* need to store a ref to the client for later access to cb's */
ZVAL_COPY(&task->zclient, zobj);
/* add the task */
task->task = gearman_client_add_task_status(&(obj->client),
task->task,
(void *)task,
job_handle,
&obj->ret
);
if (obj->ret != GEARMAN_SUCCESS) {
php_error_docref(NULL, E_WARNING, "%s",
gearman_client_error(&(obj->client)));
RETURN_FALSE;
}
task->flags |= GEARMAN_TASK_OBJ_CREATED;
// prepend task to list of tasks on client obj
Z_ADDREF_P(return_value);
add_next_index_zval(&obj->task_list, return_value);
}
/* }}} */
/* {{{ proto bool GearmanClient::setWorkloadCallback(callback function)
Callback function when workload data needs to be sent for a task. */
PHP_FUNCTION(gearman_client_set_workload_callback) {
zval *zworkload_fn;
zend_string *callable = NULL;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oz", &zobj, gearman_client_ce,
&zworkload_fn
) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
/* check that the function is callable */
if (! zend_is_callable(zworkload_fn, 0, &callable)) {
php_error_docref(NULL, E_WARNING, "function %s is not callable", callable->val);
zend_string_release(callable);
RETURN_FALSE;
}
zend_string_release(callable);
/* Defining callback again? Clean up old one first */
if (!Z_ISUNDEF(obj->zworkload_fn)) {
zval_ptr_dtor_nogc(&obj->zworkload_fn);
}
/* store the cb in client object */
ZVAL_COPY(&obj->zworkload_fn, zworkload_fn);
/* set the callback for php */
gearman_client_set_workload_fn(&(obj->client), _php_task_workload_fn);
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool GearmanClient::setCreatedCallback(callback function)
Callback function when workload data needs to be sent for a task. */
PHP_FUNCTION(gearman_client_set_created_callback) {
zval *zcreated_fn;
zend_string *callable = NULL;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oz", &zobj, gearman_client_ce,
&zcreated_fn
) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
/* check that the function is callable */
if (! zend_is_callable(zcreated_fn, 0, &callable)) {
php_error_docref(NULL, E_WARNING, "function %s is not callable", callable->val);
zend_string_release(callable);
RETURN_FALSE;
}
zend_string_release(callable);
/* Defining callback again? Clean up old one first */
if (!Z_ISUNDEF(obj->zcreated_fn)) {
zval_ptr_dtor_nogc(&obj->zcreated_fn);
}
/* store the cb in client object */
ZVAL_COPY(&obj->zcreated_fn, zcreated_fn);
/* set the callback for php */
gearman_client_set_created_fn(&(obj->client), _php_task_created_fn);
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool GearmanClient::setDataCallback(callback function)
Callback function when there is a data packet for a task. */
PHP_FUNCTION(gearman_client_set_data_callback) {
zval *zdata_fn;
zend_string *callable = NULL;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oz", &zobj, gearman_client_ce,
&zdata_fn
) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
/* check that the function is callable */
if (! zend_is_callable(zdata_fn, 0, &callable)) {
php_error_docref(NULL, E_WARNING, "function %s is not callable", callable->val);
zend_string_release(callable);
RETURN_FALSE;
}
zend_string_release(callable);
/* Defining callback again? Clean up old one first */
if (!Z_ISUNDEF(obj->zdata_fn)) {
zval_ptr_dtor_nogc(&obj->zdata_fn);
}
/* store the cb in client object */
ZVAL_COPY(&obj->zdata_fn, zdata_fn);
/* set the callback for php */
gearman_client_set_data_fn(&(obj->client), _php_task_data_fn);
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool GearmanClient::setWarningCallback(callback function)
Callback function when there is a warning packet for a task. */
PHP_FUNCTION(gearman_client_set_warning_callback) {
zval *zwarning_fn;
zend_string *callable = NULL;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oz", &zobj, gearman_client_ce,
&zwarning_fn
) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
/* check that the function is callable */
if (! zend_is_callable(zwarning_fn, 0, &callable)) {
php_error_docref(NULL, E_WARNING, "function %s is not callable", callable->val);
zend_string_release(callable);
RETURN_FALSE;
}
zend_string_release(callable);
/* Defining callback again? Clean up old one first */
if (!Z_ISUNDEF(obj->zwarning_fn)) {
zval_ptr_dtor_nogc(&obj->zwarning_fn);
}
/* store the cb in client object */
ZVAL_COPY(&obj->zwarning_fn, zwarning_fn);
/* set the callback for php */
gearman_client_set_warning_fn(&(obj->client), _php_task_warning_fn);
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool GearmanClient::setStatusCallback(callback function)
Callback function when there is a status packet for a task. */
PHP_FUNCTION(gearman_client_set_status_callback) {
zval *zstatus_fn;
zend_string *callable = NULL;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oz", &zobj, gearman_client_ce,
&zstatus_fn
) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
/* check that the function is callable */
if (!zend_is_callable(zstatus_fn, 0, &callable)) {
php_error_docref(NULL, E_WARNING, "function %s is not callable", callable->val);
zend_string_release(callable);
RETURN_FALSE;
}
zend_string_release(callable);
/* Defining callback again? Clean up old one first */
if (!Z_ISUNDEF(obj->zstatus_fn)) {
zval_ptr_dtor_nogc(&obj->zstatus_fn);
}
/* store the cb in client object */
ZVAL_COPY(&obj->zstatus_fn, zstatus_fn);
/* set the callback for php */
gearman_client_set_status_fn(&(obj->client), _php_task_status_fn);
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool GearmanClient::setCompleteCallback(callback function)
Callback function when there is a status packet for a task. */
PHP_FUNCTION(gearman_client_set_complete_callback) {
zval *zcomplete_fn;
zend_string *callable = NULL;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oz", &zobj, gearman_client_ce,
&zcomplete_fn
) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
/* check that the function is callable */
if (! zend_is_callable(zcomplete_fn, 0, &callable)) {
php_error_docref(NULL, E_WARNING, "function %s is not callable", callable->val);
zend_string_release(callable);
RETURN_FALSE;
}
zend_string_release(callable);
/* Defining callback again? Clean up old one first */
if (!Z_ISUNDEF(obj->zcomplete_fn)) {
zval_ptr_dtor_nogc(&obj->zcomplete_fn);
}
/* store the cb in client object */
ZVAL_COPY(&obj->zcomplete_fn, zcomplete_fn);
/* set the callback for php */
gearman_client_set_complete_fn(&(obj->client), _php_task_complete_fn);
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool GearmanClient::setExceptionCallback(callback function)
Callback function when there is a exception packet for a task. */
PHP_FUNCTION(gearman_client_set_exception_callback) {
zval *zexception_fn;
zend_string *callable = NULL;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oz", &zobj, gearman_client_ce,
&zexception_fn
) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
if (!gearman_client_set_server_option(&(obj->client), "exceptions", (sizeof("exceptions") - 1))) {
GEARMAN_EXCEPTION("Failed to set exception option", 0);
}
/* check that the function is callable */
if (! zend_is_callable(zexception_fn, 0, &callable)) {
php_error_docref(NULL, E_WARNING, "function %s is not callable", callable->val);
zend_string_release(callable);
RETURN_FALSE;
}
zend_string_release(callable);
/* Defining callback again? Clean up old one first */
if (!Z_ISUNDEF(obj->zexception_fn)) {
zval_ptr_dtor_nogc(&obj->zexception_fn);
}
/* store the cb in client object */
ZVAL_COPY(&obj->zexception_fn, zexception_fn);
/* set the callback for php */
gearman_client_set_exception_fn(&(obj->client), _php_task_exception_fn);
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool GearmanClient::setFailCallback(callback function)
Callback function when there is a fail packet for a task. */
PHP_FUNCTION(gearman_client_set_fail_callback) {
zval *zfail_fn;
zend_string *callable = NULL;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oz", &zobj, gearman_client_ce,
&zfail_fn
) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
/* check that the function is callable */
if (! zend_is_callable(zfail_fn, 0, &callable)) {
php_error_docref(NULL, E_WARNING, "function %s is not callable", callable->val);
zend_string_release(callable);
RETURN_FALSE;
}
zend_string_release(callable);
/* Defining callback again? Clean up old one first */
if (!Z_ISUNDEF(obj->zfail_fn)) {
zval_ptr_dtor_nogc(&obj->zfail_fn);
}
/* store the cb in client object */
ZVAL_COPY(&obj->zfail_fn, zfail_fn);
/* set the callback for php */
gearman_client_set_fail_fn(&(obj->client), _php_task_fail_fn);
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool GearmanClient::clearCallbacks()
Clear all task callback functions. */
PHP_FUNCTION(gearman_client_clear_callbacks) {
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &zobj, gearman_client_ce) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
gearman_client_clear_fn(&obj->client);
zval_ptr_dtor_nogc(&obj->zworkload_fn);
ZVAL_UNDEF(&obj->zworkload_fn);
zval_ptr_dtor_nogc(&obj->zcreated_fn);
ZVAL_UNDEF(&obj->zcreated_fn);
zval_ptr_dtor_nogc(&obj->zdata_fn);
ZVAL_UNDEF(&obj->zdata_fn);
zval_ptr_dtor_nogc(&obj->zwarning_fn);
ZVAL_UNDEF(&obj->zwarning_fn);
zval_ptr_dtor_nogc(&obj->zstatus_fn);
ZVAL_UNDEF(&obj->zstatus_fn);
zval_ptr_dtor_nogc(&obj->zcomplete_fn);
ZVAL_UNDEF(&obj->zcomplete_fn);
zval_ptr_dtor_nogc(&obj->zexception_fn);
ZVAL_UNDEF(&obj->zexception_fn);
zval_ptr_dtor_nogc(&obj->zfail_fn);
ZVAL_UNDEF(&obj->zfail_fn);
RETURN_TRUE;
}
/* }}} */
/* {{{ proto string GearmanClient::context()
Get the application data */
PHP_FUNCTION(gearman_client_context) {
const char *data;
int length = 0;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &zobj, gearman_client_ce) == FAILURE) {
RETURN_EMPTY_STRING();
}
obj = Z_GEARMAN_CLIENT_P(zobj);
data = gearman_client_context(&(obj->client));
if (data) {
length = strlen(data);
}
RETURN_STRINGL(data, length);
}
/* }}} */
/* {{{ proto bool GearmanClient::setContext(string data)
Set the application data */
PHP_FUNCTION(gearman_client_set_context) {
char *data, *old_context;
size_t data_len = 0;
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &zobj, gearman_client_ce, &data, &data_len) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
old_context = gearman_client_context(&(obj->client));
if (old_context) {
efree(old_context);
}
gearman_client_set_context(&(obj->client), (void*) estrndup(data, data_len));
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool GearmanClient::enableExceptionHandler()
Enable exception handling to be used by exception callback function
GearmanClient::enableExceptionHandler */
PHP_FUNCTION(gearman_client_enable_exception_handler) {
gearman_client_obj *obj;
zval *zobj;
if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &zobj, gearman_client_ce) == FAILURE) {
RETURN_FALSE;
}
obj = Z_GEARMAN_CLIENT_P(zobj);
if (!gearman_client_set_server_option(&(obj->client), "exceptions", (sizeof("exceptions") - 1))) {
GEARMAN_EXCEPTION("Failed to set exception option", 0);
}
RETURN_TRUE;
}
/* }}} */