From nobody@FreeBSD.org  Fri Sep  7 23:01:54 2012
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52])
	by hub.freebsd.org (Postfix) with ESMTP id E68F5106566B
	for <freebsd-gnats-submit@FreeBSD.org>; Fri,  7 Sep 2012 23:01:54 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22])
	by mx1.freebsd.org (Postfix) with ESMTP id C6BE18FC1A
	for <freebsd-gnats-submit@FreeBSD.org>; Fri,  7 Sep 2012 23:01:54 +0000 (UTC)
Received: from red.freebsd.org (localhost [127.0.0.1])
	by red.freebsd.org (8.14.5/8.14.5) with ESMTP id q87N1snG018748
	for <freebsd-gnats-submit@FreeBSD.org>; Fri, 7 Sep 2012 23:01:54 GMT
	(envelope-from nobody@red.freebsd.org)
Received: (from nobody@localhost)
	by red.freebsd.org (8.14.5/8.14.5/Submit) id q87N1sJi018747;
	Fri, 7 Sep 2012 23:01:54 GMT
	(envelope-from nobody)
Message-Id: <201209072301.q87N1sJi018747@red.freebsd.org>
Date: Fri, 7 Sep 2012 23:01:54 GMT
From: Garrett Cooper <yaneurabeya@gmail.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: [sh] Hitting ^Z doesn't suspend jobs like expected
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         171427
>Category:       bin
>Synopsis:       sh(1): Hitting ^Z doesn't suspend jobs like expected
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Sep 07 23:10:01 UTC 2012
>Closed-Date:    
>Last-Modified:  Sun Feb 03 22:30:53 UTC 2013
>Originator:     Garrett Cooper
>Release:        7.4-RELEASE/9.1-RELEASE
>Organization:
EMC Isilon
>Environment:
FreeBSD  7.4-STABLE FreeBSD 7.4-STABLE #0: Fri Aug 24 15:41:28 UTC 2012     root@bf049.west.isilon.com:/usr/obj/mnt/freebsd/stable/7/sys/ISI-GENERIC  amd64

FreeBSD wf048.west.isilon.com 9.1-RC1 FreeBSD 9.1-RC1 #0: Fri Aug 17 02:18:40 PDT 2012     root@wf048.west.isilon.com:/usr/obj/mnt/freebsd/releng/9.1/sys/ISI-GENERIC  amd64
>Description:
Running some netperf tests in a while loop like so under /bin/sh, I'm running into
cases where the while loop continues to loop, even after I mash on ^C (which I would expect to kill netperf eventually -- works on 9.1-RC1, but not 7.4-STABLE) or ^Z (I would expect job control to stop spawning jobs, but it doesn't in either version):

bf049# exec sh


wf048# exec sh
$ while : ; do netperf -cCjt TCP_STREAM -H 10.7.187.52 -l 10 -- -D; done

..

^ZTCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.56 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo
^ZTCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.56 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo
^ZTCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.56 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo
^ZTCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.56 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo
^ZTCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.56 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo
^ZTCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.56 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo
^ZTCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.56 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo
^ZTCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.56 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo
^ZTCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.56 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo
^ZTCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.56 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo
^ZTCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.56 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo
^ZTCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.56 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo
^ZTCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.56 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo
^ZTCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.56 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo
^ZTCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.56 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo
^ZTCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.56 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo
^ZTCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.56 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo
^ZTCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.56 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo
^ZTCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.56 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo
^ZTCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.56 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo
Recv   Send    Send                          Utilization       Service Demand
Socket Socket  Message  Elapsed              Send     Recv     Send    Recv
Size   Size    Size     Time     Throughput  local    remote   local   remote
bytes  bytes   bytes    secs.    10^6bits/s  % C      % C      us/KB   us/KB

 65536  32768  32768    10.01       810.28   8.05     7.52     3.254   6.080  
TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.56 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo

Bash on the other hand does stop the code snippet:

$ while : ; do netperf -cCjt TCP_STREAM -H 10.7.187.52 -l 10 -- -D; done
TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.7.187.52 () port 0 AF_INET : nodelay : histogram : interval : dirty data : demo
^Z
[1]+  Stopped                 netperf -cCjt TCP_STREAM -H 10.7.187.52 -l 10 -- -D

The expected behavior isn't documented in sh(1) and in the opengroup sh(1) manpage.
>How-To-Repeat:
exec sh
while : ; do netperf -cCjt TCP_STREAM -H $IP -l 10 -- -D; done

You could probably replace the second command (to netperf) with something that blocks.
>Fix:


>Release-Note:
>Audit-Trail:

From: Jilles Tjoelker <jilles@stack.nl>
To: bug-followup@FreeBSD.org, yanegomi@gmail.com
Cc:  
Subject: Re: bin/171427: sh(1): Hitting ^Z doesn&#39;t suspend jobs like
 expected
Date: Sun, 16 Sep 2012 23:11:33 +0200

 > [while : ; do netperf -cCjt TCP_STREAM -H 10.7.187.52 -l 10 -- -D; done
 > works strangely with ^C/^Z]
 
 For the case with ^C, I indeed deliberately fixed that for 9.0.
 
 For the case with ^Z, this is indeed a caveat that is complained about
 more frequently, and different shells handle it differently because
 POSIX leaves it vague.
 
 POSIX discusses suspending jobs (process groups), but a sequence or
 while loop is not a job.
 
 One workaround is to make it a job by placing parentheses around the
 loop. With most shells, this creates a new process group and job that
 can be suspended normally. An exception is ksh93 which attempts to
 execute the subshell in the same process; I do not like this but I think
 POSIX permits it (and in non-interactive or no-job-control mode it is
 fine to execute a subshell in that way).
 
 What sh does is return status 146 (128+SIGTSTP) and continue (so while
 netperf; do :; done will abort if ^Z'ed).
 
 What bash appears to do is break loops if something was ^Z'ed.
 
 What zsh appears to do is fork and continue the loop after the suspended
 process terminates. However, it gets $? wrong. Also, it needs a fair bit
 of code and changes to the shell environment after the suspension do not
 affect the parent.
 
 -- 
 Jilles Tjoelker
>Unformatted:
