Porting on FreeBSD 53

Hervé Kergourlay herve.kergourlay at atempo.com
Fri May 13 09:03:04 PDT 2005


Seán C. Farley a écrit :

> On Thu, 12 May 2005, Seán C. Farley wrote:
>
>> On Thu, 12 May 2005, Hervé Kergourlay wrote:
>>
>> <snip>
>>
>>> 4) wait() API
>>>
>>> 2 problems, the first is a ECHILD error on a wait call after a fork
>>> fork The code is generic for most of unix system. Is there any
>>> specific problems to manage the fork and wait APIs ?
>>> the second problem with calls is a blocking wait() call in the same
>>> condition but this time the son process is finished but the wait call
>>> in the father stays blocked, again it's a generic Unix code
>>>
>>> If there is no evidence, ask me for more informations
>>
>>
>> The second problem sounds like what I am encountering
>> (http://www.freebsd.org/cgi/query-pr.cgi?pr=77818) with zsh for my
>> shell.  You did suspend (sigsuspend()) SIGCHLD before the fork?  By
>> "fork fork", do you mean you fork twice?
>
>
> Ah ha!  I see the problem that has been causing me this problem and
> probably you too.  Signal suspensions (only these?) are not being copied
> with a double fork().  Here is an example program[1] to illustrate.
> They do get copied on FreeBSD-4.10 and Linux.  I just do not know if
> they are supposed to be copied.
>
> Seán
>
> P.S.  I included David since he has been trying to help me with this
> bug.
>
>   1. http://www.farley.org/freebsd/tmp/grandparent.c


I test your sample

it's working on Linux and FreeBSD 4.0 but failing on FreeBDS 5.2 et 5.3.
the process stays blocked on the suspend call

I rewrite another sample with the same model, joined here, as we wrote 
it in our main program. It's working also on Linux but failing on all 
FreeBSD included FreeBSD 4.0, 5.2 et 5.3

trace when working

avant FORK : pid 71995.
avant FORK : pid 71996.
son pid 71997.
Child calling execve(/bin/ls).
sigw    sigw.c  sigw2   sigw2.c
Grand parent pid 71996.
Grand parent waiting for a signal.
Parent pid 71997.
Parent waiting for a signal.
Parent get status 100000.
Grand parent get status 100000.

trace when failing

avant FORK : pid 71995.
avant FORK : pid 71996.
son pid 71997.
Child calling execve(/bin/ls).
sigw    sigw.c  sigw2   sigw2.c
Grand parent pid 71996.
Grand parent waiting for a signal.
Parent pid 71997.
Parent waiting for a signal.
wait returned No child processes.
wait returned No child processes.

the wait call return with an errno ECHILD ??

did you have any idea if the problem will be solve by the FreeBSD team 
or not ?
or if there is a workarouund ?

thanks
hervé


>------------------------------------------------------------------------
>
>_______________________________________________
>freebsd-hackers at freebsd.org mailing list
>http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
>To unsubscribe, send any mail to "freebsd-hackers-unsubscribe at freebsd.org"
>  
>

-------------- next part --------------
/*
 * Test SIGCHLD atempo().
 */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>

#define TRUE 1
#define FALSE 0

/* gestion des processus        */
/* la foncion v_wait renvoie dans p_status l'etat du process :                                          */
/* les 8 bits de poids fort contiennent le status (EXITED, TERMINATED, STOPPED)                 */
/* les 24 bits de poids faible contiennent le code d'exit si le status est EXITED, et 0 sinon           */
/* (a noter que sur unix, l'API ne permet de recuperer que les 8 bits de poids faible du code d'exit)   */
#define VOS_PROC_STATUS_NOVAL           0x00000000
#define VOS_PROC_STATUS_EXITED          0x01000000      /* process has exited (normal termination)              */
#define VOS_PROC_STATUS_TERMINATED      0x02000000      /* process has terminated due to receipt of a signal    */
#define VOS_PROC_STATUS_STOPPED         0x03000000      /* process has been stopped                             */

/* macros pour recuperer les valeurs    */
#define VOS_GET_PROC_STATUS(status)     (status & 0xFF000000)
#define VOS_GET_PROC_EXIT_CODE(status)  (status & 0x00FFFFFF)

const char cmd[] = "/bin/ls";

void unix_ignore_all_signals();
void fork_cmd(int isChild);
void handler(int sig);

int main(int argc,
         char **argv)
{
#ifdef XXX
    sigset_t newMask;
    sigset_t oldMask;

    struct sigaction act;

    // Create handler for child signal.
    act.sa_handler = handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    sigaction(SIGCHLD, &act, NULL);

    // Block child signals until suspend is ready.
    sigemptyset(&newMask);
    sigaddset(&newMask, SIGCHLD); 
    if (sigprocmask(SIG_BLOCK, &newMask, &oldMask) < 0)
    {
        perror("sigprocmask()");
        exit(EXIT_FAILURE);
    }
#endif

    // Become a grand parent.
    fork_cmd(FALSE);

#ifdef XXX
    // Unblock.
    if (sigprocmask(SIG_UNBLOCK, &newMask, &oldMask) < 0)
    {
        perror("sigprocmask()");
        exit(EXIT_FAILURE);
    }

#endif

    exit(EXIT_SUCCESS);
}


void fork_cmd(int isChild)
{
  const char *age;
  char *args[] = {"ls -la", NULL};
  char *envp[] = {NULL};
  int pid;
  int sig;
  int retos;
  int attendu_recu;
  int status;
  int exit_status;
  int sleepy;
  sigset_t mask;

  void (*sig_handler)(int);
  void (*old_sig_handler)(int);
  struct sigaction act;
  struct sigaction oact;

  sig_handler = SIG_DFL;
  act.sa_handler = sig_handler;
  act.sa_flags = SA_NOCLDWAIT;

  if (sigaction (SIGCHLD, &act, &oact) == -1) {
    fprintf(stderr, "sigaction returned %s.\n",
            strerror(errno));
    exit(EXIT_FAILURE);
  }

  old_sig_handler = oact.sa_handler;

  fprintf(stderr, "avant FORK : pid %d.\n", getpid());

  pid = fork();
  if (! pid)
  {
      // Execute program or be the parent.
      if (isChild)
      {
          fprintf(stderr, "%s pid %d.\n", "son", getpid());
          unix_ignore_all_signals();
          fprintf(stderr, "Child calling execve(%s).\n", cmd);
          retos = execve(cmd, args, envp);

          if (retos == -1)
          {
              fprintf(stderr, "execve(%s) returned %s.\n", cmd,
                      strerror(errno));
              exit(EXIT_FAILURE);
          }
          fprintf(stderr, "Child executed.\n");
          exit(EXIT_SUCCESS);
      }
      else
      {
          fork_cmd(TRUE);
      }
  }
  else if (pid > 0)
  {
    // Message for parent/grand parent.
    if (isChild)
      {
          age = "Parent";
          sleepy = 2;
      }
      else
      {
          age = "Grand parent";
          sleepy = 1;
      }

    while ((sleepy = sleep(sleepy)))
    {
        // Sleep around signals.
    }

    fprintf(stderr, "%s pid %d.\n", age, pid);

#ifdef XXX
        sigfillset(&mask);
        sigdelset(&mask, SIGCHLD);
        sigdelset(&mask, SIGINT);

        fprintf(stderr, "%s waiting for a signal.\n", age);
        sigsuspend(&mask);
        fprintf(stderr, "%s received signal.\n", age);
#endif

    fprintf(stderr, "%s waiting for a signal.\n", age);

    pid = (int) wait(&status);
    if (pid == -1) {
      fprintf(stderr, "wait returned %s.\n",
              strerror(errno));
      exit(EXIT_FAILURE);
    }

    if (WIFEXITED(status)) {
      /* Oui                            */
      exit_status = (0x00FFFFFF & WEXITSTATUS(status));
      exit_status |= VOS_PROC_STATUS_EXITED;
    }
    else if (WIFSIGNALED(status)) {
      /* Termine par signal             */
      sig = WTERMSIG(status);
      fprintf(stderr, "son process ended by signal %d\n", sig);
      exit_status = 0;
      exit_status |= VOS_PROC_STATUS_TERMINATED;
      }
    else if (WIFSTOPPED(status)) {
      sig = WSTOPSIG(status);
      fprintf(stderr, "son process ended by signal %d\n", sig);
      exit_status = 0;
      exit_status |= VOS_PROC_STATUS_STOPPED;
    }
    else {
      fprintf(stderr, "wait returned unknowned %d status\n", status);
    }
  
    fprintf(stderr, "%s get status %X.\n", age, exit_status);

  }
  else
  {
      perror("fork()");
      exit(EXIT_FAILURE);
  }

  return;
}


void handler(int sig)
{
    return;
}

void unix_ignore_all_signals() {

  if ((void (*)())signal(SIGHUP, SIG_IGN) == (void (*)())-1) {
    fprintf(stderr, "Unable to inhibit the signal %s.\n", SIGHUP);
  }

  if ((void (*)())signal(SIGINT, SIG_IGN) == (void (*)())-1) {
    fprintf(stderr, "Unable to inhibit the signal %s.\n", SIGINT);
  }

  if ((void (*)())signal(SIGTERM, SIG_IGN) == (void (*)())-1) {
    fprintf(stderr, "Unable to inhibit the signal %s.\n", SIGTERM);
  }

  if ((void (*)())signal(SIGPIPE, SIG_IGN) == (void (*)())-1) {
    fprintf(stderr, "Unable to inhibit the signal %s.\n", SIGPIPE);
  }

  if ((void (*)())signal(SIGALRM, SIG_IGN) == (void (*)())-1) {
    fprintf(stderr, "Unable to inhibit the signal %s.\n", SIGALRM);
  }

  if ((void (*)())signal(SIGCHLD, SIG_IGN) == (void (*)())-1) {
    fprintf(stderr, "Unable to inhibit the signal %s.\n", SIGCHLD);
  }

}



More information about the freebsd-hackers mailing list