Zac Reynolds
Zac Reynolds

Reputation: 133

Make child process wait for parent

I have to write a program in C that will fork a new process and then use that processes pid for another function. However I need to call this function before the child process can run and I don't know how to do this.

Here's some pseudo code of what I'm trying to do.

pid_t pid = fork();
if(in_child){    //In the child process
    //launch child application
    //somehow stop the child application before it actually executes any code
}
else{
    //call my function with the child's pid
    //resume the child process
    //do other stuff
}

If you need any additional info please ask. Thanks.

Edit: I do not have access to the code for the child. I'm just wanting to run an executable.

Upvotes: 5

Views: 8507

Answers (3)

Utkarsh Kumar
Utkarsh Kumar

Reputation: 607

What you are looking for is interprocess condition variable. https://en.wikipedia.org/wiki/Monitor_(synchronization)

The way it would work (roughly) :-

Before forking you set a variable asking child to wait :- child_continue = false

1.) CHILD process begins to execute (or parent, doesn't matter)

  • If the variable child_continue == false
  • Sleep on a condition variable and wait for signal from parent

2.) Parent process waits for its chance to run (note the order of run doesn't matter). When the parent process is ready to run, it does whatever it wants with the child PID (or something else) and signals the child process to continue.

In order to do this, you'd need interprocess mutex and interprocess condition variable.

//#include "pthread.h" in main file

//create IPC MUTEX which can be shared by both child and parent.

pthread_mutexattr_t mutex_attr;
pthread_condattr_t cond_attr;
pthread_mutex_t mtx;
pthread_cond_t cond;
if (0!= pthread_mutexattr_init(&mutex_attr))
{
 //errror handling
}
if (0!= pthread_condattr_init(&cond_attr))
{
 //errror handling
}

if (0 != pthread_condattr_setpshared(&cond_attr,PTHREAD_PROCESS_SHARED)
{
 //error handling
}
if (0 !=   pthread_mutexattr_setpshared(&mutex_attr,PTHREAD_PROCESS_SHARED)
{
 //error handling
}

if (0 !=pthread_mutex_init(&mtx,&mtx_attr))
{
//error handling
}

if (0 !=pthread_cond_init(&cond,&cond_attr))
{
//error handling
}
boolean child_continue = false;
//now fork !!

pid_t pi = fork();
if (pi ==0) //child
{
  if (0 !=pthread_mutex_lock(&mtx))
  {
    //error handling
  }
  while (!child_continue) //wait until we receive signal from parent.
  {
   if (0 !=pthread_cond_wait(&cond,&mtx))
   {
    //error handling
   }
  }
  if (0 !=pthread_mutex_unlock(&mtx))
  {
    //error handling
  }
  //Parent is done!! either we woke up by condition variable or, parent was done before hand
  //in which case, child_continue was true already.
}
else
{
  //in parent process do whatever you want with child pid (pi variable)

  //once you are done, set child_continue to true and wake up child.
  if (0 !=pthread_mutex_lock(&mtx))
  {
    //error handling
  }
  child_continue = true;
  if (0 !=pthread_cond_signal(&cond)) 
  {
    //error handling
  }
  if (0 !=pthread_mutex_unlock(&mtx))
  {
    //error handling
  }
}

Upvotes: 0

paxdiablo
paxdiablo

Reputation: 882686

If you mean any code at all, that can be difficult. You can use clone with CLONE_STOPPED instead of fork to start the application into a stopped state (needing SIGCONT to get it going again).

However, if you simply mean specific code in the child and you can modify the child code, you can, as the first thing in main, simply set up a handler for a USR1 signal (any IPC would probably do but a signal seems the simplest in this particular case) and then wait for it to fire before carrying on.

That way, the process itself will be running but won't be doing anything yet.

You then have the parent weave whatever magic it needs to do, then send a SIGUSR1 to the child.


But since, according to a comment, you don't have access to the client code, the first option may be the best, assuming that SIGCONT won't actually cause problems with the child. That will require testing.


Of course, one thing to keep in mind is that neither clone() nor fork() will actually load your new program into the child process, that has to be done with an exec-type call after the split. This is a result of the UNIX split between fork and exec functionality, detailed here.

That means that, while you don't control the child program, you do control the child process, so your code can wait for whatever signal it wants before loading up the new child program. Hence it's doable even with just fork().

Unfortunately, that also means that neither clone nor fork can stop your process after the new program has been loaded with exec (at least not deterministically) so, if the fiddling you want to do is to the new program (such as manipulating its variables by attaching to its memory), you can't do it.

The best you can do is to fiddle with the new process while it still has a copy of the old program (before the exec).

Upvotes: 2

Arlie Stephens
Arlie Stephens

Reputation: 1176

There's a simpler way, assuming your OS will let you share the address space before the child execs. Pseudo-code follows.

volatile int barrier;

int safe_fork(routine_to_call) 
{
     pid_t pid;

     barrier = 0;
     pid = fork();
     if (pid == 0) {
         /* parent */
         routine_to_call()
         barrier = 1;
     } else if (pid > 0) {
         while (barrier = 0) 
             ;   /* or sleep if it's a slow routine */
         exec()
         //if we get here, exec failed; exit with failure code 
     } else {
         /* return failure */
     }
     /* must be parent; return success */
}

You may need to do something special to get the sharing behaviour, rather than having them both start with independent copies. I know it's doable on FreeBSD. In linux, check out the CLONE_VM flag to clone(); it looks like it should let you do what you need here.

Upvotes: 1

Related Questions