Go4Expert

Go4Expert (http://www.go4expert.com/)
-   C (http://www.go4expert.com/forums/c/)
-   -   Linux signals problem (http://www.go4expert.com/forums/linux-signals-problem-t28130/)

ihatec 4Apr2012 16:51

Linux signals problem
 
Can someone help me with that, please?
Above is task description and my solution. I don't know what is wrong, but I don't get any "SUCCESS" printed on the screen only "FAILS";

Program takes 2 numerical parameters each of them represents the time in milliseconds (t)[50-100]. Each parameter is served by subprocess.

Subprocess chooses random time [500 - 2000] ms to run. After this time it must terminate. During its lifetime, subprocess periodically sends chosen unique signal(of your choice) to its parent. The gap between the consequential sends is 't' miliseconds(each subprocess has its own 't' from command line argument).

Parent process awaits the signals from child processes in fixed time window of 100 ms. If in one such a window two signals appear only once in fixed order(of your choice) the parent process prints "SUCCESS" on the screen. Parent process terminates immediately after the last of its children.

Your implementation must ensure that the signals you sent to the parent process will never merge.

Please keep in mind:
avoid fork bombs and busy waiting, use buffered stdout, different random seeds in child processes, SIGCHLD handler, useful functions: fork, kill, wait, waitpid, sigaction, sigsuspend, sigprocmask, fflush, nanosleep, setitimer,
Code:


#define INTERVAL 100
int sethandler( void (*f)(int), int sigNo) 
{
  struct sigaction act;
  memset(&act, 0, sizeof(struct sigaction));
  act.sa_handler = f;
  if (-1==sigaction(sigNo, &act, NULL))
      return -1;
  return 0;
}
 
void sigchld_handler(int sig) 
{
      pid_t pid;
      for(;;)
      {
        pid = waitpid(0,NULL,WNOHANG);
        if(pid > 0)
        {
          childcount--;
        }
        else if(pid<0)
        {
          switch(errno)
          {
              case ECHILD:
                    exit(EXIT_SUCCESS);
              case EINTR:
                    continue;
              default:
                  perror("waitpid:");
                  exit(EXIT_FAILURE);
          }
        }
    }
}
 
void sig_handler(int sig)
{
  last_signal = sig;
}
 
void child_work(int interval, int sig) 
{
  int t;
  struct itimerval timer;
  struct timespec z, zn = {0,0};
  zn.tv_nsec = interval * 1000;
  //sigset_t mask, oldmask;
  srand(getpid());
  t = rand()%1500+500;
    memset(&timer, 0, sizeof(struct itimerval));
    if(t>=1000)
    {
      timer.it_value.tv_sec = 1;
      timer.it_value.tv_usec = (t-1000)*1000;
  }
  else
  {
      timer.it_value.tv_usec = t*1000;
  }
  fprintf(stderr,"CREATED [ %d ] having interval: %d ms and lifetime: %d ms\n",getpid(), interval, t);
  setitimer(ITIMER_REAL,&timer,NULL);
  while(SIGALRM!=last_signal)
  {
      if(kill(getppid(),sig)<0)
      {
        perror("kill:");
        exit(EXIT_FAILURE);
      }
      for(z=zn;nanosleep(&z,&z);)
      {
        if(EINTR != errno)
        {
            perror("Nanosleep;");
            exit(EXIT_FAILURE);
        }
        if(SIGALRM == last_signal)
            break;
      }
  }
  printf("process [ %d ] - terminates!\n", getpid());
}
 
void create_children(int first, int second) 
{
  int n=2;
  while (n-->0) 
  {
      switch (fork()) 
      {
        case 0:
            if(1==n)
            {           
              child_work(first,SIGRTMIN);
            }
            else
            {
              child_work(second,SIGRTMAX);
            }
            exit(EXIT_SUCCESS);
        case -1:
            perror("Fork:");
            exit(EXIT_FAILURE);
        default:
            childcount++;
      }
  }
}
 
void parent_work(sigset_t mask)
{
  struct itimerval timer;
  int val=0;
  int flag = 0;
  int timer_running = 0;
  memset(&timer,0,sizeof(struct itimerval));
  timer.it_value.tv_usec = INTERVAL * 1000;
  while(childcount)
  {
      if(!timer_running)
      {
        setitimer(ITIMER_REAL,&timer,NULL);
        timer_running = 1;
      }
      last_signal = 0;
      sigsuspend(&mask);
      if(last_signal == SIGRTMIN)
      {
        if(!flag)
        {
            flag= 1;
            val++;
        }
        else
        {
            val = 3;
        }
      }
      else if(last_signal == SIGRTMAX)
      {
        if(flag ==1)
        {
            val++;
        }
        else
        {
            flag = 3;
        }
      }
      else if(last_signal == SIGALRM)
      {
        if(val == 2)
        {
            fprintf(stdout,">>>SUCCESS\n");
            if(fflush(stdout) == EOF)
            {
              perror("FFLUSH:");
              exit(EXIT_FAILURE);
            }
        }
        else
        {
            fprintf(stdout,">>>FAIL\n");
            if(fflush(stdout)==EOF)
            {
              perror("FFLUSH:");
              exit(EXIT_FAILURE);
            }
        }
        timer_running = 0;
        flag = 0;
        val = 0;
      }
  }
}
void usage(void)
{
  fprintf(stderr,"USAGE: signals first second\n");
  fprintf(stderr,"first - time for first process between 50 and 100 \n");
  fprintf(stderr,"second - time for second process between 50 and 100\n");
}
 
int main(int argc, char** argv) 
{
  int first, second;
  pid_t pid;
  sigset_t mask,oldmask;
  if(argc!=3) 
  {
      usage();
      return EXIT_FAILURE;
  }
  first = atoi(argv[1]);
  second = atoi(argv[2]);
  if (first<50 || first>100 || second<50 || second>100) 
  {
      usage();
      return EXIT_FAILURE;
  }
  if(sethandler(sigchld_handler,SIGCHLD)) 
  {
      perror("Seting parent SIGCHLD:");
      return EXIT_FAILURE;
  }
  if(sethandler(sig_handler, SIGALRM))
  {
      perror("Setting SIGALRM:");
      return EXIT_FAILURE;
  }
  if(sethandler(sig_handler, SIGRTMIN))
  {
      perror("Setting SIGRTMIN:");
      return EXIT_FAILURE;
  }
  if(sethandler(sig_handler, SIGRTMAX))
  {
      perror("Setting SIGRTMAX:");
      return EXIT_FAILURE;
  }
  create_children(first, second);
  sigemptyset(&mask);
  sigaddset(&mask, SIGCHLD);
  sigaddset(&mask, SIGALRM);
  sigaddset(&mask, SIGRTMIN);
  sigaddset(&mask, SIGRTMAX);
  sigprocmask(SIG_BLOCK, &mask, &oldmask);
  parent_work(oldmask);
  sigprocmask(SIG_UNBLOCK,&mask, NULL);
  for(;;)
  {
      pid=waitpid(0,NULL,WNOHANG);
      if(pid<0)
      {
            switch (errno)
            {
              case ECHILD:
                  return EXIT_SUCCESS;
              case EINTR:
                  continue;
              default:
                  perror("wait:");
                  exit(EXIT_FAILURE);
            }
      }
  }
  return EXIT_SUCCESS;
}



All times are GMT +5.5. The time now is 20:02.