#!/usr/local/bin/tclsh
package require Tclx
# package require md5
namespace eval test {
}
proc test::md5 {} {
set procId [fork];
if { $procId != 0 } {
puts "Exiting parent process pid=[pid]";
return 0;
}
puts "Child process pid=[pid]"
# puts [::md5::md5 -hex
-file /var/named/zones/in-addr.arpa/0.249.24.in-addr.arpa]
return 0;
}
test::md5
exit 0
Under 8.5 child process is not gonna to finish:
[dan@king BIND]$ ./test.tcl
Child process pid=26488
Exiting parent process pid=26485
[dan@king BIND]$ ps ax | grep test.tcl
26488 pts/1 S 0:00 /usr/local/bin/tclsh ./test.tcl
26490 pts/1 S+ 0:00 grep test.tcl
Why use a threaded version under unix ? Threads and fork don't make a
happy blend.
-Alex
I know that threads + fork potentially can cause problems (seems like I hit
one of them). Is there workaround to solve this problem and use 8.5 with
threads support or I should recompile tcl with threads disabled. Apparently
this problem wider - why binary distribution has so obvious bug (or
feature ;-)).
Sure, but keeping orthogonal things orthogonal is a nice habit. Here
you changed simultaneously the version and the thread support... So
did you try with 8.4-threads ?
-Alex
Seems like there is a bug. Who should take a look at this issue ? Somebody
from tcl core devs ?
IMHO, threads are portable, but fork() is not. I think it might come
down to you choosing either methodology as mutually exclusive.
I think this fork vs threads debate dates back to 2001 if I remember
right when Dave Welton flailed the big red flags about how pthreads and
fork just don't and can't mix.
> Daniel A. Mezentsev wrote:
>> As I expected, tcl 8.4 with threads support doesn't work properly with
>> fork.
>
> IMHO, threads are portable, but fork() is not. I think it might come
> down to you choosing either methodology as mutually exclusive.
Perhaps like fast solution of this issue I'll recompile 8.5 without threads,
but for long term ... hm, I don't know yet.
>
> I think this fork vs threads debate dates back to 2001 if I remember
> right when Dave Welton flailed the big red flags about how pthreads and
> fork just don't and can't mix.
I was a russian post grad student in 2001 in deep siberian city, so it's
really hard for me to operate with historical data. Actually it doesn't
clear for me - why fork+threads blend cause such problem. We don't have
same issue using C/C++, do we ? I have pretty simple perl program with the
same structure (parent -- fork -- parent + child -- parent exit -- child)
and it works just fine, honestly saying I'm not sure about threads support
in perl. Is is a bad tcl design ?
See:
http://sourceforge.net/tracker/index.php?func=detail&aid=1470152&group_id=10894&atid=110894
Michael
We had a recent thread about this that I started.
http://groups.google.com/group/comp.lang.tcl/msg/ce6a1324bada8db0
It's basically unfixable IMO, unless the contraints are changed, and
even then it's iffy.
George
As I understand it, the problem relates to mutexes and the way Tcl needs
a thread to manage the notifier.
> We don't have same issue using C/C++, do we ?
Actually, you do the problems but you have enough control that you can
often sidestep them.
> I have pretty simple perl program with the
> same structure (parent -- fork -- parent + child -- parent exit -- child)
> and it works just fine, honestly saying I'm not sure about threads support
> in perl.
IIRC, perl is usually built unthreaded. They also don't use a notifier,
and so avoid a lot of complexity in that area (at the cost of not having
a notifier of course).
> Is is a bad tcl design ?
The problem is purely that the pthread library and the fork syscall are
not happy bed-fellows, and there's not much Tcl can do about it (since
threaded Tcl uses a number of threads internally). Now, it isn't
actually a problem when the fork is followed by an exec (all the
dangling lock problems get swept away by starting another executable)
but for other uses of fork are just trouble. If you insist on using them
together (e.g. because you're wanting to run as a daemon) then you
should write a small program to stand instead of tclsh that does the
forking and only then hands off control to the Tcl library.
(There are ways to make fork work for real; they're horrific.)
Donal.
The thread has the key points, but to summarize:
This has nothing to do with 8.4 vs 8.5, it is purely a pthreads+fork
issue. It isn't unique to Tcl. It is solvable *with constraints*. I
think the constraints are reasonable though (you use either fork()
*or* threads, but not both, and we would try and best support the
fork() case with the minimally threaded Tcl). There is dev effort
involved to make it work.
Jeff
As a work around you can have the parent wait for the child to exit,
using wait . Alternatively, you can also set up a SIGCHLD handler
in the parent to do a wait to clean up the child. Accepting/handling
the SIGCHLD signal will prevent zombies from being created..
To get the child to exit have it send itself a signal. I have tried
only the default SIGTERM see kill in tclx man page and
the child cleans up and the parent is able to capture its exit
status. I tried this on my linux box and it workd fine.
The only draw back is if you wanted to know the real exit status of
the child then you would have to come up with another means to
comunicate that to the parent. ( like write to a file or pipe or
socket ) .
Carl
#!/bin/sh
# the next line restarts using wish \
exec /opt/usr/bin/tclsh8.5 "$0" ${1+"$@"}
package require Tclx
# package require md5
# this is how to use signals in Tclx trap a signal(s) and call command
the signal is subst into %s befor eval
#signal trap { SIGUSR1} [list sigUser1 %S ]
#proc sigUser1 { signal } {
# puts "[pid] got signal $signal"
# kill [pid]
#}
proc bye { } {
# kill yourself and OS will clean up
kill [ pid ]
}
namespace eval test {
}
proc test::md5 {} {
set procId [fork];
if { $procId != 0 } {
puts "Exiting parent process pid=[pid]";
puts "[wait -untraced $procId ]"
return 0;
}
puts "Child process pid=[pid]"
# puts [::md5::md5 -hex -file /var/named/zones/in-addr.arpa/
0.249.24.in-addr.arpa]
# after child calls this it will not return parent will get
sigterm signal for exit status
bye
}
test::md5
puts "Parent out of test"
exit 0