• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 304
  • Last Modified:

Forking Processes problem I have the code

I am trying to create a process that will split itself into two other processes that I call "Batman" and "Robin" and if i terminate either process, the other process will need to spawn a replacement of the terminated process.  I have a running code that does start the process giving me a pid when i run a /usr/ucb/ps -xwww but the I want it to show the actual name of the process, ie batman and robin but it would only show the filename of my program.  Right now when I run it and run a process scheduler it shows...

PID      TT       S  TIME COMMAND
 19209 pts/6    S  0:00 -tcsh
 19570 pts/6    S  0:00 stuff.exe
 19571 pts/6    S  0:00 stuff.exe
 19572 pts/6    S  0:00 stuff.exe

How can I modify my code to show the actual names of my processes and also how would I modify my code that when I type in the command "kill pid#" it would spawn and save the process and send me a message saying so.  I would like it that when I kill the process it would do something like this...

/export/staff/amb/dev/p3:[19]> kill 19572
Batman: Pray help Robin!  I'm being attacked!
Batman: (terminated)
Robin: Fear not Batman!  I will rout the penguin's men!
Batman: My thanks Robin!  I live to fight another day...
/export/staff/amb/dev/p3:[20]> kill 19571
Robin: Pray help Friar!  I'm being attacked!
Robin: (terminated)
Batman: Fear not Robin!  I will rout the penguin's men!
Robin: My thanks Batman!  I live to fight another day...
/export/staff/amb/dev/p3:[21]> kill -9 19599
Robin: Poor Batman has been taken from us!  I will set him free to once more roam Gotham!
Batman: Robin, but for your assistance I would have met a certain death!
/export/staff/amb/dev/p3:[22]> /usr/ucb/ps -xwww


   PID TT       S  TIME COMMAND
 19209 pts/6    S  0:00 -tcsh
 19570 pts/6    S  0:00 Gotham City
 19604 pts/6    S  0:00 Robin
 19623 pts/6    S  0:00 Batman

/export/staff/amb/dev/p3:[23]> touch Alfred
/export/staff/amb/dev/p3:[24]> kill -9 19604
Batman: Poor Robin has been taken from us!  I will set him free to once more roam Gotham!
Robin: Friar, but for your assistance I would have met a certain death!
/export/staff/amb/dev/p3:[25]> chmod +x Alfred
/export/staff/amb/dev/p3:[26]> kill 19623
Batman: Pray help Robin!  I'm being attacked!
Batman: (terminated)
Robin: Alas, I dare not save Batman for fear Alfred would suffer execution!  Batman, I will remember you always...
/export/staff/amb/dev/p3:[26]> kill -9 19677 19570

My code does little of this as I have not yet set up any messages whatsoever, I just had this program to actually start the processes.  If anyone can help me modify my code, it would be greatly appreciated.  It runs and compiles at the time being through a unix shell but this won't run with Visual C++.  I know I am asking too much but a little help each person would help me out greatly!  Thanks in advance!  Here is my code:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>

void SigHandler();
void waitInfo(int pid, int status);
void gprs_routine(void);
void startacap(void);
void startpcap(void);
void ErrorStopProcesses(void);

void SigHandler() {
  printf("PID %d caught a SIGHUP signal.\n",getpid());
  return;
}

void waitInfo(int pid, int status) {
  if(WIFEXITED(status))
    printf("\tProcess %d exited normally with exit code %d.\n",pid,WEXITSTATUS(status));
  else {
    if(WIFSIGNALED(status))
      printf("\tProcess %d exited because signal %d was not caught.\n",pid,WTERMSIG(status));
    if(WIFSTOPPED(status))
      printf("\tProcess %d is stopped because signal %d.\n",pid,WSTOPSIG(status));
  }
  return;
}

void gprs_routine(void) {
  int ret;
  char cmd[128];
  signal(SIGHUP,SigHandler);
  sleep(1);   //simulate startup code
  printf("\tBATMAN Process started.\n");
  sprintf(cmd,"top -p %d -b > junk\0",getpid());
  ret=system(cmd);
  printf("BATMAN system process exited with %d.\n",ret);
  sleep(60);   //simulate cleanup code
  printf("BATMAN Process ending.\n");
  exit(0);
}

void startacap(void) {
  sleep(1);   //simulate startup code
  printf("\tROBIN Process started.\n");
  sleep(60);   //simulate short running process
  printf("\tROBIN Process ending.\n");
  exit(0);
}

void startpcap(void) {
  sleep(1);   //simulate startup code
  printf("\tPENGIUN Process started.\n");
  sleep(60);  //simulate short running process
  printf("\tPENGUIN Process ending.\n");
  exit(0);
}

void ErrorStopProcesses(void) {
  printf("\nMAIN: Error %d occurred, kill all processes with process group:%d.\n",errno, (getpid()*-1));
  kill((getpid()*-1),SIGHUP);
  return;
}

