Skip to content

Commit f0d8db9

Browse files
committed
Merge branch 'thread'
some libuv functions requires threading feature. you have to re-compile your PHPwith --enable-maintainer-zts if you want to use threading functions. NOTE: thread feature runs new php vm another thread. current implementation doesn't copy current executor globals. so you have to load bootstrap file (like composer's autoloader) manually.
2 parents 111d9b2 + edf8f7f commit f0d8db9

File tree

5 files changed

+148
-25
lines changed

5 files changed

+148
-25
lines changed

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2129,9 +2129,12 @@ send async callback immidiately
21292129
##### *Example*
21302130

21312131

2132-
21332132
### void uv_queue_work(resource $loop, callable $callback, callable $after_callback)
21342133

2134+
##### *Description*
2135+
2136+
execute callbacks in another thread (requires Thread Safe enabled PHP)
2137+
21352138

21362139
### resource uv_fs_open(resource $loop, string $path, long $flag, long $mode, callable $callback)
21372140

@@ -2835,8 +2838,7 @@ $poll = uv_poll_init(uv_default_loop(), $fd);
28352838
##### *Note*
28362839

28372840
* if you want to use a socket. please use uv_poll_init_socket instead of this. Windows can't handle socket with this function.
2838-
2839-
2841+
* some platform doesn't support file descriptor on these method.
28402842

28412843
### uv uv_poll_init_socket([resource $uv_loop], zval fd)
28422844

php_uv.c

Lines changed: 88 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "php_uv.h"
2121
#include "ext/standard/info.h"
2222

