Solved

Forking Processes problem I have the code

Posted on 2004-04-28
9
281 Views
Last Modified: 2010-04-15
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
Comment
Question by:djchiena
9 Comments
 
LVL 46

Expert Comment

by:Sjef Bosman
ID: 10940472
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
 
LVL 9

Accepted Solution

by:
ankuratvb earned 500 total points
ID: 10940475
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
 
LVL 46

Expert Comment

by:Sjef Bosman
ID: 10940543
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
 
LVL 9

Expert Comment

by:ankuratvb
ID: 10940685

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
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 46

Expert Comment

by:Sjef Bosman
ID: 10940991
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
 
LVL 22

Expert Comment

by:grg99
ID: 10948682
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
 
LVL 2

Expert Comment

by:anupvijay
ID: 10949017
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
 
LVL 22

Expert Comment

by:NovaDenizen
ID: 10963556
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

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

An Outlet in Cocoa is a persistent reference to a GUI control; it connects a property (a variable) to a control.  For example, it is common to create an Outlet for the text field GUI control and change the text that appears in this field via that Ou…
Windows programmers of the C/C++ variety, how many of you realise that since Window 9x Microsoft has been lying to you about what constitutes Unicode (http://en.wikipedia.org/wiki/Unicode)? They will have you believe that Unicode requires you to use…
The goal of this video is to provide viewers with basic examples to understand and use pointers in the C programming language.
The goal of this video is to provide viewers with basic examples to understand opening and writing to files in the C programming language.

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

23 Experts available now in Live!

Get 1:1 Help Now