I don't understand how the child gets placed in the background - Unix

This is a discussion on I don't understand how the child gets placed in the background - Unix ; The following code is from figure 9.11 in the book "Advanced Programming in the Unix Environment" by Stevens and Rago. #include #include #include #include #include static void sig_hup(int signo) { printf("SIGHUP received from pid = %d\n", getpid()); } static void ...

+ Reply to Thread
Results 1 to 10 of 10

Thread: I don't understand how the child gets placed in the background

  1. I don't understand how the child gets placed in the background

    The following code is from figure 9.11 in the book "Advanced
    Programming in the Unix Environment" by Stevens and Rago.

    #include
    #include
    #include
    #include
    #include

    static void
    sig_hup(int signo)
    {
    printf("SIGHUP received from pid = %d\n", getpid());
    }

    static void
    pr_ids(char *name)
    {
    printf("%s: pid = %d, ppid = %d, pgrp = %d, tgrp = %d\n",
    name, getpid(), getppid(), getpgrp(),
    tcgetpgrp(STDIN_FILENO));
    fflush(stdout);
    }

    int main(void)
    {
    char c;
    pid_t pid;

    pr_ids("parent");
    if ((pid = fork()) < 0) {
    fprintf(stderr, "fork error\n");
    exit(1);
    } else if (pid > 0) {
    sleep(5);
    exit(0);
    } else {
    pr_ids("child");
    signal(SIGHUP, sig_hup);
    kill(getpid(), SIGTSTP);
    pr_ids("child");
    if (read(STDIN_FILENO, &c, 1) != 1)
    printf("read error from controlling TTY, errno = %d\n", errno);
    }
    exit(0);
    }

    When I run it (under zsh), I get the following..

    > gcc -g job.c -o job
    > ./job

    parent: pid = 14823, ppid = 12446, pgrp = 14823, tgrp = 14823
    child: pid = 4693, ppid = 14823, pgrp = 14823, tgrp = 14823
    > SIGHUP received from pid = 4693

    child: pid = 4693, ppid = 1, pgrp = 14823, tgrp = 12446
    read error from controlling TTY, errno = 5

    I understand that parent is executed as a foreground job. The part I
    don't understand is how the child is placed in the background process
    group when the parent terminates. What I mean is before SIGHUP, it
    looks like both the parent and child are in same process group and
    hence the same foreground group, right? If that is the case, how does
    the child process get moved to the background when the parent
    terminates?

  2. Re: I don't understand how the child gets placed in the background

    On Tue, 09 Sep 2008 06:10:25 -0700, K-mart Cashier wrote:

    > The following code is from figure 9.11 in the book "Advanced Programming
    > in the Unix Environment" by Stevens and Rago.
    >
    > #include
    > #include
    > #include
    > #include
    > #include
    >
    > static void
    > sig_hup(int signo)
    > {
    > printf("SIGHUP received from pid = %d\n", getpid());
    > }
    >
    > static void
    > pr_ids(char *name)
    > {
    > printf("%s: pid = %d, ppid = %d, pgrp = %d, tgrp = %d\n",
    > name, getpid(), getppid(), getpgrp(),
    > tcgetpgrp(STDIN_FILENO));
    > fflush(stdout);
    > }
    >
    > int main(void)
    > {
    > char c;
    > pid_t pid;
    >
    > pr_ids("parent");
    > if ((pid = fork()) < 0) {
    > fprintf(stderr, "fork error\n");
    > exit(1);
    > } else if (pid > 0) {
    > sleep(5);
    > exit(0);
    > } else {
    > pr_ids("child");
    > signal(SIGHUP, sig_hup);
    > kill(getpid(), SIGTSTP);
    > pr_ids("child");
    > if (read(STDIN_FILENO, &c, 1) != 1)
    > printf("read error from controlling TTY, errno = %d\n", errno);
    > }
    > exit(0);
    > }


    This is all wrong; it doesn't do what it prints out that it is doing.

    1) The function sig_hup() handler prints the process id of the process
    that receives the signal, not the one that sent it.

    2) The sig_hup() handler is only installed in the child after it has
    forked.

    3) The child sends the SIGSTP signal to *itself*, and it stops and is
    moved to the background by the shell.

    4) The parent waits five seconds and exits.

    5) The child remains stopped, waiting for SIGCONT.

    Send it SIGCONT (see `man 1 kill`).

    Now it will try to read from the terminal, and when it succeeds, exit.

    While it is waiting to read, you could send it SIGHUP from another
    terminal, and it would print its own pid.

    My advice: either you have typed it in wrong*, or you have
    mis-described what it is supposed to do, or perhaps that book just
    belongs in the bin!

    * have you typed getpid() where it says getppid()?

    HTH
    viza

  3. Re: I don't understand how the child gets placed in the background

    On Tue, 09 Sep 2008 15:34:36 +0000, viza wrote:
    > On Tue, 09 Sep 2008 06:10:25 -0700, K-mart Cashier wrote:


    >> static void
    >> sig_hup(int signo)
    >> {
    >> printf("SIGHUP received from pid = %d\n", getpid());
    >> }


    PS: signal handlers aren't allowed to call library functions.


  4. Re: I don't understand how the child gets placed in the background

    On Sep 9, 8:34*am, viza
    wrote:
    > On Tue, 09 Sep 2008 06:10:25 -0700, K-mart Cashier wrote:
    > > The following code is from figure 9.11 in the book "Advanced Programming
    > > in the Unix Environment" by Stevens and Rago.

    >
    > > #include
    > > #include
    > > #include
    > > #include
    > > #include

    >
    > > static void
    > > sig_hup(int signo)
    > > {
    > > * printf("SIGHUP received from pid = %d\n", getpid());
    > > }

    >
    > > static void
    > > pr_ids(char *name)
    > > {
    > > * printf("%s: pid = %d, ppid = %d, pgrp = %d, tgrp = %d\n",
    > > * * * * *name, getpid(), getppid(), getpgrp(),
    > > tcgetpgrp(STDIN_FILENO));
    > > * fflush(stdout);
    > > }

    >
    > > int main(void)
    > > {
    > > * char c;
    > > * pid_t pid;

    >
    > > * pr_ids("parent");
    > > * if ((pid = fork()) < 0) {
    > > * * fprintf(stderr, "fork error\n");
    > > * * exit(1);
    > > * } else if (pid > 0) {
    > > * * sleep(5);
    > > * * exit(0);
    > > * } else {
    > > * * pr_ids("child");
    > > * * signal(SIGHUP, sig_hup);
    > > * * kill(getpid(), SIGTSTP);
    > > * * pr_ids("child");
    > > * * if (read(STDIN_FILENO, &c, 1) != 1)
    > > * * * printf("read error from controlling TTY, errno = %d\n", errno);
    > > * }
    > > * exit(0);
    > > }

    >
    > This is all wrong; it doesn't do what it prints out that it is doing.
    >
    > 1) The function sig_hup() handler prints the process id of the process
    > that receives the signal, not the one that sent it.
    >
    > 2) The sig_hup() handler is only installed in the child after it has *
    > forked.
    >
    > 3) The child sends the SIGSTP signal to *itself*, and it stops and is
    > moved to the background by the shell.
    >
    > 4) The parent waits five seconds and exits.
    >
    > 5) The child remains stopped, waiting for SIGCONT.
    >
    > Send it SIGCONT (see `man 1 kill`).
    >
    > Now it will try to read from the terminal, and when it succeeds, exit.
    >
    > While it is waiting to read, you could send it SIGHUP from another
    > terminal, and it would print its own pid.
    >
    > My advice: either you have typed it in wrong*, or you have
    > mis-described what it is supposed to do, or perhaps that book just
    > belongs in the bin!
    >
    > * have you typed getpid() where it says getppid()?
    >
    > HTH
    > viza- Hide quoted text -
    >
    > - Show quoted text -


    I don't think there was a typo. However, I can check when I get home.

  5. Re: I don't understand how the child gets placed in the background

    On Sep 9, 8:36*am, viza
    wrote:
    > On Tue, 09 Sep 2008 15:34:36 +0000, viza wrote:
    > > On Tue, 09 Sep 2008 06:10:25 -0700, K-mart Cashier wrote:
    > >> static void
    > >> sig_hup(int signo)
    > >> {
    > >> * printf("SIGHUP received from pid = %d\n", getpid());
    > >> }

    >
    > PS: signal handlers aren't allowed to call library functions.


    I know, but the Stevens book does use printf() in the signal handlers.

  6. Re: I don't understand how the child gets placed in the background

    viza writes:

    > On Tue, 09 Sep 2008 15:34:36 +0000, viza wrote:
    >> On Tue, 09 Sep 2008 06:10:25 -0700, K-mart Cashier wrote:

    >
    >>> static void
    >>> sig_hup(int signo)
    >>> {
    >>> printf("SIGHUP received from pid = %d\n", getpid());
    >>> }

    >
    > PS: signal handlers aren't allowed to call library functions.


    As far as ANSI C goes, you're right. For POSIX, some functions are
    documented as being reentrant and therefore are safe to call from a
    signal handler. However, printf is not one of them. (Some systems,
    of course, may supply a reentrant version.)

  7. Re: I don't understand how the child gets placed in the background

    viza writes:
    >On Tue, 09 Sep 2008 15:34:36 +0000, viza wrote:
    >> On Tue, 09 Sep 2008 06:10:25 -0700, K-mart Cashier wrote:

    >
    >>> static void
    >>> sig_hup(int signo)
    >>> {
    >>> printf("SIGHUP received from pid = %d\n", getpid());
    >>> }

    >
    >PS: signal handlers aren't allowed to call library functions.
    >


    The above postscript is incorrect. POSIX defines a set of
    async-signal-safe functions, and 'getpid' is in that list. It is
    perfectly acceptable to call getpid(2) from a signal handler.

    However, to get the pid of the process which generated the
    signal, one would use sigaction with the SA_SIGINFO flag and
    extract the pid from the si_pid field in the signal handler.

    That said, the SIGHUP in this case is generated by the kernel,
    not by a kill(2) call and the si_pid field will not be valid.

    scott

  8. Re: I don't understand how the child gets placed in the background

    On Sep 9, 10:03 am, K-mart Cashier wrote:
    > On Sep 9, 8:34 am, viza
    > wrote:
    >
    >
    >
    > > On Tue, 09 Sep 2008 06:10:25 -0700, K-mart Cashier wrote:
    > > > The following code is from figure 9.11 in the book "Advanced Programming
    > > > in the Unix Environment" by Stevens and Rago.

    >
    > > > #include
    > > > #include
    > > > #include
    > > > #include
    > > > #include

    >
    > > > static void
    > > > sig_hup(int signo)
    > > > {
    > > > printf("SIGHUP received from pid = %d\n", getpid());
    > > > }

    >
    > > > static void
    > > > pr_ids(char *name)
    > > > {
    > > > printf("%s: pid = %d, ppid = %d, pgrp = %d, tgrp = %d\n",
    > > > name, getpid(), getppid(), getpgrp(),
    > > > tcgetpgrp(STDIN_FILENO));
    > > > fflush(stdout);
    > > > }

    >
    > > > int main(void)
    > > > {
    > > > char c;
    > > > pid_t pid;

    >
    > > > pr_ids("parent");
    > > > if ((pid = fork()) < 0) {
    > > > fprintf(stderr, "fork error\n");
    > > > exit(1);
    > > > } else if (pid > 0) {
    > > > sleep(5);
    > > > exit(0);
    > > > } else {
    > > > pr_ids("child");
    > > > signal(SIGHUP, sig_hup);
    > > > kill(getpid(), SIGTSTP);
    > > > pr_ids("child");
    > > > if (read(STDIN_FILENO, &c, 1) != 1)
    > > > printf("read error from controlling TTY, errno = %d\n", errno);
    > > > }
    > > > exit(0);
    > > > }

    >
    > > This is all wrong; it doesn't do what it prints out that it is doing.

    >
    > > 1) The function sig_hup() handler prints the process id of the process
    > > that receives the signal, not the one that sent it.

    >
    > > 2) The sig_hup() handler is only installed in the child after it has
    > > forked.

    >
    > > 3) The child sends the SIGSTP signal to *itself*, and it stops and is
    > > moved to the background by the shell.

    >
    > > 4) The parent waits five seconds and exits.

    >
    > > 5) The child remains stopped, waiting for SIGCONT.

    >
    > > Send it SIGCONT (see `man 1 kill`).

    >
    > > Now it will try to read from the terminal, and when it succeeds, exit.

    >
    > > While it is waiting to read, you could send it SIGHUP from another
    > > terminal, and it would print its own pid.

    >
    > > My advice: either you have typed it in wrong*, or you have
    > > mis-described what it is supposed to do, or perhaps that book just
    > > belongs in the bin!

    >


    So should I go off and read some O'Reilly books instead?

    > > * have you typed getpid() where it says getppid()?

    >


    > I don't think there was a typo. However, I can check when I get home.


    I looked at it again. There was no typo in the code. At the top of
    page 285, it says

    " Finally, note that our child was placed in the background process
    group when the parent terminated, since the parent was executed as a
    foreground job by the shell. "

    So now, again given the following code, how does the child get placed
    in the background process group when the parent terminates?

  9. Re: I don't understand how the child gets placed in the background

    In article
    <51f36b60-df51-41fa-8b6f-decb56e601fa@w7g2000hsa.googlegroups.com>,
    K-mart Cashier wrote:

    > I looked at it again. There was no typo in the code. At the top of
    > page 285, it says
    >
    > " Finally, note that our child was placed in the background process
    > group when the parent terminated, since the parent was executed as a
    > foreground job by the shell. "
    >
    > So now, again given the following code, how does the child get placed
    > in the background process group when the parent terminates?


    When you run a program from the shell, it forks a process to execute it.
    This process is in its own process group, and any child processes it
    spawns will also be in this PG (unless they start new PGs, which is
    unusual). The terminal's foreground PG is set to this PG while the
    program is running.

    Meanwhile, the shell waits for the process to exit. When it does, it
    sets the terminal's foreground PG to its own PG. Since the child is not
    in this PG, it's considered a background process.

    --
    Barry Margolin, barmar@alum.mit.edu
    Arlington, MA
    *** PLEASE post questions in newsgroups, not directly to me ***
    *** PLEASE don't copy me on replies, I'll read them in the group ***

  10. Re: I don't understand how the child gets placed in the background

    On Sep 10, 8:58 pm, Barry Margolin wrote:
    > In article
    > <51f36b60-df51-41fa-8b6f-decb56e60...@w7g2000hsa.googlegroups.com>,
    > K-mart Cashier wrote:
    >
    > > I looked at it again. There was no typo in the code. At the top of
    > > page 285, it says

    >
    > > " Finally, note that our child was placed in the background process
    > > group when the parent terminated, since the parent was executed as a
    > > foreground job by the shell. "

    >
    > > So now, again given the following code, how does the child get placed
    > > in the background process group when the parent terminates?

    >
    > When you run a program from the shell, it forks a process to execute it.
    > This process is in its own process group, and any child processes it
    > spawns will also be in this PG (unless they start new PGs, which is
    > unusual). The terminal's foreground PG is set to this PG while the
    > program is running.
    >
    > Meanwhile, the shell waits for the process to exit. When it does, it
    > sets the terminal's foreground PG to its own PG. Since the child is not
    > in this PG, it's considered a background process.
    >
    > --


    Once again, thank you for clarifty as to what is going on.

    Chad


+ Reply to Thread