tags:

views:

56

answers:

2

When launching tclsh and typing this:

close [open "|tclsh" w]

it works fine.

But, when in ~/.tclshrc you have package require Tk, the same line makes tclsh to HANG!

The same issue is with all GUI packages like Tk, Itk, Img, Iwidgets, however with not GUI packages like Itcl, it worsk fine.

How can I fix this issue? The point is to make tclsh not to hang, when typing close [open "|tclsh" w] with package require Tk in ~/.tclshrc.

The same issue is with wish. close [open "|wish" w] makes wish to HANG (with an empty ~/.wishrc file)!

I got this issue on both 32 and 64 bit CentOS. I have the following versions of packages: tcl-8.5.8, tk-8.5.8, img-1.3, itcl-3.4.b1, itk-3.3, iwidgets-4.0.1.

+1  A: 

My thought would be that it's waiting for wish to finish running, as per the man page:

If channelId is a blocking channel for a command pipeline then close waits for the child processes to complete.

Since wish enters an infinite loop (the event loop) and never exits, the close command will hang. Along the same lines, [package require Tk] (I believe) starts the event loop, so will cause the same behavior.

I'll admit though that it's loading .tclshrc at all, since

If there exists a file .tclshrc (or tclshrc.tcl on the Windows platforms) in the home directory of the user, interactive tclsh evaluates the file as a Tcl script just before reading the first command from standard input.

It seems odd to me that [open "|tclsh" w] winds up in an interactive shell.

As a side note, [pacakge require Tk] seems like a really strange thing to do in .tclshrc. In theory, you won't always want Tk (the window and event loop) when running Tcl (ie, command line only apps)... and, when you do want it, you know you do. To each their own, I suppose, it just seems odd to me.

RHSeeger
Ok, lets consider the case with wish. close [open "|wish" w] makes wish to hang. As I understood form your answer, you say that there is no way to fix this issue. Is it so ?
Vahagn
Just have the script in question call exit. Since it can't rely on "reaching the end of the script" to cause the program to end (since that now sends it into the global event loop), you need to call [exit] to make that happen.
RHSeeger
The .tclshrc is only read in interactive sessions; if there's a script passed in to run, tclsh doesn't touch the user's rc files. Wish is the same, except with the .wishrc file of course. (And for the record, I never define anything in either file.)
Donal Fellows
That's why I said it seemed strange to me that it was reading the .tclshrc. Either it's a bug somewhere that it's being read, or the poster is incorrect about it being read.
RHSeeger
@Donal Fellows - It seems to me that the best solution is to manually send the exit command to the pipe. Thanks for your answer.
Vahagn
+1  A: 

Tcl applications mostly exit when they have finished their script, whether or not it is provided interactively. However the Tk package changes things around so that when the end of the script is reached, it instead goes into a loop handling events. If you're relying on an end-of-file causing things to exit, that's going to look a lot like a hang, but really it's just waiting properly for the GUI app to finish (so it can report the exit status of the subprocess).

The fix is to make a channel-readable event handler for stdin in the subprocess. There's a few ways to do this in detail, but here's a simple one that can go at the end of the bulk of code that you normally send:

proc ReadFromStdin {} {
    if {[gets stdin line] >= 0} {
        uplevel "#0" $line
    } elseif {[eof stdin]} {
        exit
    } else {
        # Partial read; try later when rest of data available
    }
}
fileevent stdin readable ReadFromStdin

This assumes that each line is a full executable command; that might not be true, of course, but writing the code to use info complete to compose lines is less clear and possibly unnecessary here. (You know what you're actually sending better than I…)

Donal Fellows