amphp / byte-stream

A non-blocking stream abstraction for PHP based on Amp.

Home Page:https://amphp.org/byte-stream

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Consider avoiding stream_socket_shutdown

withinboredom opened this issue · comments

When file descriptors are shared between processes or threads, stream_socket_shutdown will close the file descriptor for ALL threads/processes (took me forever to figure out what was going on) and cause broken pipes.

Unfortunately, this is exactly what it's designed to do. The issue is that PHP doesn't open FDs with the close on exec option, so any child process will inherit the file descriptors. We shutdown the sockets so they don't stay open in case any child process is started while the socket was open.

The issue is that PHP doesn't open FDs with the close on exec option, so any child process will inherit the file descriptors

This is pretty much how things are done in Linux. In fact, after a fork() in C, you usually do something like this and manually close them all yourself; but generally, you don't want to break them in the parent.

Alternatively, call pcntl_unshare(1024) in the child to disassociate the FD table with the parent. Granted, it's PHP so a lot happens between fork and your call to unshare... so YMMV.

Or, if you're lucky enough to be on BSD, there's pcntl_rfork which allows you to fork without FDs being copied.

This should work IMHO, fwiw:

$pid = pcntl_fork();
if($pid === 0) {
  foreach (EventLoop::getIdentifiers() as $identifier) {
    EventLoop::cancel($identifier);
  }
  // clean process?
}

But now if any destructors get called in a child, for any reason (such as when the child dies), the entire program crashes and/or corrupts things in databases (depending on what gets destructed and in what order).

For the record, this was simply resolved by using the ZTS version of PHP.