Uh oh!
There was an error while loading. Please reload this page.
feat: macOS support for Zend Max Execution timers - #13468
Conversation
dunglas
commented
Feb 22, 2024
I tried with an NTS build and it works, so this is ready for review. What I haven't handled yet is hard timeouts (that have never been supported for ZTS builds anyway). |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
| pthread_kill(*tid, ZEND_MAX_EXECUTION_TIMERS_SIGNAL); | ||
| #else | ||
| pid_t *pid = (pid_t *) arg; | ||
| kill(*pid, ZEND_MAX_EXECUTION_TIMERS_SIGNAL); |
There was a problem hiding this comment.
I think this can cause zend_timeout_handler to be executed in parallel to the VM: We have multiple threads due to Dispatch or other libraries starting helper threads, so the signal may be delivered in any of them.
This probably already happens anyway, and zend_timeout_handler is threads safe for the most part (probably not the hard timeout part).
We could call zend_timeout_handler directly here for the same effect.
There was a problem hiding this comment.
I'm trying. The red tests may be related to this.
There was a problem hiding this comment.
This seems to work, but tests are still red.
| dispatch_time(DISPATCH_TIME_NOW, seconds * NSEC_PER_SEC), | ||
| seconds * NSEC_PER_SEC, | ||
| 0 |
There was a problem hiding this comment.
Can we disable recurrence of the timer?
There was a problem hiding this comment.
No, this seems not possible: https://developer.apple.com/documentation/dispatch/1385606-dispatch_source_set_timer
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
devnexen
commented
Feb 23, 2024
Nice work overall ,but I ll have a better look either later today or within this weekend with my sonoma/arm machine. |
| return; | ||
| } | ||
| dispatch_queue_global_t queue = dispatch_get_global_queue(QOS_CLASS_UTILITY, 0); |
There was a problem hiding this comment.
quick question: did you try with using your own queue or at least, does it make any meaningful difference in your opinion e.g.
dispatch_queue_attr_tattr=dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, 0);
dispatch_queue_tqueue=dispatch_queue_create("net.php.zend_max_execution_timer", attr);There was a problem hiding this comment.
According to the docs, this queue looks adapted to our use case, but I'm not a specialist in Mac specifics.
There was a problem hiding this comment.
ACK. Was wondering what is best for, at least, ZTS context.
bukka
commented
Feb 27, 2024
Just an update here that I have been trying to figure out why FPM tests are failing which we were discussing internally. The problem seems to be that curl initialization uses internally through another library (possibly krb5) libdispatch which happens in master process before forking. When the timer is later activated in the child process after fork through I created this simplified program that reproduces the crash: #include<dispatch/dispatch.h>#include<curl/curl.h>#include<stdio.h>#include<stdlib.h>#include<sys/wait.h>#include<unistd.h>#include<signal.h>voidtimer_handler(void*ctx)
{
printf("handle\n");
}
voidtimer_cancel(void*ctx)
{
printf("cancel\n");
}
voidsigchld_handler(intsignum) {
intstatus;
pid_tpid;
while ((pid=waitpid(-1, &status, WNOHANG)) >0) {
if (WIFEXITED(status)) {
printf("Child %d exited with status %d\n", pid, WEXITSTATUS(status));
} elseif (WIFSIGNALED(status)) {
printf("Child %d killed by signal %d\n", pid, WTERMSIG(status));
}
}
}
intmain()
{
// if global curl init in parent, it crashescurl_global_init(CURL_GLOBAL_DEFAULT);
signal(SIGCHLD, sigchld_handler);
intpid=fork();
if (pid==0) {
// if global init in the child, it works// curl_global_init(CURL_GLOBAL_DEFAULT);dispatch_queue_global_tqueue=dispatch_get_global_queue(QOS_CLASS_UTILITY, 0);
dispatch_source_ttimer=dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
if (timer==NULL) {
printf("timer is null\n");
return1;
}
dispatch_source_set_event_handler_f(timer, timer_handler);
dispatch_source_set_cancel_handler_f(timer, timer_cancel);
dispatch_source_set_timer(
timer,
dispatch_time(DISPATCH_TIME_NOW, 2*NSEC_PER_SEC),
2*NSEC_PER_SEC,
0
);
dispatch_activate(timer);
sleep(10);
} elseif (pid>0) {
printf("created child %d\n", pid);
intstatus;
waitpid(pid, &status, 0);
if (WIFEXITED(status)) {
printf("Child exited with status %d\n", WEXITSTATUS(status));
} elseif (WIFSIGNALED(status)) {
printf("Child killed by signal %d\n", WTERMSIG(status));
}
printf("finishing\n");
} else {
printf("fork error\n");
}
return0;
}Not sure what we can do about it. It will require some further investigation. |
bukka
commented
Feb 27, 2024
Just for the record I created the issue for libdispatch. Arnaud found out the exact place in Curl so the reproducer there is a bit updated. I might be looking to possibility of introducing some child hook in FPM which we could potentially use for Curl initialization if we don't find a better solution. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Co-authored-by: Peter Kokot <peterkokot@gmail.com>
Add support for the new timeout system (#10141) on macOS.
Closes#12814.
Relies on Grand Central Dispatch.
I tested the patch with FrankenPHP (ZTS build) and it seems to work.