Working with POE is sometimes a real struggle. Things I want to do that seem perfectly normal to me are apparently weird exotic things things that are impossible and can't be added and why on earth would you want that anyway, you can solve the trivial example case different, you use AIX right?
Todays example was wanting to test that a program has shut down properly and cleaned up itself, SPECIFICALLY such that POE::Kernel->run should naturally finish.
So basically I want to know when something will end.
With both mjd (in his "You Can't Get There From Here" talk) and myself (in my "Nothing Can Possibly Go Wrong" talk, and my PPI talk) harping on about the Halting Problem, I think people are maybe making it more powerful than it is.
Now, granted, if I didn't know what the code was, and I wanted to write a generic function, it would be impossible.
But really, I don't. I want to know if POE will stop.
Now, the naive way is to do something like this.
POE::Kernel->run;
pass( "POE stopped" );
The more astute of you will have noticed straight away that the problem with this is if the test fails. Because the test never fails. Either the test passes, or it deadlocks and the tests hang. BAD!
We could maybe use a hard alarm(), but POE might be trapping it, and alarm() I'm told isn't working right on Win32, so that's out.
That leaves playing games with fork() (oops, bad on Win32, nope) or some form of IPC (most of which suck on Win32) or doing it INSIDE of POE itself.
Which creates a problem... now, the obvious approach is to set an alarm (in POE via $poe_kernel->delay_set( 'program_stops' => 10 ) or similar.
Except that POE can't finish because of the very alarm we are using to test that everything is done.
HOWEVER, we can now ask not WHEN the program will finish, but is this alarm event (when it fires) the very last thing that POE will do and do we have the specific conditions to stop NOW.
And we can do that via introspection. Since POE doesn't have much introspection capability by default, we need to add a dep on the extremely useful POE::API::Peek by sungo++.
If we are in the last even, there should be no other sessions by ours, be nothing in the queues, be no signals handlers, and no event generators like file handles. If so, the test passes, and we allow POE to continue and shut down.
But if the test FAILS and we find something, now we can do something about it. We can just call a hard-stop on the kernel, and we finish as well, with a fail case.
Problem solved, and the Halting Problem avoided.
You can find this solution on the CPAN as Test::POE::Stopping.
Of course, if you're thinking ahead, you'll have realised what I've really made is a really crude and almost useless POE leak detector that doesn't report what actually leaked.
So the next step, if nobody has done it already, is take a similar approach, but boil down the introspection data into a simple report structure, and dump it out as a nice readable YAML report, so that you can see exactly what it is that leaked, and who it belongs to.
Re:Er, separate process?
Alias on 2006-10-05T00:10:56
Sounds great, wrap all that platform abstraction up into something something simple that actually works everywhere, and then I'll look into it. It would be really nice if IPC::Open3 was finally sane everywhere.
Further, how do you handle debugging?
I mean, if you are just killing your process, what's the point?
With Test::POE::Stopping, we only need to add a few minor enhancements and we can start getting it to not only say that it won't end, but spit out full diagnositics of the specifics of the POE resources (aliases, handles, alarms, etc) that are actually leaking.
This takes it into another realm of usefulness entirely.
Just killing off the process doesn't give you that.
Re:Er, separate process?
jjore on 2006-10-05T00:42:24
IPC::Open3 isn't sane everywhere? Drat. People have been recommending it in my presence lately and I figured it was ok.
Oh well.:-/ Re:Er, separate process?
Alias on 2006-10-05T08:22:15
You might be thinking of IPC::Run3, which is most certainly sane everywhere.