Skip to content

Commit 5175b3f

Browse files
committed
Refactor register_tick_function mechanism
1 parent c757c61 commit 5175b3f

File tree

3 files changed

+42
-74
lines changed

3 files changed

+42
-74
lines changed

ext/standard/basic_functions.c

Lines changed: 27 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,9 @@ PHPAPI php_basic_globals basic_globals;
110110
#include "basic_functions_arginfo.h"
111111

112112
typedef struct _user_tick_function_entry {
113-
zval *arguments;
114-
int arg_count;
115-
int calling;
113+
zend_fcall_info fci;
114+
zend_fcall_info_cache fci_cache;
115+
bool calling;
116116
} user_tick_function_entry;
117117

118118
/* some prototypes for local functions */
@@ -1678,12 +1678,9 @@ void user_shutdown_function_dtor(zval *zv) /* {{{ */
16781678

16791679
void user_tick_function_dtor(user_tick_function_entry *tick_function_entry) /* {{{ */
16801680
{
1681-
int i;
1681+
zval_ptr_dtor(&tick_function_entry->fci.function_name);
16821682

1683-
for (i = 0; i < tick_function_entry->arg_count; i++) {
1684-
zval_ptr_dtor(&tick_function_entry->arguments[i]);
1685-
}
1686-
efree(tick_function_entry->arguments);
1683+
efree(tick_function_entry);
16871684
}
16881685
/* }}} */
16891686

@@ -1713,27 +1710,12 @@ static int user_shutdown_function_call(zval *zv) /* {{{ */
17131710

