grpc: PHP gRPC extension breaks fork functions

Please answer these questions before submitting your issue.

What version of gRPC and what language are you using?

Latest on PECL, 1.7.0

What operating system (Linux, Windows, …) and version?

Mac OS X, 10.12.6

What runtime / compiler are you using (e.g. python version or version of gcc)

⇒  cc -v
Apple LLVM version 9.0.0 (clang-900.0.38)
Target: x86_64-apple-darwin16.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

What did you do?

Script to reproduce:

<?php 

$pid = pcntl_fork(); 

if($pid === -1) { 
	echo "error forking\n"; 
} elseif ($pid) { //parent 
	echo "parent: waiting for child...\n"; 
	pcntl_waitpid(0, $status);
	echo "parent: child exited successfully\n"; 
} elseif ($pid === 0) { //child
	echo "child: sleeping for 1s...\n";
	sleep(1); 
	echo "child: exiting...\n";
	exit(0); 
}

echo "parent: finished.\n"; 

What did you expect to see?

This is the script output with gRPC extension disabled:

⇒  php grpc-fork-bug.php
parent: waiting for child...
child: sleeping for 1s...
child: exiting...
parent: child exited successfully
parent: finished.

What did you see instead?

This is the script output with the extension enabled:

⇒  php grpc-fork-bug.php
parent: waiting for child...
child: sleeping for 1s...
child: exiting...
[HANG]

Here’s a syscall trace of the process while its hung:

⇒  sudo dtruss -af php grpc-fork-bug.php
Password:
	PID/THRD  RELATIVE  ELAPSD    CPU SYSCALL(args) 		 = return
