I need to simulate a broken pipe scenario between a Tcl script and a
'C program..
For which i have written the following code
C program 'ctcl.c'
#include<stdio.h>
#include<string.h>
int main()
{
int i; char c[30],tmp[50];;
printf("Reading...\n");
fflush(stdout);
gets(c);
sprintf(tmp,"kill -9 %d",getpid());
printf("Killing....");
system(tmp);
printf("String written is :%s \n",c);
fflush(stdout);
return 0;
}
The Tcl Script is 'ctcl.tcl'
#!/usr/add-on/exptools/bin/tclsh
set fd [open "|./ctcl" r+]
puts "......................."
gets $fd tmp1
puts "#######################"
puts "tmp1 = $tmp1"
set stat 0
set tmp2 "Default value... "
if { ![catch { puts $fd "This is test.." } res]} {
if { ![catch { flush $fd } res] } {
if { ![catch { gets $fd tmp2} res ] } {
set stat 1
} else { puts "Error 'gets' from pipe : $res" }
} else { puts "Error 'flush' from pipe:$res " }
} else { puts "Error 'puts' from pipe:$res " }
if { $stat == 1 } {
puts "Success......:$tmp2 :)"
} else {
puts "Failure......:$tmp2 :("
}
Both these scripts reside in the same directory.
I have created an executable for 'C' program and then run the Tcl
script from command line.
o/p is as follows:-
.......................
#######################
tmp1 = Reading...
Success......: :)
What i was assuming about broken pipes is when two process are
communicating and when a pipe is established b/w both of them.. here
the case is tcl script communicating with a 'C' executable, and
suddenly one of the entity comes down.. here in this case i am killing
the 'C' process by extracting its pid.
Tcl script must report a broken pipe error as the pipe b/w both of
them is broken due to the 'C' process being killed.
But here my Tcl script is not catching that error.
Instead it is saying it was succesfull.. bt reading nothing from the
stream..
This is not my desired output. I need to simulate the error condition
of broken pipe..
Could any body help me modifying my program to simulate the error
scenario..
Thanks in advance,
Ravikanth
uwe
I have modifyed my 'C' program as below.. but still i find the same
response..
#include<stdio.h>
#include<signal.h>
#include<string.h>
int main()
{
int i; char c[30],tmp[50];;
printf("Reading...\n");
fflush(stdout);
gets(c);
printf("Killing using SIGPIPE...\n");
kill(getpid(),SIGPIPE);
printf("String written is :%s \n",c);
fflush(stdout);
return 0;
}
But the output of the Tcl script remains the same...No change in the
response..
<sigpipe.tcl>
#!/usr/bin/tclsh
package require Tclx
signal trap SIGPIPE {puts SIGPIPE}
set pfd [ open "|./downstream.tcl" w ]
fconfigure $pfd -buffering line
while 1 {
puts $pfd hallo
puts hallo
after 500 set cont 1
vwait cont
}
<downstream.tcl>
#!/usr/bin/tclsh
package require Tclx
close stdin
puts stderr downstream:ready
after 5000 set cont
vwait cont
puts downstream:exit
exit
uwe
The default action for SIGPIPE is to die.
see "man 7 signal" which gives all signames
and default behaviour.
uwe
Hi uwe,
I couldn't understand the code you have given.
I am new to Tcl & UNIX.
Could you please explain me what your program does.
Thanks in advance,
Raviknath
To show the action we have to change this
to something that gives some diagnostic.
In tcl having a "|" as the first element of a
filename to open will create a process with
the rest of the filename as a command line
and hang it on a pipe connected to stdin for write,
stdout for read or both for read/write.
write both scripts to the same directory.
then
chmod u+x sigpipe.tcl downstream.tcl
<file sigpipe.tcl>
#!/usr/bin/tclsh
# get the Tclx extension for signal handling
package require Tclx
# change signal action for SIGPIPE:
# from the default "terminate process" to execute
# the script "puts SIGPIPE"
signal trap SIGPIPE {puts SIGPIPE}
# open a writing pipe to a process that executes
# the second script:
set pfd [ open "|./downstream.tcl" w ]
# see that each line get written to this pipe
# immediately ( and not in the 4k blocks that
# the default blocking size for nontty files )
fconfigure $pfd -buffering line
# do an endless loop:
while 1 {
# write "hallo" to the previously opened pipe
puts $pfd hallo
# write the same to stdout ( to see what happens )
puts hallo
# wait 500ms with the eventloop active
after 500 set cont 1
vwait cont
}
the second script
<file downstream.tcl>
#!/usr/bin/tclsh
# from copying sigpipe.tcl ;-)
package require Tclx
# close stdin to show SIGPIPE effects
# the upstream process has no "taker" now
close stdin
# debug : setup done, waiting.
puts stderr downstream:ready
# wait for 5 seconds while the eventloop is active
after 5000 set cont
vwait cont
# debug : exiting
puts downstream:exit
# and killing the process via exit
# actually the same would happen without the exit
exit
uwe
This is the expected behaviour. 'gets' simply gets EOF.
Only when you 'close' the channel, you will see the non-zero exit
status of the C-Program due to getting killed.
| This is not my desired output. I need to simulate the error
| condition of broken pipe..
Simply close that channel, and write in the exec'd program.
t.c
#include <stdio.h>
int main() {
if (printf("hello world\n") < 0) {
perror("printf");
}
if (EOF == fflush(stdout)) {
perror("fflush");
}
return 0;
}
cc -o t t.c
TCL:
tclsh% close [open "|./t" r]
=> child killed: write on pipe with no readers
tclsh% set errorCode
CHILDKILLED 25296 SIGPIPE {write on pipe with no readers}
Note that on Windows things behave differently: programs are not
signalled there, but simply get an EPIPE (or the windows equivalent)
error in the fflush().
$ cl -nologo -o t t.c
t.c
$ tclsh
% exec ./t.exe
hello world
% close [open "|./t.exe" r]
fflush: Invalid argument
% set errorCode
NONE
HTH
R'
Thank you all,
I understood the concept of pipe clearly from the discussion above..
My program is working fine now.