int main () {
  int childcounter=0;
  int status;
  int pid;
  int threadgprs;

  threadgprs=fork();
  if(!threadgprs) {
    gprs_routine();
    exit(0);
  }
  printf("GOTHAM CITY: created BATMAN ( pid %d ).\n",threadgprs);

  pid=fork();
  if(!pid) {
    startpcap();
    exit(0);
  }
  if(pid==-1) ErrorStopProcesses();
  childcounter++;
  printf("GOTHAM CITY: created ROBIN ( pid %d ).\n",pid);

  pid=fork();
  if(!pid) {
    startacap();
    exit(0);
  }
  if(pid==-1) ErrorStopProcesses();
  childcounter++;
  printf("GOTHAM CITY: created PENGUIN ( pid:%d ).\n",pid);
 

  printf("\nGOTHAM CITY: entering main wait loop.\n");
  while (childcounter) {
    pid=waitpid(0,&status,0);
    if(pid!=threadgprs)
      childcounter--;
    else {
      threadgprs=0;
      //if BATMAN process terminates, you could kill all others by
      //calling ErrorStopProcesses(); here,
      //or just wait for them to complete.
      }
    printf("\tGOTHAM CITY: %s process terminated, %d child processes still exist.\n",(threadgprs==0? "GRPS" : "child"), childcounter);
    waitInfo(pid, status);
  }
  printf("GOTHAM CITY: exited main wait loop.\n\n");

  if(threadgprs) {
    printf("GOTHAM CITY: signaling BATMAN process to terminate (it will not catch the signal).\n");
    signal(SIGHUP,SigHandler);
    kill((getpid()*-1),SIGHUP);
    pid=waitpid(0,&status,0);
    waitInfo(pid,status);
  }
  else {
    printf("GOTHAM CITY: BATMAN already terminated.\n");
  }

  printf("\nGround control, shut down main engines.\n");
  sleep(10);  //simulate shutdown code
  return 0;
}

0
djchiena
Asked:
djchiena
1 Solution
 
Sjef BosmanGroupware ConsultantCommented:
Maybe I'll read your code later, here my first impression. You say "...the other process will need to spawn a replacement of the terminated process...". That's not how it works in Linux. The normal approach is:
- start ProtectGotham-program
- fork/exec Batman
- fork/exec Robin
- wait
- if the wait() ends, a child process has died, so revive it

Only a parent can wait() for a child, so Batman and Robin have to be two children of one and the same parent.
Btw: this is how init() used to work, it forks and reforks a process for each terminal.
0
 
ankuratvbCommented:
Here is some information:

On BSDish systems, the ps program actually looks into the address space of the running process to find the current argv[], and displays that. That enables a program to change its `name' simply by modifying argv[].

On SysVish systems, the command name and usually the first 80 bytes of the parameters are stored in the process' u-area, and so can't be directly modified. There may be a system call to change this (unlikely), but otherwise the only way is to perform an exec(), or write into kernel memory (dangerous, and only possible if running as root).

Some systems (notably Solaris) may have two separate versions of ps, one in `/usr/bin/ps' with SysV behaviour, and one in `/usr/ucb/ps' with BSD behaviour. On these systems, if you change argv[], then the BSD version of ps will reflect the change, and the SysV version won't.

Check to see if your system has a function setproctitle().

from:
http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC22
I am not sure you can change the process name of the child process.
0
 
Sjef BosmanGroupware ConsultantCommented:
Basically, the code seems to be more or less okay. What you have to do is to store the pid's of the processes you created, so you can find out what process went six feet under. It will then be easy to restart it.
0
Improve Your Query Performance Tuning

In this FREE six-day email course, you'll learn from Janis Griffin, Database Performance Evangelist. She'll teach 12 steps that you can use to optimize your queries as much as possible and see measurable results in your work. Get started today!

 
ankuratvbCommented:

There are systems have a library function that does this (pstat on
HP-UX, setproctitle on BSDI > 1.0). Most systems will allow you to
copy over argv[0], though it's not strictly ANSI C. For example:-

Try this:
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
 pid_t pid;
 int status;

 if ((pid = fork()) < 0) {
  fprintf(stderr, "Can't fork\n");
  return 1;
 } else if (pid == 0) { /* child */
  strcpy(argv[0], "foobar");
  sleep(20);
  return 0;
 } else {  /* parent */
  wait(&status);
  return 0;
 }
}

ps output:-
 7058  p5  S+     0:00.02 ./a.out
 7059  p5  S+     0:00.00 foobar (a.out)

0
 
Sjef BosmanGroupware ConsultantCommented:
If you want to change the names, do as they all do: create different executables... If your programme will grow a lot, this is anyway something you should consider to do, since a lot of (code and) data is duplicated in memory for nothing, compile-time grows as well, and flexibility goes down.
0
 
grg99Commented:
Lot of good suggestions above, to summarize:

It's a LOT easier to have ONE top-level process that spawns the two, then the top cat will get notification of what happens to the children, and it can re-spawn them as needed.   Much cleaner than having them ping-pong check on each other.  After all, what if they both succumb at the same instant, perhaps from the same malady?

Gaping logic hole there.

So better to write a small, simple "top cat" process.  Shouldnt take more than 50 lines.



0
 
anupvijayCommented:
Same thoughts as grg99 from me also.

It is more reliable this way and easy maintain too.
I have seen this approach work for real time critical applications where the down-time of the system is generally
a few minutes/year.

So it is a time tested approach  I would say.

Cheers.

0
 
NovaDenizenCommented:
Note that in the original question, one of the programs calls the other "Friar".  I think he missed an edit.

There was an infamous program a while back that had two processes watching out for each other, one was called Robin Hood, the other was called Friar Tuck.  See the story here: http://www.dpmms.cam.ac.uk/~gjm11/jargon/jargappA.html

I'm not sure I would help this guy, he may be up to no good. :)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Improved Protection from Phishing Attacks

WatchGuard DNSWatch reduces malware infections by detecting and blocking malicious DNS requests, improving your ability to protect employees from phishing attacks. Learn more about our newest service included in Total Security Suite today!

Tackle projects and never again get stuck behind a technical roadblock.
Join Now