23+
2324
#ifndef PHP_UV_DEBUG
2425
#define PHP_UV_DEBUG 0
2526
#endif
@@ -168,6 +169,16 @@ zend_fcall_info empty_fcall_info = { 0, NULL, NULL, NULL, NULL, 0, NULL, NULL, 0
168169
#define PHP_UV_DEBUG_RESOURCE_REFCOUNT(name, resource_id)
169170
#endif
170171

172+
#ifdef ZTS
173+
#define UV_FETCH_ALL(ls, id, type) ((type) (*((void ***) ls))[TSRM_UNSHUFFLE_RSRC_ID(id)])
174+
#define UV_FETCH_CTX(ls, id, type, element) (((type) (*((void ***) ls))[TSRM_UNSHUFFLE_RSRC_ID(id)])->element)
175+
#define UV_CG(ls, v) UV_FETCH_CTX(ls, compiler_globals_id, zend_compiler_globals*, v)
176+
#define UV_CG_ALL(ls) UV_FETCH_ALL(ls, compiler_globals_id, zend_compiler_globals*)
177+
#define UV_EG(ls, v) UV_FETCH_CTX(ls, executor_globals_id, zend_executor_globals*, v)
178+
#define UV_SG(ls, v) UV_FETCH_CTX(ls, sapi_globals_id, sapi_globals_struct*, v)
179+
#define UV_EG_ALL(ls) UV_FETCH_ALL(ls, executor_globals_id, zend_executor_globals*)
180+
#endif
181+
171182

172183
extern void php_uv_init(TSRMLS_D);
173184

@@ -1197,20 +1208,80 @@ static int php_uv_do_callback(zval **retval_ptr, zval *callback, zval ***params,
11971208
return error;
11981209
}
11991210

1200-
12011211
static int php_uv_do_callback2(zval **retval_ptr, php_uv_t *uv, zval ***params, int param_count, enum php_uv_callback_type type TSRMLS_DC)
12021212
{
12031213
int error = 0;
1204-
1214+
1215+
if (ZEND_FCI_INITIALIZED(uv->callback[type]->fci)) {
1216+
uv->callback[type]->fci.params = params;
1217+
uv->callback[type]->fci.retval_ptr_ptr = retval_ptr;
1218+
uv->callback[type]->fci.param_count = param_count;
1219+
uv->callback[type]->fci.no_separation = 1;
1220+
1221+
if (zend_call_function(&uv->callback[type]->fci, &uv->callback[type]->fcc TSRMLS_CC) != SUCCESS) {
1222+
error = -1;
1223+
}
1224+
} else {
1225+
error = -2;
1226+
}
1227+
1228+
//zend_fcall_info_args_clear(&uv->callback[type]->fci, 0);
1229+
1230+
return error;
1231+
}
1232+
1233+
#ifdef ZTS
1234+
static int php_uv_do_callback3(zval **retval_ptr, php_uv_t *uv, zval ***params, int param_count, enum php_uv_callback_type type)
1235+
{
1236+
int error = 0;
1237+
zend_executor_globals *ZEG = NULL;
1238+
void ***tsrm_ls, ***old;
1239+
12051240
if (ZEND_FCI_INITIALIZED(uv->callback[type]->fci)) {
1241+
tsrm_ls = tsrm_new_interpreter_context();
1242+
old = tsrm_set_interpreter_context(tsrm_ls);
1243+
1244+
PG(expose_php) = 0;
1245+
PG(auto_globals_jit) = 0;
1246+
1247+
php_request_startup(TSRMLS_C);
1248+
ZEG = UV_EG_ALL(TSRMLS_C);
1249+
ZEG->in_execution = 1;
1250+
ZEG->current_execute_data=NULL;
1251+
ZEG->current_module=phpext_uv_ptr;
1252+
ZEG->This = NULL;
1253+
12061254
uv->callback[type]->fci.params = params;
12071255
uv->callback[type]->fci.retval_ptr_ptr = retval_ptr;
12081256
uv->callback[type]->fci.param_count = param_count;
12091257
uv->callback[type]->fci.no_separation = 1;
1258+
uv->callback[type]->fci.object_ptr = ZEG->This;
1259+
uv->callback[type]->fcc.initialized = 1;
1260+
1261+
uv->callback[type]->fcc.calling_scope = NULL;
1262+
uv->callback[type]->fcc.called_scope = NULL;
1263+
uv->callback[type]->fcc.object_ptr = ZEG->This;
12101264

12111265
if (zend_call_function(&uv->callback[type]->fci, &uv->callback[type]->fcc TSRMLS_CC) != SUCCESS) {
12121266
error = -1;
12131267
}
1268+
1269+
{
1270+
zend_op_array *ops = &uv->callback[type]->fcc.function_handler->op_array;
1271+
if (ops) {
1272+
if (ops->run_time_cache) {
1273+
efree(ops->run_time_cache);
1274+
ops->run_time_cache = NULL;
1275+
}
1276+
}
1277+
}
1278+
if (retval_ptr != NULL) {
1279+
zval_ptr_dtor(retval_ptr);
1280+
}
1281+
1282+
php_request_shutdown(TSRMLS_C);
1283+
tsrm_set_interpreter_context(old);
1284+
tsrm_free_interpreter_context(tsrm_ls);
12141285
} else {
12151286
error = -2;
12161287
}
@@ -1219,6 +1290,11 @@ static int php_uv_do_callback2(zval **retval_ptr, php_uv_t *uv, zval ***params,
12191290

12201291
return error;
12211292
}
1293+
#else
1294+
static int php_uv_do_callback3(zval **retval_ptr, php_uv_t *uv, zval ***params, int param_count, enum php_uv_callback_type type)
1295+
{
1296+
}
1297+
#endif
12221298

12231299
static void php_uv_tcp_connect_cb(uv_connect_t *req, int status)
12241300
{
@@ -1628,7 +1704,7 @@ static void php_uv_async_cb(uv_async_t* handle, int status)
16281704

16291705
params[0] = &resource;
16301706
params[1] = &zstat;
1631-
1707+
16321708
php_uv_do_callback2(&retval_ptr, uv, params, 2, PHP_UV_ASYNC_CB TSRMLS_CC);
16331709

16341710
zval_ptr_dtor(&resource);
@@ -1650,11 +1726,8 @@ static void php_uv_work_cb(uv_work_t* req)
16501726

16511727
PHP_UV_DEBUG_PRINT("work_cb\n");
16521728

1653-
php_uv_do_callback2(&retval_ptr, uv, NULL, 0, PHP_UV_WORK_CB TSRMLS_CC);
1729+
php_uv_do_callback3(&retval_ptr, uv, NULL, 0, PHP_UV_WORK_CB);
16541730

1655-
if (retval_ptr != NULL) {
1656-
zval_ptr_dtor(&retval_ptr);
1657-
}
16581731
PHP_UV_DEBUG_RESOURCE_REFCOUNT(uv_work_cb, uv->resource_id);
16591732
}
16601733

@@ -1664,12 +1737,13 @@ static void php_uv_after_work_cb(uv_work_t* req, int status)
16641737
php_uv_t *uv = (php_uv_t*)req->data;
16651738
TSRMLS_FETCH_FROM_CTX(uv != NULL ? uv->thread_ctx : NULL);
16661739

1740+
uv = (php_uv_t*)req->data;
1741+
16671742
PHP_UV_DEBUG_PRINT("after_work_cb\n");
16681743

1669-
php_uv_do_callback2(&retval_ptr, uv, NULL, 0, PHP_UV_AFTER_WORK_CB TSRMLS_CC);
1744+
php_uv_do_callback3(&retval_ptr, uv, NULL, 0, PHP_UV_AFTER_WORK_CB);
16701745

1671-
zval_ptr_dtor(&retval_ptr);
1672-
PHP_UV_DEBUG_RESOURCE_REFCOUNT(uv_after_work_cb, uv->resource_id);
1746+
PHP_UV_DEBUG_RESOURCE_REFCOUNT(uv_work_cb, uv->resource_id);
16731747
}
16741748

16751749
static void php_uv_fs_cb(uv_fs_t* req)
@@ -5537,6 +5611,7 @@ PHP_FUNCTION(uv_async_send)
55375611
*/
55385612
PHP_FUNCTION(uv_queue_work)
55395613
{
5614+
#ifdef ZTS
55405615
int r;
55415616
zval *zloop = NULL;
55425617
uv_loop_t *loop;
@@ -5564,6 +5639,9 @@ PHP_FUNCTION(uv_queue_work)
55645639
php_error_docref(NULL TSRMLS_CC, E_ERROR, "uv_queue_work failed");
55655640
return;
55665641
}
5642+
#else
5643+
php_error_docref(NULL TSRMLS_CC, E_ERROR, "uv_queue_work doesn't support this PHP. please rebuild with --enable-maintainer-zts");
5644+
#endif
55675645
}
55685646
/* }}} */
55695647

