Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Standard handle pipes do not work the same on Windows #126

Open
cubiclesoft opened this issue Oct 2, 2017 · 6 comments
Open

Standard handle pipes do not work the same on Windows #126

cubiclesoft opened this issue Oct 2, 2017 · 6 comments

Comments

@cubiclesoft
Copy link

Unfortunately, Windows itself does not support non-blocking I/O on Windows pipes, which includes the standard handles used for CreateProcess(). It's an issue leftover from the early days of Windows and not something that Microsoft can easily fix or they would have already fixed it. You've accidentally run into a fundamental low-level Win32 CreateProcess() API bug. Since standard handles are almost always blocking pipes, an application might be expecting input on stdin while, at the same time, PHP is blocking while waiting for output on stdout. That, of course, creates difficult-to-diagnose issues resulting in application freezes usually on the PHP end of things. This behavior only happens on Windows and it's an easy issue to miss in cursory testing.

However, there is a workaround for standard handle applications where there is no source code control available or where the code would be too complicated to fix on the application's end of things:

https://bugs.php.net/bug.php?id=47918

An alternative could be to set up a localhost TCP/IP server on a random port (via port 0) in the PHP application, then start the Lazarus app and send the port number as part of the command line arguments or environment variables. The Lazarus app picks off the port number and connects back into the PHP application using a TCP/IP socket. Both sides enable non-blocking mode. At that point, the PHP side can terminate the TCP/IP server since it won't need to accept any more connections and then communication happens over localhost TCP/IP. By using TCP/IP, both the application and PHP can completely avoid the issue of attempting to use blocking stdin/stdout for non-blocking bidirectional IPC.

Since this project depends on react/child-process, the following bug report is relevant:

reactphp/child-process#9

I found PHP-GUI while evaluating options for solving a chicken-or-the-egg problem. Given the size of the binaries in this project and what I know about standard handle issues on Windows for IPC, I'm probably going to pass and try to figure out something simpler.

Side note: Each GitHub project is limited to 1GB total storage. Pure source code repos will likely never hit that limit. Large binaries that change frequently can use that storage up pretty quickly - I hit one of GitHub's internal storage limits once upon a time. This repo currently uses around 120MB of storage according to: https://api.github.com/repos/gabrielrcouto/php-gui Just something to keep in mind. On a related side-note, I've always been impressed with the extremely small file sizes of both the useful native Windows software produced by nirsoft and those participating in the not-as-useful-but-cool 4k and 64k demoscenes.

@gabrielrcouto
Copy link
Owner

Wow, this is one of the best issue descriptions which I've read on my projects, thank you very much @cubiclesoft for your time.

I agree with everything you said. Initially, I used the stdin/stdout to enable easy SSH tunneling (you execute the PHP side on a server, and the Lazarus side on your computer, something like a thin client, but yes, you can do this using TCP/IP), but, as you said, non-blocking I/O on Windows pipes are too complicated to get working stable, and I was thinking to change to TCP/IP a few days before your comment. Probably using something like JSON-RPC on top of TCP/IP will make things easier, and this will enable other backends (not only PHP) to create graphical user interfaces using this project. The way you described the TCP/IP port "negotiation" was perfect.

About the storage problem, I need to create a "post install" step for composer, to download the release zip file (with all binaries) and keep simple the use of this project. Well noted ;-)

Just out of curiosity, what project did you find to solve your problem?

@cubiclesoft
Copy link
Author

I tend to do a lot of research first before writing any code. Haven't settled on anything yet. I have been working on a major project for the last 8 months now so research for future projects and lightweight dev work is mostly all I can spare for brief distractions.

@trowski
Copy link

trowski commented Apr 11, 2018

amphp/process supports non-blocking I/O on process pipes on Windows. Amp also has the amphp/parallel package that may make IPC even easier.

@gabrielrcouto I'd be curious to know your thoughts of switching to Amp for process management. Note that Amp is compatible with any ReactPHP packages, so that may help ease the transition for users.

@cubiclesoft
Copy link
Author

The code for setting up socket communications should happen in the Lazarus process itself so that sockets are used across all platforms. The EXE shim is a hack to solve process I/O blocking on Windows, which adds an extra process to the mix but isn't needed when control over the target process already exists.

@gabrielrcouto
Copy link
Owner

@trowski thank you for the recommendation, amphp is an amazing project. After your comment, I made some tests and, as @cubiclesoft said, the EXE shim solves the problems, but adds one more process to control, and the Lazarus continues to be a problem, really unstable using pipes.

Well, your comment made me to refocus on this project, and after 2 days of working, I did the migration of all the IPC communication using TCP socket, you can see on https://github.com/gabrielrcouto/php-gui/tree/feature/socket. I tested on Mac, if you can help me testing on other platforms, I'll appreciate 😄 (you'll need to compile for testing). On Mac, php-gui with socket is really stable.

@reisraff could you test on Linux? \o/

@reisraff
Copy link
Collaborator

@gabrielrcouto it had worked perfect, obviously that we need do a double check and find for bugs, ant things like that, but, you gotcha 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants