On Mon, 14 Mar 2011, Bo Johansson via RT wrote:
Show quoted text> 1) You wrote:
>
> >Windows 7:
> >system $^X, "-e", "if (\$pid=fork){kill(9, \$pid)} else {sleep 5}";
> >print $?>>8, "\n";
>
> Is it a problem if it is blocking and there is no print at all?
Yes, that is a problem. Note though that kill(9, $child) is inherently
unsafe for pseudo-processes. You should only ever do this if you
know that $child is in a known "blocking" state. E.g.
system $^X, "-e", "if (\$pid=fork){sleep 1;kill(9, \$pid)} else {sleep 5}";
The sleep(1) before the kill() should give the child process enough
time to reach the sleep(5) call before getting killed.
Here is the list of warnings about some of the things that can go
wrong if you call TerminateThread() when you don't know the current
state of the thread (from the Microsoft docs):
* If the target thread owns a critical section, the critical section
will not be released.
* If the target thread is allocating memory from the heap, the heap lock
will not be released.
* If the target thread is executing certain kernel32 calls when it is
terminated, the kernel32 state for the thread's process could be
inconsistent.
* If the target thread is manipulating the global state of a shared
DLL, the state of the DLL could be destroyed, affecting other users
of the DLL.
As the terminated thread runs inside the same process as the controlling
thread, it is always possible that the controlling thread will get
damaged by this action.
I've suggested an alternative to perl5-porters, that would allow us
to SIGTERM the child and then simply exit from the parent and leave
the thread cleanup to the OS. That should work much cleaner, because
it should never affect the parent process.
Show quoted text> 2) Using the batch file:
> @echo off
> set count=0
> :loop
> set /a count=%count%+1
> echo Count %count%
> @echo on
> perl -Ilib t/01_simple.t
> perl -Ilib t/08_exit.t
> perl -Ilib t/09_fork.t
> perl -Ilib t/10_oo.t
> @echo off
> goto loop
I have not tested with the Test::TCP tests any further, but...
[...]
Show quoted text> 3) Running this batch file:
>
> @echo off
> set count=0
> :loop
> set /a count=%count%+1
> echo Count %count%
> @echo on
> perl -e "if ($pid=fork){Win32::Sleep(0); kill(9, $pid); Win32::Sleep(0)}
> else {sleep 1000}"
> if errorlevel 1 goto exit
> @echo off
> goto loop
> :exit
> ECHO.%ERRORLEVEL%
>
> (second "Win32::Sleep(0)" is added) gave the results:
>
> - Blocking after 2170 loops.
> - Blocking after 449 loops.
> - Blocking after 38 loops.
> - Blocking after 58 loops.
> - Blocking after 2108 loops.
> - Exiting with the value 9 after 3 loops.
> - Exiting with the value 9 after 7 loops.
> - Exiting with the value 9 after 7 loops.
> - Exiting with the value 9 after 1 loops.
> - Exiting with the value 9 after a few loops was repeated more than 20
> times using the same command windows.
> Is there some missing initialization???!!!
> - Blocking after 2806 loops.
> - Blocking after 353 loops.
> - Blocking after 1737 loops.
> - Run more than 7000 loops without problems.
>
> Conclusion: There are still "exiting with the value 9".
>
> Removing the first Win32::Sleep(0) resulted in immediate blocking.
I've been running this, and variations of it on my Windows 7 Pro SP1 VM,
and only had it exit with value "9" once after more than 24K interations.
So I see that it can still happen, but it is really hard to repro.
I was hoping to be able to see the blocking state, so I could use a debugger
to check the stack traces from all threads to determine the cause of the
deadlock, but have not been able to repo this at all.
Anyways, I don't think TerminateThread() can ever be completely safe
if you call it when the child thread may not be in a wait state, so
I hope the alternate implementation will solve the issue instead (for
5.14 and later only, for 5.12 and earlier we will have to add the
sleep() calls and live with the occasional breakage, I think).
Cheers,
-Jan