tcsetpgrp problem

tcsetpgrp problem

Post by zahatort » Sun, 23 Jan 2000 04:00:00



        Hello,

Recently I've begun working with process management functions on Sun
sparc systems running SunOS 5.6. I have encountered a strange problem
with tcsetpgrp and have had trouble completely understanding tcsetpgrp
etc. For example, why would something like this (some error checking
omitted):
   pid_t cpid;
   int status;

   if ((cpid = fork()) < 0) /* die, omitted */;

   if (cpid == 0) {
      setpgid(0, 0);
      tcsetpgrp(STDIN_FILENO, getpgid((pid_t)0));

      execl("/bin/vi", "vi", (char *)NULL);
      perror("error");
      exit(errno);
   }

   /* in parent */
   setpgid(cpid, cpid);
   tcsetpgrp(STDIN_FILENO, cpid);

   wait(&status);
   tcsetpgrp(STDIN_FILENO, /* parent id.. */);

etc...
not work?

The problem seems to be resolved if I block the SIGTTOU signal in the
child.. however, if I leave the default behavior for SIGTTOU, the
process gets stopped.. and ctrl-z, ctrl-c etc.. cannot touch it.. might
anyone be able to explain this? And perhaps fill in any other details
about this call/this set of calls that might be useful? Thanks very
much!

-Z

* Sent from RemarQ http://www.remarq.com The Internet's Discussion Network *
The fastest and easiest way to search and participate in Usenet - Free!

 
 
 

tcsetpgrp problem

Post by Alex Verst » Mon, 24 Jan 2000 04:00:00



>    if ((cpid = fork()) < 0) /* die, omitted */;

>    if (cpid == 0) {
>       setpgid(0, 0);
>       tcsetpgrp(STDIN_FILENO, getpgid((pid_t)0));

>       execl("/bin/vi", "vi", (char *)NULL);
>       perror("error");
>       exit(errno);
>    }

Get rid of these lines.

Quote:>    /* in parent */
>    setpgid(cpid, cpid);
>    tcsetpgrp(STDIN_FILENO, cpid);

--end

Quote:>    wait(&status);
>    tcsetpgrp(STDIN_FILENO, /* parent id.. */);
> The problem seems to be resolved if I block the SIGTTOU signal in the
> child.. however, if I leave the default behavior for SIGTTOU, the
> process gets stopped.. and ctrl-z, ctrl-c etc.. cannot touch it.. might
> anyone be able to explain this? And perhaps fill in any other details
> about this call/this set of calls that might be useful? Thanks very
> much!

The child does not become the foreground process on the terminal,
so it receives SIGTTOU or SIGTTIN, whose default action is to
block.

I suggest that you look at the source for one of the shells that
does job control (bash, ash, etc).

--
Drive^H^Hnk safely!
Alex Verstak                 averstak at vt dot edu
1078 Ambler Johnston East             *ia Tech
Blacksburg, VA 24060-0022       Tel. (540) 232-1389

 
 
 

tcsetpgrp problem

Post by zahatort » Mon, 24 Jan 2000 04:00:00



Why do you say to get rid of those lines? Isn't there the possibility
for a race condition if they are not in there?



> >    if ((cpid = fork()) < 0) /* die, omitted */;

> >    if (cpid == 0) {
> >       setpgid(0, 0);
> >       tcsetpgrp(STDIN_FILENO, getpgid((pid_t)0));

> >       execl("/bin/vi", "vi", (char *)NULL);
> >       perror("error");
> >       exit(errno);
> >    }
> Get rid of these lines.
> >    /* in parent */
> >    setpgid(cpid, cpid);
> >    tcsetpgrp(STDIN_FILENO, cpid);
> --end
> >    wait(&status);
> >    tcsetpgrp(STDIN_FILENO, /* parent id.. */);

* Sent from RemarQ http://www.remarq.com The Internet's Discussion Network *
The fastest and easiest way to search and participate in Usenet - Free!
 
 
 

tcsetpgrp problem

Post by Alex Verst » Mon, 24 Jan 2000 04:00:00



> Why do you say to get rid of those lines? Isn't there the possibility
> for a race condition if they are not in there?

What race condition?  There are many process groups, but only
one controlling terminal per session.  tcsetpgrp will make one of
the groups foreground on that terminal.  You don't need to call
it two times.  It works on the terminal, not the process.
Similarly, don't mess with the child's process group in the parent.
It just ain't right.

Also, make sure that your session actually has a controlling
terminal.  This is the case when you run your program from the
command line, but you would need to open the terminal and hook
up to it via the TIOSCTTY ioctl in a daemon.

Random hints:

1. Once a group is suspended by ^Z, you need to send SIGCONT to
wake it up.