17141711
static void user_tick_function_call(user_tick_function_entry *tick_fe) /* {{{ */
17151712
{
1716-
zval retval;
1717-
zval *function = &tick_fe->arguments[0];
1718-
1719-
/* Prevent reentrant calls to the same user ticks function */
1720-
if (! tick_fe->calling) {
1721-
tick_fe->calling = 1;
1722-
1723-
if (call_user_function(NULL, NULL,
1724-
function,
1725-
&retval,
1726-
tick_fe->arg_count - 1,
1727-
tick_fe->arguments + 1
1728-
) == SUCCESS) {
1729-
zval_ptr_dtor(&retval);
1730-
} else {
1731-
zend_string *function_name = zend_get_callable_name(function);
1732-
zend_throw_error(NULL, "Registered tick function %s() cannot be called, function does not exist", ZSTR_VAL(function_name));
1733-
zend_string_release(function_name);
1734-
}
1735-
1736-
tick_fe->calling = 0;
1713+
/* Prevent re-entrant calls to the same user ticks function */
1714+
if (!tick_fe->calling) {
1715+
tick_fe->calling = true;
1716+
zend_fcall_info_call(&tick_fe->fci, &tick_fe->fci_cache, tick_fe->fci.retval, NULL);
1717+
zend_release_fcall_info_cache(&tick_fe->fci_cache);
1718+
tick_fe->calling = false;
17371719
}
17381720
}
17391721
/* }}} */
@@ -1746,8 +1728,8 @@ static void run_user_tick_functions(int tick_count, void *arg) /* {{{ */
17461728

17471729
static int user_tick_function_compare(user_tick_function_entry * tick_fe1, user_tick_function_entry * tick_fe2) /* {{{ */
17481730
{
1749-
zval *func1 = &tick_fe1->arguments[0];
1750-
zval *func2 = &tick_fe2->arguments[0];
1731+
zval *func1 = &tick_fe1->fci.function_name;
1732+
zval *func2 = &tick_fe2->fci.function_name;
17511733
int ret;
17521734

17531735
if (Z_TYPE_P(func1) == IS_STRING && Z_TYPE_P(func2) == IS_STRING) {
@@ -2386,36 +2368,15 @@ PHP_FUNCTION(getprotobynumber)
23862368
/* {{{ Registers a tick callback function */
23872369
PHP_FUNCTION(register_tick_function)
23882370
{
2389-
user_tick_function_entry tick_fe;
2390-
int i;
2391-
zend_string *function_name = NULL;
2392-
2393-
tick_fe.calling = 0;
2394-
tick_fe.arg_count = ZEND_NUM_ARGS();
2395-
2396-
if (tick_fe.arg_count < 1) {
2397-
WRONG_PARAM_COUNT;
2398-
}
2399-
2400-
tick_fe.arguments = (zval *) safe_emalloc(sizeof(zval), tick_fe.arg_count, 0);
2371+
user_tick_function_entry *tick_fe = emalloc(sizeof(user_tick_function_entry));
24012372

2402-
if (zend_get_parameters_array(ZEND_NUM_ARGS(), tick_fe.arg_count, tick_fe.arguments) == FAILURE) {
2403-
efree(tick_fe.arguments);
2404-
RETURN_FALSE;
2405-
}
2406-
2407-
if (!zend_is_callable(&tick_fe.arguments[0], 0, &function_name)) {
2408-
efree(tick_fe.arguments);
2409-
zend_argument_type_error(1, "must be a valid tick callback, \"%s\" given", ZSTR_VAL(function_name));
2410-
zend_string_release_ex(function_name, 0);
2373+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "f*", &tick_fe->fci, &tick_fe->fci_cache,
2374+
&tick_fe->fci.params, &tick_fe->fci.param_count) == FAILURE) {
2375+
efree(tick_fe);
24112376
RETURN_THROWS();
2412-
} else if (function_name) {
2413-
zend_string_release_ex(function_name, 0);
24142377
}
24152378

2416-
if (Z_TYPE(tick_fe.arguments[0]) != IS_ARRAY && Z_TYPE(tick_fe.arguments[0]) != IS_OBJECT) {
2417-
convert_to_string(&tick_fe.arguments[0]);
2418-
}
2379+
Z_TRY_ADDREF(tick_fe->fci.function_name);
24192380

24202381
if (!BG(user_tick_functions)) {
24212382
BG(user_tick_functions) = (zend_llist *) emalloc(sizeof(zend_llist));
@@ -2425,11 +2386,8 @@ PHP_FUNCTION(register_tick_function)
24252386
php_add_tick_function(run_user_tick_functions, NULL);
24262387
}
24272388

2428-
for (i = 0; i < tick_fe.arg_count; i++) {
2429-
Z_TRY_ADDREF(tick_fe.arguments[i]);
2430-
}
2431-
2432-
zend_llist_add_element(BG(user_tick_functions), &tick_fe);
2389+
zend_llist_add_element(BG(user_tick_functions), tick_fe);
2390+
efree(tick_fe);
24332391

24342392
RETURN_TRUE;
24352393
}
@@ -2438,23 +2396,19 @@ PHP_FUNCTION(register_tick_function)
24382396
/* {{{ Unregisters a tick callback function */
24392397
PHP_FUNCTION(unregister_tick_function)
24402398
{
2441-
user_tick_function_entry tick_fe;
2442-
zend_fcall_info fci;
2443-
zend_fcall_info_cache fci_cache;
2399+
user_tick_function_entry *tick_fe = emalloc(sizeof(user_tick_function_entry));
24442400

2445-
ZEND_PARSE_PARAMETERS_START(1, 1)
2446-
Z_PARAM_FUNC(fci, fci_cache)
2447-
ZEND_PARSE_PARAMETERS_END();
2401+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "f", &tick_fe->fci, &tick_fe->fci_cache) == FAILURE) {
2402+
efree(tick_fe);
2403+
RETURN_THROWS();
2404+
}
24482405

24492406
if (!BG(user_tick_functions)) {
24502407
return;
24512408
}
24522409

2453-
tick_fe.arguments = (zval *) emalloc(sizeof(zval));
2454-
ZVAL_COPY_VALUE(&tick_fe.arguments[0], &fci.function_name);
2455-
tick_fe.arg_count = 1;
2456-
zend_llist_del_element(BG(user_tick_functions), &tick_fe, (int (*)(void *, void *)) user_tick_function_compare);
2457-
efree(tick_fe.arguments);
2410+
zend_llist_del_element(BG(user_tick_functions), tick_fe, (int (*)(void *, void *)) user_tick_function_compare);
2411+
efree(tick_fe);
24582412
}
24592413
/* }}} */
24602414

ext/standard/tests/general_functions/register_tick_function_error.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ try {
1111
}
1212
?>
1313
--EXPECT--
14-
register_tick_function(): Argument #1 ($callback) must be a valid tick callback, "a" given
14+
register_tick_function(): Argument #1 ($callback) must be a valid callback, function "a" not found or invalid function name
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
unregister_tick_function only accepts a valid callback as parameter
3+
--FILE--
4+
<?php
5+
declare(ticks=1);
6+
7+
try {
8+
unregister_tick_function("a");
9+
} catch (TypeError $exception) {
10+
echo $exception->getMessage() . "\n";
11+
}
12+
?>
13+
--EXPECT--
14+
unregister_tick_function(): Argument #1 ($callback) must be a valid callback, function "a" not found or invalid function name

0 commit comments

Comments
 (0)