Published 2002-01-22 21:41:00

Well Monday was a busy day - well, in terms of coding, if nothing else. I started looking on Sunday at a new module for phpmole, - a simple debugger that could just look at the output, find the warnings, turn them into links and allow you to jump to them. All sounded Quite easy, however from previous experience, It's not quite that easy. Details Inside.....
The key issue is that when you initiate a process (popen) in php, it will hang and wait upon responses - effectivly a blocking IO process, this is standard with the Unix definition of popen, which exec,system and popen all use. So, after working all that out, it was obvious that there no simple fix that could be applied to popen to turn it into non-blocking.

So I started looking at alternatives - the first being pcntl -a new(ish) extension in the php cvs, which deals with process controll. This module makes available commands like pcntl_fork(), and pcntl_signal(SIG???,"callback"), the key understanding  fork is that it does not start the program from the beginning, but rather at the point in time where the fork command is, it breaks the process in two, both have all the variables available, and are at the same point, however from then on, they operate as seperate entities.

the return value for fork is either (0) - which means that I'm the child, or a number=PID, which means I'm the parent, and the PID is of the child that has started...


This meant that the design of the application went something like this at the point of exec'ing the child process to monitor, the program forks. the child process is responsible for starting the exec - eg. running the program and waiting for data to come in, so this is the one that hangs.  The child process would then have to output the data to a file as it came in, and issue a signal to the parent to let it know to look at the file.

It was a bit messy, but in theory should have worked. However after installing pcntl as a module (not compiled into the php binary). It became clear that
1.pcntl_signal did handle class/method callbacks
2.the callbacks where not getting called.

The class/method callback stuff took a while, as my understanding of the Zend API, is flakey at the best of times, but eventually I got it working

Overview of the pcntl module
The internals of the pcntl module do not directly 'call a user function' as soon as it recieves a signal, this could be a 'bad' thing, (as it may be in the middle of a command). so it basically keeps a queue of signals in a standard php internal hash, and when the zend_extension_statement_handler is called (by the Zend interpreter), it loops through this queue and calls all the functions associated with the signals.

This had a few problems (as mentioned above), first was that the associated hash table that stored the mappings of signal to functions only used a string as it's association, rather than a zval (the basic storage type for php variables in C). The changes here involved modifing the input checking area, - so that it accepted array(&$this,"method") and "function", and then stored it in the hash table correctly - this took alot of working out, as it had to replicate the data before it could store it in the array (otherwise it got freed from memory at the end of the function call).

At the other end, the hash table had to get it out in the right way, and use it in the call_user_function call correctly. (basically getting the right combination of zval ** handle, zval * handle , zend_is_callable then- either *handle, &handle or just plain handle.. - This is why php is so nice, not having to wory about pointers :)


The other issue was that as I was building module as a dl'extension, none of the zend_init or statement_handler where ever getting called, the solution to this was quite simple.  - just add a php function to clear/check the queue. - this could then either be used randomly all over the program, or in php-gtk's case, in a loop with while(gtk::events_pending()) gtk::main_iteration();

Looking at the process stuff
by the time I finished looking at all that, It was getting late, and I started playing with sockets, the idea being, that the way I described above seemed a little clunky - the signal passing to tell one fork to check a file.. , so I started looking at non-blocking unix domain sockets - but thats another story........

Add Your Comment