Re: [bug-bash] Named fifo's causing hanging bash scripts
On Mon, Jan 12, 2015 at 11:50:56AM -0500, Chet Ramey wrote: > On 1/12/15 9:55 AM, wer...@linux-8jdz.site wrote: > > Configuration Information [Automatically generated, do not change]: > > Machine: x86_64 > > OS: linux-gnu > > Compiler: gcc -I/home/abuild/rpmbuild/BUILD/bash-4.3 > > -L/home/abuild/rpmbuild/BUILD/bash-4.3/../readline-6.3 > > Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' > > -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-suse-linux-gnu' > > -DCONF_VENDOR='suse' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' > > -DSHELL -DHAVE_CONFIG_H -I. -I. -I./include -I./lib -fmessage-length=0 > > -grecord-gcc-switches -O2 -Wall -D_FORTIFY_SOURCE=2 -fstack-protector > > -funwind-tables -fasynchronous-unwind-tables -g -D_GNU_SOURCE > > -DRECYCLES_PIDS -Wall -g -Wuninitialized -Wextra -Wno-unprototyped-calls > > -Wno-switch-enum -Wno-unused-variable -Wno-unused-parameter > > -Wno-parentheses -ftree-loop-linear -pipe -DBNC382214=0 > > -DMUST_UNBLOCK_CHLD=1 -DIMPORT_FUNCTIONS_DEF=0 -fprofile-use > > uname output: Linux d136 3.15.0-rc7-3-desktop #1 SMP PREEMPT Wed May 28 > > 15:39:51 UTC 2014 (96f5b60) x86_64 x86_64 x86_64 GNU/Linux > > Machine Type: x86_64-suse-linux-gnu > > > > Bash Version: 4.3 > > Patch Level: 33 > > Release Status: release > > > > Description: > > Named fifo's causing hanging bash scripts like > > > > while IFS="|" read a b c ; do > > [shell code] > > done < <(shell code) > > > > can cause random hangs of the bash.An strace shows that the bash > > stays in wait4() > > And when you attach to one of the hanging bash processes using gdb, what > does the stack traceback look like? Yes (and sorry for the wrong email address as this was done on a clean virtual sysstem) there are two hanging bash processes together with the find command: werner 19062 0.8 0.0 11864 2868 ttyS0S+ 10:21 0:00 bash -x /tmp/brp-25-symlink werner 19063 0.0 0.0 11860 1920 ttyS0S+ 10:21 0:00 bash -x /tmp/brp-25-symlink werner 19064 0.2 0.0 16684 2516 ttyS0S+ 10:21 0:00 find . -type l -printf %p|%h|%l n the gdb -p 19062 and gdb -p 19063 show (gdb) bt #0 0x7f530818a65c in waitpid () from /lib64/libc.so.6 #1 0x0042b233 in waitchld (block=block@entry=1, wpid=19175) at jobs.c:3235 #2 0x0042c6da in wait_for (pid=pid@entry=19175) at jobs.c:2496 #3 0x004302e1 in command_substitute (string=string@entry=0x22ccd80 "dirname_int $link", quoted=quoted@entry=1) at subst.c:5534 #4 0x004704db in param_expand (string=string@entry=0x22cc8d0 "$(dirname_int $link)", sindex=sindex@entry=0x7fff39f90ef0, quoted=quoted@entry=1, expanded_something=expanded_something@entry=0x0, contains_dollar_at=contains_dollar_at@entry=0x7fff39f90f20, quoted_dollar_at_p=quoted_dollar_at_p@entry=0x7fff39f90f00, had_quoted_null_p=had_quoted_null_p@entry=0x7fff39f90f10, pflags=0) at subst.c:7970 #5 0x00471123 in expand_word_internal (word=word@entry=0x22cc1a0, quoted=quoted@entry=1, isexp=isexp@entry=0, contains_dollar_at=contains_dollar_at@entry=0x7fff39f91080, expanded_something=expanded_something@entry=0x0) at subst.c:8393 #6 0x0047130f in expand_word_internal (word=word@entry=0x7fff39f91120, quoted=quoted@entry=0, isexp=isexp@entry=0, contains_dollar_at=contains_dollar_at@entry=0x0, expanded_something=expanded_something@entry=0x0) at subst.c:8548 #7 0x00472daf in call_expand_word_internal (e=0x0, c=0x0, i=0, q=0, w=0x7fff39f91120) at subst.c:3299 #8 expand_string_assignment (string=string@entry=0x22cb159 "\"$(dirname_int $link)\"", quoted=quoted@entry=0) at subst.c:3387 #9 0x00473110 in expand_string_if_necessary (string=, string@entry=0x22cb159 "\"$(dirname_int $link)\"", quoted=quoted@entry=0, func=func@entry=0x472d50 ) at subst.c:3092 #10 0x00473349 in do_assignment_internal (word=0x22cbbe0, expand=1) at subst.c:2823 #11 0x0047776a in do_word_assignment (flags=, word=) at subst.c:2912 #12 expand_word_list_internal (eflags=, list=) at subst.c:9669 #13 expand_words (list=0x) at subst.c:9280 #14 0x00461093 in execute_simple_command (simple_command=0x22c1ed0, pipe_in=pipe_in@entry=-1, pipe_out=pipe_out@entry=-1, async=async@entry=0, fds_to_close=fds_to_close@entry=0x22ccce0) at execute_cmd.c:4001 #15 0x004629fc in execute_command_internal (command=0x22bc9e0, asynchronous=asynchronous@entry=0, pipe_in=pipe_in@entry=-1, pipe_out=pipe_out@entry=-1, fds_to_close=fds_to_close@entry=0x22ccce0) at execute_cmd.c:788 #16 0x00462ba6 in execute_connection (fds_to_close=0x22ccce0, pipe_out=-1, pipe_in=-1, asynchronous=0, command=0x22c0bd0) at execute_cmd.c:2497 #17 execute_command_internal (command=command@entry=0x22c0bd0, asynchronous=asynchronous@entry=0, pipe_in=pipe_in@entry=-1, pipe_out=p
CTL-z bug?
Hi, When I run a for loop in bash, then pausing it with CTL-z, then restarting it with fg, the for loop just stops. I don't think this was the behaviour until recently, and I don't find it a correct behaviour, according to the meaning of the CTL-z "suspend" (https://en.wikipedia.org/wiki/Control-Z). Is there any explanation to this behaviour? I'm using: GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu) Under: Ubuntu 14.10 (utopic) Cheers GM
Re: CTL-z bug?
On 1/13/15 11:37 AM, Guillaume MULLER wrote: > Hi, > > When I run a for loop in bash, then pausing it with CTL-z, then restarting > it with fg, the for loop just stops. I don't think this was the behaviour > until recently, and I don't find it a correct behaviour, according to the > meaning of the CTL-z "suspend" (https://en.wikipedia.org/wiki/Control-Z). > Is there any explanation to this behaviour? SIGTSTP works at the process or job level, not the shell compound command level. When you stop the current job with ^Z, the shell has a choice to make: continue with the loop, or break out of it. There isn't a handle to suspend the entire loop's execution, since it doesn't execute in a separate process. Bash chooses to break the loop, and has done so for a very long time (at least back to bash-3.0, which was released ten years ago, at which point I stopped looking). Chet -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
Re: CTL-z bug?
I think that the following text from the zshell's code is an interesting read on the subject: TL;DR: Another strategy is to "migrate" the while-loop to a child process the moment that you hit ^Z, but, this is really hard (maybe impossible?) to do correctly. (From Src/exec.c) /* * [...] * * In most shells, if you do something like: * * cat foo | while read a; do grep $a bar; done * * the shell forks and executes the loop in the sub-shell thus created. * In zsh this traditionally executes the loop in the current shell, which * is nice to have if the loop does something to change the shell, like * setting parameters or calling builtins. * Putting the loop in a sub-shell makes life easy, because the shell only * has to put it into the job-structure and then treats it as a normal * process. Suspending and interrupting is no problem then. * Some years ago, zsh either couldn't suspend such things at all, or * it got really messed up when users tried to do it. As a solution, we * implemented the list_pipe-stuff, which has since then become a reason * for many nightmares. * Pipelines like the one above are executed by the functions in this file * which call each other (and sometimes recursively). The one above, for * example would lead to a function call stack roughly like: * * execlist->execpline->execcmd->execwhile->execlist->execpline * * (when waiting for the grep, ignoring execpline2 for now). At this time, * zsh has built two job-table entries for it: one for the cat and one for * the grep. If the user hits ^Z at this point (and jobbing is used), the * shell is notified that the grep was suspended. The list_pipe flag is * used to tell the execpline where it was waiting that it was in a pipeline * with a shell construct at the end (which may also be a shell function or * several other things). When zsh sees the suspended grep, it forks to let * the sub-shell execute the rest of the while loop. The parent shell walks * up in the function call stack to the first execpline. There it has to find * out that it has just forked and then has to add information about the sub- * shell (its pid and the text for it) in the job entry of the cat. The pid * is passed down in the list_pipe_pid variable. * But there is a problem: the suspended grep is a child of the parent shell * and can't be adopted by the sub-shell. So the parent shell also has to * keep the information about this process (more precisely: this pipeline) * by keeping the job table entry it created for it. The fact that there * are two jobs which have to be treated together is remembered by setting * the STAT_SUPERJOB flag in the entry for the cat-job (which now also * contains a process-entry for the whole loop -- the sub-shell) and by * setting STAT_SUBJOB in the job of the grep-job. With that we can keep * sub-jobs from being displayed and we can handle an fg/bg on the super- * job correctly. When the super-job is continued, the shell also wakes up * the sub-job. But then, the grep will exit sometime. Now the parent shell * has to remember not to try to wake it up again (in case of another ^Z). * It also has to wake up the sub-shell (which suspended itself immediately * after creation), so that the rest of the loop is executed by it. * But there is more: when the sub-shell is created, the cat may already * have exited, so we can't put the sub-shell in the process group of it. * In this case, we put the sub-shell in the process group of the parent * shell and in any case, the sub-shell has to put all commands executed * by it into its own process group, because only this way the parent * shell can control them since it only knows the process group of the sub- * shell. Of course, this information is also important when putting a job * in the foreground, where we have to attach its process group to the * controlling tty. * All this is made more difficult because we have to handle return values * correctly. If the grep is signaled, its exit status has to be propagated * back to the parent shell which needs it to set the exit status of the * super-job. And of course, when the grep is signaled (including ^C), the * loop has to be stopped, etc. * The code for all this is distributed over three files (exec.c, jobs.c, * and signals.c) and none of them is a simple one. So, all in all, there * may still be bugs, but considering the complexity (with race conditions, * signal handling, and all that), this should probably be expected. */ I hope this explains why bash does what it does.