parent: waiting for child...
child: sleeping for 1s...
98193/0xff925:      4990      62      1 madvise(0x10895E000, 0x2000, 0x5)		 = 0 0
98193/0xff925:      5430      61      0 madvise(0x1086D7000, 0x7000, 0x5)		 = 0 0
98193/0xff925:      5496      26     23 open("/dev/dtracehelper\0", 0x2, 0x107C69000)		 = 3 0
98193/0xff925:      8026    2766   2528 ioctl(0x3, 0x80086804, 0x7FFF57F956F8)		 = 0 0
98193/0xff925:      8042      17     13 close(0x3)		 = 0 0
98193/0xff925:      8175       3      0 thread_selfid(0x3, 0x80086804, 0x7FFF57F956F8)		 = 1046821 0
98193/0xff925:      8178       4      1 bsdthread_register(0x7FFFD3854080, 0x7FFFD3854070, 0x2000)		 = 1073741919 0
98193/0xff925:      8220       2      0 ulock_wake(0x1, 0x7FFF57F93CFC, 0x0)		 = -1 Err#2
98193/0xff925:      8231       2      0 issetugid(0x1, 0x7FFF57F93CFC, 0x0)		 = 0 0
98193/0xff925:      8377       4      2 mprotect(0x1087C3000, 0x88, 0x1)		 = 0 0
98193/0xff925:      8381       2      1 mprotect(0x108CDA000, 0x1000, 0x0)		 = 0 0
98193/0xff925:      8382       2      0 mprotect(0x108CF0000, 0x1000, 0x0)		 = 0 0
98193/0xff925:      8393       2      0 mprotect(0x108CF1000, 0x1000, 0x0)		 = 0 0
98193/0xff925:      8394       2      0 mprotect(0x108D07000, 0x1000, 0x0)		 = 0 0
98193/0xff925:      8409       2      0 mprotect(0x1089AF000, 0x1000, 0x1)		 = 0 0
98193/0xff925:      8411       3      1 mprotect(0x1087C3000, 0x88, 0x3)		 = 0 0
98193/0xff925:      8423       2      1 mprotect(0x1087C3000, 0x88, 0x1)		 = 0 0
98193/0xff925:      9149      70      0 getpid(0x1087C3000, 0x88, 0x1)		 = 98193 0
98193/0xff925:      9154       4      2 stat64("/AppleInternal/XBS/.isChrooted\0", 0x7FFF57F93BB8, 0x1)		 = -1 Err#2
98193/0xff925:      9157       2      0 stat64("/AppleInternal\0", 0x7FFF57F93C50, 0x1)		 = -1 Err#2
98193/0xff925:      9240       3      1 csops(0x17F91, 0x7, 0x7FFF57F936E0)		 = -1 Err#22
98193/0xff925:      9265      28     23 sysctl([CTL_KERN, 14, 1, 98193, 0, 0] (4), 0x7FFF57F93838, 0x7FFF57F93830, 0x0, 0x0)		 = 0 0
98193/0xff925:      9280       6      0 ulock_wake(0x1, 0x7FFF57F93C60, 0x0)		 = -1 Err#2
98193/0xff925:      9315       5      2 csops(0x17F91, 0x7, 0x7FFF57F92FC0)		 = -1 Err#22
98193/0xff925:      9465       4      0 getuid(0x17F91, 0x7, 0x7FFF57F92FC0)		 = 0 0
98193/0xff925:      9831       2      0 getuid(0x17F91, 0x7, 0x7FFF57F92FC0)		 = 0 0
98193/0xff925:     10374      25     20 stat64("/System/Library/PrivateFrameworks/Heimdal.framework/Heimdal\0", 0x7FFF57F931E8, 0x7FFF57F92FC0)		 = 0 0
98193/0xff925:     10526     132     16 stat64("/System/Library/Frameworks/GSS.framework/GSS\0", 0x7FFF57F931E8, 0x7FFF57F92FC0)	 = 0 0
98193/0xff925:     10818       4      0 sigaction(0xD, 0x7FFF57F96898, 0x7FFF57F968C0)		 = 0 0
98193/0xff925:     10836       1      0 sigaction(0x1, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10837       1      0 sigaction(0x2, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10837       1      0 sigaction(0x3, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10837       1      0 sigaction(0x4, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10838       1      0 sigaction(0x5, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10838       1      0 sigaction(0x6, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10839       2      0 sigaction(0x7, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10839       1      0 sigaction(0x8, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10840       1      0 sigaction(0xA, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10840       1      0 sigaction(0xB, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10840       1      0 sigaction(0xC, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10841       1      0 sigaction(0xD, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10841       1      0 sigaction(0xE, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10842       1      0 sigaction(0xF, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10842       1      0 sigaction(0x10, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10842       1      0 sigaction(0x12, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10843       1      0 sigaction(0x13, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10843       1      0 sigaction(0x14, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10844       2      0 sigaction(0x15, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10844       2      0 sigaction(0x16, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10845       2      0 sigaction(0x17, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10846       1      0 sigaction(0x18, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10846       1      0 sigaction(0x19, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10846       1      0 sigaction(0x1A, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10847       1      0 sigaction(0x1B, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10847       1      0 sigaction(0x1C, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10847       1      0 sigaction(0x1D, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10848       1      0 sigaction(0x1E, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10848       1      0 sigaction(0x1F, 0x0, 0x7FFF57F968B8)		 = 0 0
98193/0xff925:     10927       9      3 mmap(0x0, 0x200000, 0x3, 0x1002, 0xFFFFFFFF, 0x0)		 = 0x108D08000 0
98193/0xff925:     10934       4      1 munmap(0x108D08000, 0x200000)		 = 0 0
98193/0xff925:     10935       2      0 mmap(0x0, 0x3FF000, 0x3, 0x1002, 0xFFFFFFFF, 0x0)		 = 0x108D08000 0
98193/0xff925:     10937       2      1 munmap(0x108D08000, 0xF8000)		 = 0 0
98193/0xff925:     10938       2      0 munmap(0x109000000, 0x107000)		 = 0 0
98193/0xff925:     10951       7      3 sysctl([CTL_HW, 7, 0, 0, 0, 0] (2), 0x7FFFDC53BE00, 0x7FFF57F96270, 0x0, 0x0)		 = 0 0
98193/0xff925:     10963       9      6 open_nocancel(".\0", 0x0, 0x1)		 = 3 0
98193/0xff925:     10965       3      1 fstat64(0x3, 0x7FFF57F95D00, 0x1)		 = 0 0
98193/0xff925:     10968       4      2 fcntl_nocancel(0x3, 0x32, 0x7FFF57F95F00)		 = 0 0
98193/0xff925:     10973       6      4 close_nocancel(0x3)		 = 0 0
98193/0xff925:     10978       5      3 stat64("/Users/zack.angelo/git/grpc-fork-bug\0", 0x7FFF57F95C70, 0x7FFF57F95F00)		 = 0 0
98193/0xff925:     11142      17     15 open_nocancel("/usr/share/locale/en_US.UTF-8/LC_CTYPE\0", 0x0, 0x5)		 = 3 0
98193/0xff925:     11143       2      0 fcntl_nocancel(0x3, 0x3, 0x0)		 = 0 0
98193/0xff925:     11145       2      0 getrlimit(0x1008, 0x7FFF57F95D38, 0x0)		 = 0 0
98193/0xff925:     11152       4      1 fstat64(0x3, 0x7FFF57F95DF8, 0x0)		 = 0 0
98193/0xff925:     11155       2      0 fstat64(0x3, 0x7FFF57F95BE8, 0x0)		 = 0 0
98193/0xff925:     11157       2      0 lseek(0x3, 0x0, 0x1)		 = 0 0
98193/0xff925:     11158       1      0 lseek(0x3, 0x0, 0x0)		 = 0 0
98193/0xff925:     11167      11      8 read_nocancel(0x3, "RuneMagAUTF-8\0", 0x1000)		 = 4096 0
98193/0xff925:     11177       3      1 read_nocancel(0x3, "\0", 0x1000)		 = 4096 0
98193/0xff925:     11194       3      1 read_nocancel(0x3, "\0", 0x1000)		 = 4096 0
98193/0xff925:     11209       2      1 read_nocancel(0x3, "\0", 0x1000)		 = 4096 0
98193/0xff925:     11225       2      1 read_nocancel(0x3, "\0", 0x1000)		 = 4096 0
98193/0xff925:     11240       2      1 read_nocancel(0x3, "\0", 0x1000)		 = 4096 0
98193/0xff925:     11285      37     36 read_nocancel(0x3, "@\004\031\0", 0xDE80)		 = 56960 0
98193/0xff925:     11299       5      3 close_nocancel(0x3)		 = 0 0
98193/0xff925:     11335      27     25 access("/etc/localtime\0", 0x4, 0xDE80)		 = 0 0
98193/0xff925:     11353      19     17 open_nocancel("/etc/localtime\0", 0x0, 0x0)		 = 3 0
98193/0xff925:     11355       3      1 fstat64(0x3, 0x7FFF57F933E0, 0x0)		 = 0 0
98193/0xff925:     11357       3      1 read_nocancel(0x3, "TZif\0", 0x2A64)		 = 791 0
98193/0xff925:     11358       2      1 close_nocancel(0x3)		 = 0 0
98193/0xff925:     11490       8      5 shm_open(0x7FFFD3847DE7, 0x0, 0x0)		 = 3 0
98193/0xff925:     11495       7      4 mmap(0x0, 0x1000, 0x1, 0x1, 0x3, 0x0)		 = 0x1089B0000 0
98193/0xff925:     11497       3      1 close_nocancel(0x3)		 = 0 0
98193/0xff925:     11569       7      4 lstat64("/Users/zack.angelo/.rvm/gems/ruby-2.2.4/bin/php\0", 0x7FFF57F95990, 0x1)		 = -1 Err#2
98193/0xff925:     11583       9      7 lstat64("/Users/zack.angelo/.rvm/gems/ruby-2.2.4@global/bin/php\0", 0x7FFF57F95990, 0x1)	 = -1 Err#2
98193/0xff925:     11585       3      1 lstat64("/Users/zack.angelo/.rvm/rubies/ruby-2.2.4/bin/php\0", 0x7FFF57F95990, 0x1)		 = -1 Err#2
98193/0xff925:     11589       5      3 lstat64("/Users/zack.angelo/.nvm/versions/node/v4.4.7/bin/php\0", 0x7FFF57F95990, 0x1)		 = -1 Err#2
98193/0xff925:     11592       3      1 lstat64("/Users/zack.angelo/google-cloud-sdk/bin/php\0", 0x7FFF57F95990, 0x1)		 = -1 Err#2
98193/0xff925:     11594       3      1 lstat64("/usr/local/sbin/php\0", 0x7FFF57F95990, 0x1)		 = -1 Err#2
98193/0xff925:     11599       5      4 lstat64("/usr/local/bin/php\0", 0x7FFF57F95990, 0x1)		 = 0 0
98193/0xff925:     11609       3      1 readlink("/usr/local/bin/php\0", 0x7FFF57F95AE0, 0x400)		 = 33 0
98193/0xff925:     11618       6      5 lstat64("/usr/local/bin/../Cellar/php71/7.1.11_22/bin/php\0", 0x7FFF57F95860, 0x400)		 = 0 0
98193/0xff925:     11622       3      1 lstat64("/usr/local/bin/../Cellar/php71/7.1.11_22/bin\0", 0x7FFF57F95730, 0x400)		 = 0 0
98193/0xff925:     11626       3      1 lstat64("/usr/local/bin/../Cellar/php71/7.1.11_22\0", 0x7FFF57F95600, 0x400)		 = 0 0
98193/0xff925:     11628       2      1 lstat64("/usr/local/bin/../Cellar/php71\0", 0x7FFF57F954D0, 0x400)		 = 0 0
98193/0xff925:     11631       2      1 lstat64("/usr/local/bin/../Cellar\0", 0x7FFF57F953A0, 0x400)		 = 0 0
98193/0xff925:     11633       2      1 lstat64("/usr/local/bin\0", 0x7FFF57F95140, 0x400)		 = 0 0
98193/0xff925:     11636       2      1 lstat64("/usr/local\0", 0x7FFF57F95010, 0x400)		 = 0 0
98193/0xff925:     11638       2      1 lstat64("/usr\0", 0x7FFF57F94EE0, 0x400)		 = 0 0
98193/0xff925:     11660      16     14 access("/usr/local/Cellar/php71/7.1.11_22/bin/php\0", 0x1, 0x400)		 = 0 0
98193/0xff925:     11667       3      1 stat64("/usr/local/Cellar/php71/7.1.11_22/bin/php\0", 0x7FFF57F963F0, 0x400)		 = 0 0
98193/0xff925:     11702       5      3 open_nocancel("/usr/local/Cellar/php71/7.1.11_22/bin/php-cli.ini\0", 0x0, 0x1B6)		 = -1 Err#2
98193/0xff925:     11706       5      3 open_nocancel("/usr/local/etc/php/7.1/php-cli.ini\0", 0x0, 0x1B6)		 = -1 Err#2
98193/0xff925:     11709      12      2 open_nocancel("/usr/local/Cellar/php71/7.1.11_22/bin/php.ini\0", 0x0, 0x1B6)		 = -1 Err#2
98193/0xff925:     11714       6      4 open_nocancel("/usr/local/etc/php/7.1/php.ini\0", 0x0, 0x1B6)		 = 3 0
98193/0xff925:     11729       3      1 ioctl(0x3, 0x4004667A, 0x7FFF57F95B3C)		 = -1 Err#25
98193/0xff925:     11729       1      0 ioctl(0x3, 0x40487413, 0x7FFF57F95B40)		 = -1 Err#25
98193/0xff925:     11737       3      1 fstat64(0x3, 0x7FFF57F95BB0, 0x7FFF57F95B40)		 = 0 0
98193/0xff925:     11743       8      5 mmap(0x0, 0x1162B, 0x1, 0x2, 0x3, 0x0)		 = 0x108D08000 0
98193/0xff925:     11748       2      0 lseek(0x3, 0x0, 0x1)		 = 0 0
98193/0xff925:     12086      10      6 munmap(0x108D08000, 0x1162B)		 = 0 0
98193/0xff925:     12097       8      5 close_nocancel(0x3)		 = 0 0
98193/0xff925:     12114      12      9 open_nocancel("/usr/local/etc/php/7.1/conf.d\0", 0x1100004, 0x0)		 = 3 0
98193/0xff925:     12117       5      2 fstatfs64(0x3, 0x7FFF57F953D8, 0x0)		 = 0 0
98193/0xff925:     12140      23     20 getdirentries64(0x3, 0x7F814F002C00, 0x1000)		 = 136 0
98193/0xff925:     12145       6      3 getdirentries64(0x3, 0x7F814F002C00, 0x1000)		 = 0 0
98193/0xff925:     12148       3      1 close_nocancel(0x3)		 = 0 0
98193/0xff925:     12162       6      4 stat64("/usr/local/etc/php/7.1/conf.d/ext-intl.ini\0", 0x7FFF57F95E70, 0x1000)		 = 0 0
98193/0xff925:     12167       5      3 open_nocancel("/usr/local/etc/php/7.1/conf.d/ext-intl.ini\0", 0x0, 0x1B6)		 = 3 0
98193/0xff925:     12169       3      0 ioctl(0x3, 0x4004667A, 0x7FFF57F95B3C)		 = -1 Err#25
98193/0xff925:     12169       1      0 ioctl(0x3, 0x40487413, 0x7FFF57F95B40)		 = -1 Err#25
98193/0xff925:     12171       2      0 fstat64(0x3, 0x7FFF57F95BB0, 0x7FFF57F95B40)		 = 0 0
98193/0xff925:     12176       8      4 mmap(0x0, 0x14F, 0x1, 0x2, 0x3, 0x0)		 = 0x1089B1000 0
98193/0xff925:     12177       2      0 lseek(0x3, 0x0, 0x1)		 = 0 0
98193/0xff925:     12226       7      3 munmap(0x1089B1000, 0x14F)		 = 0 0
98193/0xff925:     12231       7      4 close_nocancel(0x3)		 = 0 0
98193/0xff925:     13270      16     12 stat64("/usr/local/Cellar/php71/7.1.11_22/lib/php/extensions/no-debug-non-zts-20160303/grpc.so\0", 0x7FFF57F95778, 0x1)		 = 0 0
98193/0xff925:     13281       7      5 open("/usr/local/Cellar/php71/7.1.11_22/lib/php/extensions/no-debug-non-zts-20160303/grpc.so\0", 0x0, 0x0)		 = 3 0
98193/0xff925:     13330     219     47 pread(0x3, "\317\372\355\376\a\0", 0x1000, 0x0)		 = 4096 0
98193/0xff925:     13386      47     42 mmap(0x109000000, 0x219000, 0x5, 0x12, 0x3, 0x0)		 = 0x109000000 0
98193/0xff925:     13391       7      4 mmap(0x109219000, 0x1A000, 0x3, 0x12, 0x3, 0x219000)		 = 0x109219000 0
98193/0xff925:     13394       4      2 mmap(0x109239000, 0x51BDC, 0x1, 0x12, 0x3, 0x233000)		 = 0x109239000 0
98193/0xff925:     13404       4      1 madvise(0x109239000, 0x2000, 0x2)		 = 0 0
98193/0xff925:     13408       4      2 close(0x3)		 = 0 0
98193/0xff925:     13957       4      0 madvise(0x109239000, 0x2000, 0x5)		 = 0 0
98193/0xff925:     14224      15     12 stat64("/usr/local/opt/php71-intl/intl.so\0", 0x7FFF57F95778, 0x5)		 = 0 0
98193/0xff925:     14233       8      5 open("/usr/local/opt/php71-intl/intl.so\0", 0x0, 0x0)		 = 3 0
98193/0xff925:     14239       9      5 pread(0x3, "\317\372\355\376\a\0", 0x1000, 0x0)		 = 4096 0
98193/0xff925:     14269      26     23 mmap(0x108D57000, 0x3F000, 0x5, 0x12, 0x3, 0x0)		 = 0x108D57000 0
98193/0xff925:     14273       5      2 mmap(0x108D96000, 0xA000, 0x3, 0x12, 0x3, 0x3F000)		 = 0x108D96000 0
98193/0xff925:     14276       5      2 mmap(0x108DA1000, 0x1D520, 0x1, 0x12, 0x3, 0x49000)		 = 0x108DA1000 0
98193/0xff925:     14283       2      0 madvise(0x108DA1000, 0x4000, 0x2)		 = 0 0
98193/0xff925:     14286       4      2 close(0x3)		 = 0 0
98193/0xff925:     14300      12     10 stat64("/usr/local/opt/icu4c/lib/libicui18n.59.dylib\0", 0x7FFF57F95538, 0x2)		 = 0 0
98193/0xff925:     14307       6      4 open("/usr/local/opt/icu4c/lib/libicui18n.59.dylib\0", 0x0, 0x0)		 = 3 0
98193/0xff925:     14310       5      3 pread(0x3, "\317\372\355\376\a\0", 0x1000, 0x0)		 = 4096 0
98193/0xff925:     14332      20     17 mmap(0x10928B000, 0x15E000, 0x5, 0x12, 0x3, 0x0)		 = 0x10928B000 0
98193/0xff925:     14335       4      2 mmap(0x1093E9000, 0xF000, 0x3, 0x12, 0x3, 0x15E000)		 = 0x1093E9000 0
98193/0xff925:     14337       4      1 mmap(0x1093F8000, 0xCE03C, 0x1, 0x12, 0x3, 0x16D000)		 = 0x1093F8000 0
98193/0xff925:     14342       2      0 madvise(0x1093F8000, 0x2000, 0x2)		 = 0 0
98193/0xff925:     14347       3      1 close(0x3)		 = 0 0
98193/0xff925:     14355       7      6 stat64("/usr/local/opt/icu4c/lib/libicuuc.59.dylib\0", 0x7FFF57F95538, 0x2)		 = 0 0
98193/0xff925:     14361       5      3 open("/usr/local/opt/icu4c/lib/libicuuc.59.dylib\0", 0x0, 0x0)		 = 3 0
98193/0xff925:     14364       5      2 pread(0x3, "\317\372\355\376\a\0", 0x1000, 0x0)		 = 4096 0
98193/0xff925:     14384      18     16 mmap(0x1094C7000, 0x103000, 0x5, 0x12, 0x3, 0x0)		 = 0x1094C7000 0
98193/0xff925:     14387       4      2 mmap(0x1095CA000, 0x12000, 0x3, 0x12, 0x3, 0x103000)		 = 0x1095CA000 0
98193/0xff925:     14389       4      2 mmap(0x1095DD000, 0x58EA4, 0x1, 0x12, 0x3, 0x115000)		 = 0x1095DD000 0
98193/0xff925:     14398       3      1 close(0x3)		 = 0 0
98193/0xff925:     14404       5      4 stat64("/usr/local/opt/icu4c/lib/libicudata.59.1.dylib\0", 0x7FFF57F95538, 0x1)		 = 0 0
98193/0xff925:     14409       4      3 open("/usr/local/opt/icu4c/lib/libicudata.59.1.dylib\0", 0x0, 0x0)		 = 3 0
98193/0xff925:     14412       5      2 pread(0x3, "\317\372\355\376\a\0", 0x1000, 0x0)		 = 4096 0
98193/0xff925:     14433      19     17 mmap(0x109636000, 0x1914000, 0x5, 0x12, 0x3, 0x0)		 = 0x109636000 0
98193/0xff925:     14435       4      1 mmap(0x10AF4A000, 0x60, 0x1, 0x12, 0x3, 0x1914000)		 = 0x10AF4A000 0
98193/0xff925:     14445       3      1 close(0x3)		 = 0 0
98193/0xff925:     14452       7      5 stat64("/usr/local/opt/icu4c/lib/libicuio.59.dylib\0", 0x7FFF57F95538, 0x1)		 = 0 0
98193/0xff925:     14458       5      3 open("/usr/local/opt/icu4c/lib/libicuio.59.dylib\0", 0x0, 0x0)		 = 3 0
98193/0xff925:     14460       4      2 pread(0x3, "\317\372\355\376\a\0", 0x1000, 0x0)		 = 4096 0
98193/0xff925:     14483      21     19 mmap(0x108DBF000, 0x9000, 0x5, 0x12, 0x3, 0x0)		 = 0x108DBF000 0
98193/0xff925:     14486       4      2 mmap(0x108DC8000, 0x2000, 0x3, 0x12, 0x3, 0x9000)		 = 0x108DC8000 0
98193/0xff925:     14488       4      1 mmap(0x108DCA000, 0x3DA0, 0x1, 0x12, 0x3, 0xB000)		 = 0x108DCA000 0
98193/0xff925:     14497       3      1 close(0x3)		 = 0 0
98193/0xff925:     14509       3      1 stat64("/\0", 0x7FFF57F93780, 0x1)		 = 0 0
98193/0xff925:     14518       6      4 getattrlist("/usr\0", 0x114ED1364, 0x7FFF57F95090)		 = 0 0
98193/0xff925:     14521       4      2 getattrlist("/usr/local\0", 0x114ED1364, 0x7FFF57F95090)		 = 0 0
98193/0xff925:     14524       3      2 getattrlist("/usr/local/opt\0", 0x114ED1364, 0x7FFF57F95090)		 = 0 0
98193/0xff925:     14527       4      2 getattrlist("/usr/local/opt/icu4c\0", 0x114ED1364, 0x7FFF57F95090)		 = 0 0
98193/0xff925:     14529       4      1 readlink("/usr/local/opt/icu4c\0", 0x7FFF57F94490, 0x3FF)		 = 22 0
98193/0xff925:     14532       4      2 getattrlist("/usr/local/Cellar\0", 0x114ED1364, 0x7FFF57F95090)		 = 0 0
98193/0xff925:     14535       4      2 getattrlist("/usr/local/Cellar/icu4c\0", 0x114ED1364, 0x7FFF57F95090)		 = 0 0
98193/0xff925:     14538       4      2 getattrlist("/usr/local/Cellar/icu4c/59.1_1\0", 0x114ED1364, 0x7FFF57F95090)		 = 0 0
98193/0xff925:     14541       3      2 getattrlist("/usr/local/Cellar/icu4c/59.1_1/lib\0", 0x114ED1364, 0x7FFF57F95090)		 = 0 0
98193/0xff925:     14544       4      2 getattrlist("/usr/local/Cellar/icu4c/59.1_1/lib/libicui18n.59.dylib\0", 0x114ED1364, 0x7FFF57F95090)		 = 0 0
98193/0xff925:     14546       2      1 readlink("/usr/local/Cellar/icu4c/59.1_1/lib/libicui18n.59.dylib\0", 0x7FFF57F94490, 0x3FF)	 = 21 0
98193/0xff925:     14549       4      2 getattrlist("/usr/local/Cellar/icu4c/59.1_1/lib/libicui18n.59.1.dylib\0", 0x114ED1364, 0x7FFF57F95090)		 = 0 0
98193/0xff925:     14557       6      4 stat64("/usr/local/opt/icu4c/lib/libicudata.59.dylib\0", 0x7FFF57F953C8, 0x7FFF57F95090)	 = 0 0
98193/0xff925:     14563       3      1 getattrlist("/usr\0", 0x114ED1364, 0x7FFF57F94F80)		 = 0 0
98193/0xff925:     14565       3      2 getattrlist("/usr/local\0", 0x114ED1364, 0x7FFF57F94F80)		 = 0 0
98193/0xff925:     14567       3      1 getattrlist("/usr/local/opt\0", 0x114ED1364, 0x7FFF57F94F80)		 = 0 0
98193/0xff925:     14571       4      2 getattrlist("/usr/local/opt/icu4c\0", 0x114ED1364, 0x7FFF57F94F80)		 = 0 0
98193/0xff925:     14572       3      1 readlink("/usr/local/opt/icu4c\0", 0x7FFF57F94380, 0x3FF)		 = 22 0
98193/0xff925:     14575       3      1 getattrlist("/usr/local/Cellar\0", 0x114ED1364, 0x7FFF57F94F80)		 = 0 0
98193/0xff925:     14577       4      1 getattrlist("/usr/local/Cellar/icu4c\0", 0x114ED1364, 0x7FFF57F94F80)		 = 0 0
98193/0xff925:     14579       3      1 getattrlist("/usr/local/Cellar/icu4c/59.1_1\0", 0x114ED1364, 0x7FFF57F94F80)		 = 0 0
98193/0xff925:     14582       3      2 getattrlist("/usr/local/Cellar/icu4c/59.1_1/lib\0", 0x114ED1364, 0x7FFF57F94F80)		 = 0 0
98193/0xff925:     14585       4      2 getattrlist("/usr/local/Cellar/icu4c/59.1_1/lib/libicuuc.59.dylib\0", 0x114ED1364, 0x7FFF57F94F80)		 = 0 0
98193/0xff925:     14587       2      1 readlink("/usr/local/Cellar/icu4c/59.1_1/lib/libicuuc.59.dylib\0", 0x7FFF57F94380, 0x3FF)	 = 19 0
98193/0xff925:     14590       3      2 getattrlist("/usr/local/Cellar/icu4c/59.1_1/lib/libicuuc.59.1.dylib\0", 0x114ED1364, 0x7FFF57F94F80)		 = 0 0
98193/0xff925:     14596       4      3 stat64("/usr/local/opt/icu4c/lib/libicudata.59.dylib\0", 0x7FFF57F952B8, 0x7FFF57F94F80)	 = 0 0
98193/0xff925:     14603       3      1 getattrlist("/usr\0", 0x114ED1364, 0x7FFF57F95070)		 = 0 0
98193/0xff925:     14605       3      1 getattrlist("/usr/local\0", 0x114ED1364, 0x7FFF57F95070)		 = 0 0
98193/0xff925:     14608       3      1 getattrlist("/usr/local/opt\0", 0x114ED1364, 0x7FFF57F95070)		 = 0 0
98193/0xff925:     14610       3      1 getattrlist("/usr/local/opt/icu4c\0", 0x114ED1364, 0x7FFF57F95070)		 = 0 0
98193/0xff925:     14611       2      1 readlink("/usr/local/opt/icu4c\0", 0x7FFF57F94470, 0x3FF)		 = 22 0
98193/0xff925:     14614       3      1 getattrlist("/usr/local/Cellar\0", 0x114ED1364, 0x7FFF57F95070)		 = 0 0
98193/0xff925:     14616       3      1 getattrlist("/usr/local/Cellar/icu4c\0", 0x114ED1364, 0x7FFF57F95070)		 = 0 0
98193/0xff925:     14618       3      1 getattrlist("/usr/local/Cellar/icu4c/59.1_1\0", 0x114ED1364, 0x7FFF57F95070)		 = 0 0
98193/0xff925:     14621       3      1 getattrlist("/usr/local/Cellar/icu4c/59.1_1/lib\0", 0x114ED1364, 0x7FFF57F95070)		 = 0 0
98193/0xff925:     14624       4      2 getattrlist("/usr/local/Cellar/icu4c/59.1_1/lib/libicuio.59.dylib\0", 0x114ED1364, 0x7FFF57F95070)		 = 0 0
98193/0xff925:     14625       2      1 readlink("/usr/local/Cellar/icu4c/59.1_1/lib/libicuio.59.dylib\0", 0x7FFF57F94470, 0x3FF)	 = 19 0
98193/0xff925:     14628       3      2 getattrlist("/usr/local/Cellar/icu4c/59.1_1/lib/libicuio.59.1.dylib\0", 0x114ED1364, 0x7FFF57F95070)		 = 0 0
98193/0xff925:     14634       4      2 stat64("/usr/local/opt/icu4c/lib/libicudata.59.dylib\0", 0x7FFF57F953A8, 0x7FFF57F95070)	 = 0 0
98193/0xff925:     15262       5      0 madvise(0x1093F8000, 0x2000, 0x5)		 = 0 0
98193/0xff925:     22471       9      2 madvise(0x108DA1000, 0x4000, 0x5)		 = 0 0
98193/0xff925:     23425      27     20 stat64("/usr/lib/libz.dylib\0", 0x7FFF57F95658, 0x5)		 = 0 0
98193/0xff925:     25263      39     33 socket(0x1E, 0x2, 0x0)		 = 3 0
98193/0xff925:     25275      12     10 close(0x3)		 = 0 0
98193/0xff925:     26714      13      5 sysctl([CTL_KERN, 8, 0, 0, 0, 0] (2), 0x7FFF57F961E4, 0x7FFF57F961E8, 0x0, 0x0)		 = 0 0
98193/0xff925:     29304      12      8 open_nocancel("grpc-fork-bug.php\0", 0x0, 0x1B6)		 = 3 0
98193/0xff925:     29310       3      1 fstat64(0x3, 0x7FFF57F960D8, 0x1B6)		 = 0 0
98193/0xff925:     29360     249     49 read_nocancel(0x3, "<?php \n\n$pid = pcntl_fork(); \n\nif($pid === -1) { \n\techo \"error forking\\n\"; \n} elseif ($pid) { //parent \n\techo \"parent: waiting for child...\\n\"; \n\tpcntl_waitpid(0, $status);\n\techo \"parent: child exited successfully\\n\"; \n} elseif ($pid === 0) { //child\n\techo", 0x1000)		 = 371 0
98193/0xff925:     29370       3      0 lseek(0x3, 0x0, 0x1)		 = 371 0
98193/0xff925:     29377       8      5 open_nocancel(".\0", 0x0, 0x1)		 = 4 0
98193/0xff925:     29379       3      1 fstat64(0x4, 0x7FFF57F95C40, 0x1)		 = 0 0
98193/0xff925:     29381       4      2 fcntl_nocancel(0x4, 0x32, 0x7FFF57F95E50)		 = 0 0
98193/0xff925:     29384       4      1 close_nocancel(0x4)		 = 0 0
98193/0xff925:     29387       5      3 stat64("/Users/zack.angelo/git/grpc-fork-bug\0", 0x7FFF57F95BB0, 0x7FFF57F95E50)		 = 0 0
98193/0xff925:     29397       4      2 lstat64("/Users/zack.angelo/git/grpc-fork-bug/grpc-fork-bug.php\0", 0x7FFF57F958B0, 0x7FFF57F95E50)		 = 0 0
98193/0xff925:     29399       2      1 lstat64("/Users/zack.angelo/git/grpc-fork-bug\0", 0x7FFF57F95780, 0x7FFF57F95E50)		 = 0 0
98193/0xff925:     29401       3      1 lstat64("/Users/zack.angelo/git\0", 0x7FFF57F95650, 0x7FFF57F95E50)		 = 0 0
98193/0xff925:     29403       2      1 lstat64("/Users/zack.angelo\0", 0x7FFF57F95520, 0x7FFF57F95E50)		 = 0 0
98193/0xff925:     29404       2      1 lstat64("/Users\0", 0x7FFF57F953F0, 0x7FFF57F95E50)		 = 0 0
98193/0xff925:     29425       4      1 sigaction(0x1B, 0x0, 0x7FFF57F96138)		 = 0 0
98193/0xff925:     29426       1      0 sigaction(0x1B, 0x7FFF57F96108, 0x0)		 = 0 0
98193/0xff925:     29426       1      0 sigaction(0x1, 0x0, 0x7FFF57F96138)		 = 0 0
98193/0xff925:     29427       1      0 sigaction(0x1, 0x7FFF57F96108, 0x0)		 = 0 0
98193/0xff925:     29427       1      0 sigaction(0x2, 0x0, 0x7FFF57F96138)		 = 0 0
98193/0xff925:     29428       1      0 sigaction(0x2, 0x7FFF57F96108, 0x0)		 = 0 0
98193/0xff925:     29428       1      0 sigaction(0x3, 0x0, 0x7FFF57F96138)		 = 0 0
98193/0xff925:     29429       1      0 sigaction(0x3, 0x7FFF57F96108, 0x0)		 = 0 0
98193/0xff925:     29430       1      0 sigaction(0xF, 0x0, 0x7FFF57F96138)		 = 0 0
98193/0xff925:     29431       1      0 sigaction(0xF, 0x7FFF57F96108, 0x0)		 = 0 0
98193/0xff925:     29431       1      0 sigaction(0x1E, 0x0, 0x7FFF57F96138)		 = 0 0
98193/0xff925:     29432       1      0 sigaction(0x1E, 0x7FFF57F96108, 0x0)		 = 0 0
98193/0xff925:     29432       1      0 sigaction(0x1F, 0x0, 0x7FFF57F96138)		 = 0 0
98193/0xff925:     29432       1      0 sigaction(0x1F, 0x7FFF57F96108, 0x0)		 = 0 0
98193/0xff925:     29433       1      0 sigaction(0x1B, 0x7FFF57F96098, 0x0)		 = 0 0
98193/0xff925:     29441       2      0 sigprocmask(0x2, 0x7FFF57F960CC, 0x0)		 = 0x0 0
98193/0xff925:     29521      10      4 mmap(0x0, 0x10000, 0x3, 0x1002, 0xFFFFFFFF, 0x0)		 = 0x10AF6F000 0
98193/0xff925:     30217      10      5 pipe(0x0, 0x10000, 0x3)		 = 4 0
98193/0xff925:     30229       3      0 fcntl(0x4, 0x3, 0x0)		 = 0 0
98193/0xff925:     30230       2      0 fcntl(0x4, 0x4, 0x4)		 = 0 0
98193/0xff925:     30231       1      0 fcntl(0x5, 0x3, 0x0)		 = 1 0
98193/0xff925:     30231       1      0 fcntl(0x5, 0x4, 0x5)		 = 0 0
98193/0xff925:     30243       4      2 close(0x4)		 = 0 0
98193/0xff925:     30244       2      1 close(0x5)		 = 0 0
98193/0xff925:     30747      25     20 bsdthread_create(0x109010800, 0x7F814DC719C0, 0x80000)		 = 10268672 0
98193/0xffb51:         6      69      0 thread_selfid(0x0, 0x0, 0x0)		 = 1047377 0
98193/0xffb51:       102      13      0 gettimeofday(0x7000009CAD58, 0x0, 0x0)		 = 0 0
98193/0xff925:     30936       5      2 fstat64(0x0, 0x7FFF57F96060, 0x80000)		 = 0 0
98193/0xff925:     30952       2      0 fstat64(0x0, 0x108E72038, 0x80000)		 = 0 0
98193/0xff925:     30954       2      0 lseek(0x0, 0x0, 0x1)		 = 3311256 0
98193/0xff925:     30956       2      0 fstat64(0x1, 0x7FFF57F96060, 0x1)		 = 0 0
98193/0xff925:     30957       1      0 fstat64(0x1, 0x108E72118, 0x1)		 = 0 0
98193/0xff925:     30958       1      0 lseek(0x1, 0x0, 0x1)		 = 3311256 0
98193/0xff925:     30959       2      0 fstat64(0x2, 0x7FFF57F96060, 0x1)		 = 0 0
98193/0xff925:     30960       1      0 fstat64(0x2, 0x108E721F8, 0x1)		 = 0 0
98193/0xff925:     30961       1      0 lseek(0x2, 0x0, 0x1)		 = 3311256 0
98193/0xff925:     30976      10      8 open_nocancel(".\0", 0x0, 0x1)		 = 4 0
98193/0xff925:     30978       2      1 fstat64(0x4, 0x7FFF57F95600, 0x1)		 = 0 0
98193/0xff925:     30981       5      2 fcntl_nocancel(0x4, 0x32, 0x7FFF57F95820)		 = 0 0
98193/0xff925:     30984       4      2 close_nocancel(0x4)		 = 0 0
98193/0xff925:     30988       5      3 stat64("/Users/zack.angelo/git/grpc-fork-bug\0", 0x7FFF57F95570, 0x7FFF57F95820)		 = 0 0
98193/0xff925:     31000       2      0 ioctl(0x3, 0x4004667A, 0x7FFF57F957BC)		 = -1 Err#25
98193/0xff925:     31001       1      0 ioctl(0x3, 0x40487413, 0x7FFF57F957C0)		 = -1 Err#25
98193/0xff925:     31003       2      1 fstat64(0x3, 0x7FFF57F95830, 0x7FFF57F957C0)		 = 0 0
98193/0xff925:     31011      10      7 mmap(0x0, 0x193, 0x1, 0x2, 0x3, 0x0)		 = 0x1089B2000 0
98193/0xff925:     31125       8      5 munmap(0x1089B2000, 0x193)		 = 0 0
98193/0xff925:     31131       7      5 close_nocancel(0x3)		 = 0 0
98193/0xff925:     33667    2512   2495 fork()		 = 98238 0
98238/0xffb52:        80:        0:       0 fork()		 = 0 0
98238/0xffb52:        80       4      0 thread_selfid(0x0, 0x0, 0x0)		 = 1047378 0
98238/0xffb52:        85       6      3 bsdthread_register(0x7FFFD3854080, 0x7FFFD3854070, 0x2000)		 = -1 Err#22
98193/0xff925:     33858      15     10 write(0x1, "parent: waiting for child...\n\0", 0x1D)		 = 29 0
98238/0xffb52:       192       3      0 getpid(0x7FFFD3854080, 0x7FFFD3854070, 0x2000)		 = 98238 0
98238/0xffb52:       197       4      1 __mac_syscall(0x7FFFD385FC46, 0x4, 0x7FFF57F95578)		 = -1 Err#45
98238/0xffb52:       199       3      1 csops(0x17FBE, 0xB, 0x7FFF57F955B8)		 = -1 Err#22
98238/0xffb52:       685      14      9 write(0x1, "child: sleeping for 1s...\n\b\0", 0x1A)		 = 26 0
child: exiting...
98238/0xffb52:       760 1000905     10 __semwait_signal(0x703, 0x0, 0x1)		 = -1 Err#60
98193/0xffb51:       112 1004731      9 psynch_cvwait(0x109236098, 0x100000100, 0x0)		 = -1 Err#316
98238/0xffb52:       793     111     16 write(0x1, "child: exiting...\n\0", 0x12)		 = 18 0
98193/0xffb51:       196      75      0 gettimeofday(0x7000009CAD58, 0x0, 0x0)		 = 0 0
98238/0xffb52:      1457      71      2 close_nocancel(0x2)		 = 0 0
98238/0xffb52:      1480       3      0 close_nocancel(0x1)		 = 0 0
98238/0xffb52:      1502       3      0 close_nocancel(0x0)		 = 0 0
98238/0xffb52:      2089      16     13 munmap(0x108D96000, 0xB000)		 = 0 0
98238/0xffb52:      2093       5      2 munmap(0x108DA1000, 0x1E000)		 = 0 0
98238/0xffb52:      2097       6      3 munmap(0x108D57000, 0x3F000)		 = 0 0
98238/0xffb52:      2119       4      2 munmap(0x1093E9000, 0xF000)		 = 0 0
98238/0xffb52:      2121       3      1 munmap(0x1093F8000, 0xCF000)		 = 0 0
98238/0xffb52:      2125       6      4 munmap(0x10928B000, 0x15E000)		 = 0 0
98238/0xffb52:      2135       3      1 munmap(0x1095CA000, 0x13000)		 = 0 0
98238/0xffb52:      2137       2      0 munmap(0x1095DD000, 0x59000)		 = 0 0
98238/0xffb52:      2140       5      3 munmap(0x1094C7000, 0x103000)		 = 0 0
98238/0xffb52:      2149       3      1 munmap(0x10AF4A000, 0x1000)		 = 0 0
98238/0xffb52:      2154       7      4 munmap(0x109636000, 0x1914000)		 = 0 0
98238/0xffb52:      2168       3      1 munmap(0x108DC8000, 0x2000)		 = 0 0
98238/0xffb52:      2169       3      0 munmap(0x108DCA000, 0x4000)		 = 0 0
98238/0xffb52:      2172       4      2 munmap(0x108DBF000, 0x9000)		 = 0 0
98238/0xffb52:      2302       6      2 psynch_cvbroad(0x109236098, 0x100, 0x100)		 = 2 0
98193/0xffb51:       207 1005369     10 psynch_cvwait(0x109236098, 0x10100000200, 0x0)		 = -1 Err#316
98193/0xffb51:       238      69      0 gettimeofday(0x7000009CAD58, 0x0, 0x0)		 = 0 0
98193/0xffb51:       247 1001302      8 psynch_cvwait(0x109236098, 0x20100000300, 0x0)		 = -1 Err#316
98193/0xffb51:       286      72      0 gettimeofday(0x7000009CAD58, 0x0, 0x0)		 = 0 0
98193/0xffb51:       298 1004393     11 psynch_cvwait(0x109236098, 0x30100000400, 0x0)		 = -1 Err#316
98193/0xffb51:       335     139      3 gettimeofday(0x7000009CAD58, 0x0, 0x0)		 = 0 0
98193/0xffb51:       347 1002852     10 psynch_cvwait(0x109236098, 0x40100000500, 0x0)		 = -1 Err#316
98193/0xffb51:       377      67      9 gettimeofday(0x7000009CAD58, 0x0, 0x0)		 = 0 0
^C
98193/0xffb51:       403 1002432     22 psynch_cvwait(0x109236098, 0x50100000600, 0x0)		 = -1 Err#316
98193/0xffb51:       442      84      0 gettimeofday(0x7000009CAD58, 0x0, 0x0)		 = 0 0
98193/0xff925:     33973 6645911      6 wait4(0x0, 0x7FFF57F95984, 0x0)		 = -1 Err#4
98238/0xffb52:      2319 5642539      6 psynch_cvwait(0x1092360C8, 0x100000100, 0x0)		 = -1 Err#260

(it basically keeps calling gettimeofday and psynch_cvwait).

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 1
  • Comments: 17 (10 by maintainers)

Most upvoted comments

gRPC C++ does not allow fork. This is common to many networking packages - after a fork the parent and child share the same internal FD and that is not sensible for an event-based system with multiple streams sharing the same channel (or many other modes of deployment). I don’t believe that any gRPC C-based binding accepts fork.

This issue is ready for beta testing. We have pushed a release candidate for the upcoming 1.17.0 release. You can update your PECL extension to this version via:

$ sudo pecl install grpc-beta

This should pull in version 1.17.0RC2. You can verify your grpc extension version by checking:

$ php -d extension=grpc.so --re grpc | head -1
Extension [ <persistent> extension #39 grpc version 1.17.0RC2 ] {

With that, use of pcntl_fork() is supported. Here are some restrictions:

  • This will only work from CLI
  • This has only been tested on Linux
  • This has only been tested on PHP 7.0+

From the command line, you have to set two environment variables to enable fork support, like this:

$ GRPC_ENABLE_FORK_SUPPORT=1 GRPC_POLL_STRATEGY=epoll1 php -d extension=grpc.so test.php

The short script in the first post in this issue will no longer hang.


Furthermore, the gRPC client should continue to be useable after pcntl_fork() happen. Here’s a test script:

<?php                                                                                                         
                                                                                                              
require dirname(__FILE__).'/vendor/autoload.php';                                                             
                                                                                                              
$client = new Helloworld\GreeterClient('localhost:9090', [                                                    
  'credentials' => Grpc\ChannelCredentials::createInsecure(),                                                 
]);                                                                                                           
$request = new Helloworld\HelloRequest();                                                                     
$request->setName('php-parent');                                                                              
$call = $client->SayHello($request);                                                                          
                                                                                                              
$pid = pcntl_fork();                                                                                          
if ($pid == -1) {                                                                                             
  die('could not fork');                                                                                      
                                                                                                              
} else if ($pid) {                                                                                            
  // parent                                                                                                   
  list($reply, $status) = $call->wait();                                                                      
  $message = $reply->getMessage();                                                                            
  echo "parent | rpc result: ---$message---\n";                                                               
  pcntl_waitpid($pid, /*&*/$pcntl_status);                                                                    
                                                                                                              
} else {                                                                                                      
  // child                                                                                                    
  $request->setName('php-child');                                                                             
  $child_call = $client->SayHello($request);                                                                  
  list($child_reply, $child_status) = $child_call->wait();                                                    
  $child_message = $child_reply->getMessage();                                                                
  echo "child  | rpc result: ---$child_message---\n";                                                         
  echo "child exiting\n";                                                                                     
  exit(0);                                                                                                    
}                                                                                                             
echo "parent finishing\n";

This will print out:

$ GRPC_ENABLE_FORK_SUPPORT=1 GRPC_POLL_STRATEGY=epoll1 php -d extension=grpc.so fork_client.php 
parent | rpc result: ---Hello! php-parent---
child  | rpc result: ---Hello! php-child---
child exiting
parent finishing

Please check it out and let us know if this works for you!

How would the grpc extension like being loaded after the fork with dl? The reason I bring that up is because for CLI use-cases where dl is still available this could be a potential workaround until forking is supported. dl is not available in FPM but, IMHO, pcntl_fork shouldn’t be used from within FPM anyway.

This script works on PHP 7 macOS with the extension present on the system but not loaded in the .ini files:

<?php

$pid = pcntl_fork();

if($pid === -1) {
    echo "error forking\n";
} elseif ($pid) { //parent
    echo "parent: extension_loaded(grpc): ". var_export(extension_loaded("grpc"), true) ."\n";
    echo "parent: waiting for child...\n";
    pcntl_waitpid(0, $status);
    echo "parent: child exited successfully\n";
} elseif ($pid === 0) { //child
    dl("grpc.so");
    echo "child: extension_loaded(grpc): ". var_export(extension_loaded("grpc"), true) ."\n";
    echo "child: sleeping for 1s...\n";
    sleep(1);
    echo "child: exiting...\n";
    exit(0);
}

echo "parent: finished.\n";

This requires enable_dl to be set, like so:

$ php -d enable_dl=1 fork.php
parent: extension_loaded(grpc): false
parent: waiting for child...
child: extension_loaded(grpc): true
child: sleeping for 1s...
child: exiting...
parent: child exited successfully
parent: finished.