2. Shells usually set processes to ignore SIGTTOU and SIGTSTP.
This will mix the output of foreground and background jobs,
but avoid putting background jobs to sleep.

3. I do not claim to be comprehensive.  Again: read the source
of your favorite shell.

--
Drive^H^Hnk safely!
Alex Verstak                 averstak at vt dot edu
1078 Ambler Johnston East             *ia Tech
Blacksburg, VA 24060-0022       Tel. (540) 232-1389



> > >    if ((cpid = fork()) < 0) /* die, omitted */;

> > >    if (cpid == 0) {
> > >       setpgid(0, 0);
> > >       tcsetpgrp(STDIN_FILENO, getpgid((pid_t)0));

> > >       execl("/bin/vi", "vi", (char *)NULL);
> > >       perror("error");
> > >       exit(errno);
> > >    }
> > Get rid of these lines.
> > >    /* in parent */
> > >    setpgid(cpid, cpid);
> > >    tcsetpgrp(STDIN_FILENO, cpid);
> > --end
> > >    wait(&status);
> > >    tcsetpgrp(STDIN_FILENO, /* parent id.. */);

 
 
 

tcsetpgrp problem

Post by Andrew Giert » Tue, 25 Jan 2000 04:00:00



 >> Why do you say to get rid of those lines? Isn't there the possibility
 >> for a race condition if they are not in there?

 Alex> What race condition?

The usual race condition in this context is when you start multiple
processes in a single process group (for example, if spawning a
pipeline of processes as a single job). If you do setpgid() only in
the child, then it is possible for it not to have been reached by the
time you fork the second process, which can cause the setpgid() in
_that_ process to fail (as it specifies an invalid PGID). Doing the
setpgid() call in both the parent and child avoids this problem.

Doing the tcsetpgrp() call twice probably isn't necessary though.

 Alex> 2. Shells usually set processes to ignore SIGTTOU and SIGTSTP.

Nonsense. Shells do nothing of the kind, and absolutely should not.

Whether or not output is allowed from background processes is
controlled by the TOSTOP setting on the tty, allowing the user to
set it either way on the fly.

--
Andrew.

comp.unix.programmer FAQ: see <URL: http://www.erlenstar.demon.co.uk/unix/>
                           or <URL: http://www.whitefang.com/unix/>

 
 
 

tcsetpgrp problem