php_uv.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,18 @@
4040
#include "ext/sockets/php_sockets.h"
4141
#endif
4242

43-
#include "zend_interfaces.h"
43+
#include <Zend/zend.h>
44+
#include <Zend/zend_compile.h>
45+
#include <Zend/zend_exceptions.h>
46+
#include <Zend/zend_extensions.h>
47+
#include <Zend/zend_globals.h>
48+
#include <Zend/zend_hash.h>
49+
#include <Zend/zend_ts_hash.h>
50+
#include <Zend/zend_interfaces.h>
51+
#include <Zend/zend_list.h>
52+
#include <Zend/zend_object_handlers.h>
53+
#include <Zend/zend_variables.h>
54+
#include <Zend/zend_vm.h>
4455

4556
/* Define the entry point symbol
4657
* Zend will use when loading this module

tests/330-poll.phpt

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,45 @@
11
--TEST--
2-
Check for fs read and close
2+
Check for poll read and close
33
--FILE--
44
<?php
5-
$fd = fopen("testfile","w+");
5+
$socket = stream_socket_server("tcp://0.0.0.0:9999", $errno, $errstr);
6+
stream_set_blocking($socket, 0);
7+
8+
$poll = uv_poll_init(uv_default_loop(), $socket);
9+
uv_poll_start($poll, UV::READABLE, function($poll, $stat, $ev, $socket){
10+
$conn = stream_socket_accept($socket);
11+
12+
uv_poll_stop($poll);
13+
$pp = uv_poll_init(uv_default_loop(), $conn);
14+
uv_poll_start($pp, UV::WRITABLE, function($poll, $stat, $ev, $conn) use (&$pp){
615

7-
$poll = uv_poll_init(uv_default_loop(), $fd);
8-
uv_poll_start($poll, UV::WRITABLE, function($poll, $stat, $ev, $conn){
9-
fwrite($conn, "Hello");
10-
fclose($conn);
11-
$data = file_get_contents("testfile");
12-
if ($data == "Hello") {
13-
echo "OK";
14-
}
15-
unlink("testfile");
1616
uv_poll_stop($poll);
17+
uv_fs_write(uv_default_loop(), $conn, "OK", -1, function($conn, $nwrite){
18+
fclose($conn);
19+
});
20+
});
1721
});
1822

23+
$address = uv_ip4_addr("0.0.0.0","9999");
24+
$tcp = uv_tcp_init();
25+
uv_tcp_connect($tcp, $address, function($client, $stat){
26+
$request = <<<EOF
27+
HELO
28+
EOF;
29+
uv_write($client,$request,function($client, $stat){
30+
if ($stat == 0) {
31+
uv_read_start($client,function($client, $nread, $buffer){
32+
echo "$buffer\n";
33+
//var_dump($buffer);
34+
uv_close($client);
35+
});
36+
} else {
37+
uv_close($client);
38+
}
39+
});
40+
});
41+
42+
1943
uv_run();
2044
--EXPECT--
2145
OK

tests/800-uv_queue_work.phpt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
--TEST--
22
Check for uv_queue_work
3+
--SKIPIF--
4+
<?php
5+
ob_start();
6+
phpinfo();
7+
$data = ob_get_clean();
8+
if (!preg_match("/Thread Safety.+?enabled/", $data)) {
9+
echo "skip";
10+
}
311
--FILE--
412
<?php
513
$loop = uv_default_loop();

0 commit comments

Comments
 (0)