Post by Andrew Giert » Tue, 25 Jan 2000 04:00:00


 zahatorte> Recently I've begun working with process management
 zahatorte> functions on Sun sparc systems running SunOS 5.6. I have
 zahatorte> encountered a strange problem with tcsetpgrp and have had
 zahatorte> trouble completely understanding tcsetpgrp etc. For
 zahatorte> example, why would something like this (some error
 zahatorte> checking omitted):

 zahatorte>    pid_t cpid;
 zahatorte>    int status;

 zahatorte>    if ((cpid = fork()) < 0) /* die, omitted */;

 zahatorte>    if (cpid == 0) {
 zahatorte>       setpgid(0, 0);
 zahatorte>       tcsetpgrp(STDIN_FILENO, getpgid((pid_t)0));

It looks like SunOS 5.6, in common with a number of other systems,
delivers SIGTTOU to the process (unless blocked or ignored) when
tcsetpgrp is called from a non-foreground process. This seems to me
to be an exceptionally bogus thing to do (since virtually all uses
of tcsetpgrp are affected).

(The FAQ examples don't allow for this bogosity, since they were
mainly tested on a version of FreeBSD that seems to have suffered from
a brief attack of sanity. Both FreeBSD-current and FreeBSD-stable are
broken again in this respect. Looks like I need to revise the code...)

I don't find anything in the standards that justifies this. The nearest
I could find was (in SUSv2, under "Terminal Access Control"):

#   Certain calls that set terminal parameters are treated in the same
#   fashion as write(), except that TOSTOP is ignored; that is, the
#   effect is identical to that of terminal writes when TOSTOP is set
#   (see Local Modes , tcdrain(), tcflow(), tcflush(), tcsendbreak()
#   and tcsetattr()).

The descriptions of tcdrain, tcflow, etc., all mention that they cause
SIGTTOU if invoked from the background. No such comment is made in the
description of tcsetpgrp().

Everything seems to work if you replace calls to tcsetpgrp with calls
to a wrapper function that blocks SIGTTOU around the call.

--
Andrew.

comp.unix.programmer FAQ: see <URL: http://www.erlenstar.demon.co.uk/unix/>
                           or <URL: http://www.whitefang.com/unix/>

 
 
 

tcsetpgrp problem

Post by Alex Verst » Tue, 25 Jan 2000 04:00:00





>  >> Why do you say to get rid of those lines? Isn't there the possibility
>  >> for a race condition if they are not in there?

>  Alex> What race condition?

> The usual race condition in this context is when you start multiple
> processes in a single process group

[...]

This was not the case in the code.  Only one child was started
and then waited for.

Quote:>  Alex> 2. Shells usually set processes to ignore SIGTTOU and SIGTSTP.

> Nonsense. Shells do nothing of the kind, and absolutely should not.

> Whether or not output is allowed from background processes is
> controlled by the TOSTOP setting on the tty, allowing the user to
> set it either way on the fly.

I was wrong here.

--
Drive^H^Hnk safely!
Alex Verstak                 averstak at vt dot edu
1078 Ambler Johnston East             *ia Tech
Blacksburg, VA 24060-0022       Tel. (540) 232-1389

 
 
 

tcsetpgrp problem

Post by zahatort » Tue, 25 Jan 2000 04:00:00


        Yeah, sorry about that. Andrew Gierth did see what I was talking about
though. I really meant in the case in which you are forking other
children and popping them into a process group.

-Z



> This was not the case in the code.  Only one child was started
> and then waited for.

* Sent from RemarQ http://www.remarq.com The Internet's Discussion Network *
The fastest and easiest way to search and participate in Usenet - Free!
 
 
 

tcsetpgrp problem

Post by zahatort » Tue, 25 Jan 2000 04:00:00


        Thanks to everyone for the enlightenment!

-Z

* Sent from RemarQ http://www.remarq.com The Internet's Discussion Network *
The fastest and easiest way to search and participate in Usenet - Free!

 
 
 

tcsetpgrp problem

Post by Geoff Clar » Fri, 28 Jan 2000 04:00:00



>It looks like SunOS 5.6, in common with a number of other systems,
>delivers SIGTTOU to the process (unless blocked or ignored) when
>tcsetpgrp is called from a non-foreground process.

Not just "a number of other systems".  All POSIX.1-compliant systems
behave this way.  (All those that support job control, anyway).

Quote:>This seems to me
>to be an exceptionally bogus thing to do (since virtually all uses
>of tcsetpgrp are affected).

POSIX.1 considers tcsetpgrp() to be one of the control functions of
the terminal, along with tcsetattr(), tcdrain(), tcflush(), etc.
So the same rules about background processes and SIGTTOU apply.

Quote:>(The FAQ examples don't allow for this bogosity, since they were
>mainly tested on a version of FreeBSD that seems to have suffered from
>a brief attack of sanity. Both FreeBSD-current and FreeBSD-stable are
>broken again in this respect. Looks like I need to revise the code...)
>I don't find anything in the standards that justifies this. The nearest
>I could find was (in SUSv2, under "Terminal Access Control"):
>#   Certain calls that set terminal parameters are treated in the same
>#   fashion as write(), except that TOSTOP is ignored; that is, the
>#   effect is identical to that of terminal writes when TOSTOP is set
>#   (see Local Modes , tcdrain(), tcflow(), tcflush(), tcsendbreak()
>#   and tcsetattr()).

Looks like a problem with the way they have adopted section 7.2 of
POSIX.1 into the SUS style.  The beginning of 7.2 says that the SIGTTOU
stuff applies to all functions in that section (except where noted
otherwise - i.e. tcgetattr() and tcgetpgrp()).  SUSv2 doesn't group
functions in the same way, so the equivalent bit of text in the XBD spec
has the list of functions quoted above instead.  In POSIX.1, tcsetpgrp()
is in section 7.2 and so it should have been included in the list.

The Open Group's test suite for UNIX95/98 compliance does include tests
of this requirement for tcsetpgrp().

--


 
 
 

1. tcsetpgrp() problem

with several process groups all descendant of a single parent, can I
give tcsetpgrp() as the `fd' parameter a open("/dev/tty", O_RDWR) done
by the parent?

NOTE: its in a shell. My program doesn't output what it should, just
blocks...! while spawning the childs in foreground.

2. Newbie: Dynamic IP

3. xxgdb warning: tcsetpgrp failed in terminal_inferior: not a typewrite

4. Problems with proxyarp/PPP

5. xxgdb [tcsetpgrp failed in terminal_inferior: Not a typewriter]

6. Allowing any user to kill a process

7. tcsetpgrp() bug?

8. Stealth Pro (S3 928 chipset)?

9. tcsetpgrp error

10. question about tcsetpgrp()

11. tcsetpgrp() & SIGTTOU

12. Help: xxgdb: [tcsetpgrp failed in terminal_inferior: Not a typewriter]

13. gdb error: [tcsetpgrp failed in terminal_inferior: Not a typewriter] in xterm and emacs