Can I set the process group of an existing process?

I have a bunch of mini server processes. They are in the same process group as the FastCGI server that I need to stop. The FastCGI server will kill everything in its process group, but I need these mini servers to keep running.

Can I change the process group of a running, non-child process (they are children of PID 1)? setpgid()

doesn't work with "No such process", although I'm sure it's there.

This is on Fedora Core 10.

NOTE processes are already running. New servers setsid()

. These are several servers spawned by old code that didn't.

+2


source to share


3 answers


One thing you could try is to do setid () in mini-servers. This will make them session and process group leaders.

Also, keep in mind that you cannot change the process group ID to one from another session and that you must make a call to change the process group either from the process you want to change, the group, or from the parent of the process.



I recently wrote some test code to periodically change a process group for a set of very similar tasks. You don't need to change the group id periodically, I just thought I might dodge a certain script that periodically checks for a group that has been running for longer than a certain amount of time. It can also help you track down the error you are getting with setpgid ():

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>

void err(const char *msg);
void prn(const char *msg);
void mydaemon();

int main(int arc, char *argv[]) {

    mydaemon();
    if (setsid() < 0)
        err("setsid");

    int secs = 5*60;

    /* creating a pipe for the group leader to send changed
       group ids to the child */
    int pidx[2];
    if (pipe(pidx))
        err("pipe");

    fcntl(pidx[0], F_SETFL, O_NONBLOCK);
    fcntl(pidx[1], F_SETFL, O_NONBLOCK);

    prn("begin");

    /* here the child forks, it a stand in for the set of
       processes that need to have their group ids changed */
    int child = fork();
    switch (child) {
    case -1: err("fork3");
    case  0:
        close(pidx[1]);

        while(1) {
            sleep(7);
            secs -= 7;
            if (secs <= 0) { prn("end child"); exit(0); }

            int pid;

            /* read new pid if available */
            if (read(pidx[0], &pid, sizeof pid) != sizeof pid) continue;

            /* set new process group id */
            if (setpgid(getpid(), pid)) err("setpgid2");

            prn("child group changed");
        }
    default: break;
    }

    close(pidx[0]);

    /* here the group leader is forked every 20 seconds so that
       a new process group can be sent to the child via the pipe */
    while (1) {
        sleep(20);

        secs -= 20;

        int pid = fork();
        switch (pid) {
        case -1: err("fork2");
        case  0:
            pid = getpid();

            /* set process group leader for this process */
            if (setpgid(pid, pid)) err("setpgid1");

            /* inform child of change */
            if (write(pidx[1], &pid, sizeof pid) != sizeof pid) err("write");

            prn("group leader changed");
            break;
        default:
            close(pidx[1]);
            _exit(0);
        }

        if (secs <= 0) { prn("end leader"); exit(0); }
    }
}

void prn(const char *msg) {
    char buf[256];
    strcpy(buf, msg);
    strcat(buf, "\n");
    write(2, buf, strlen(buf));
}

void err(const char *msg) {
    char buf[256];
    strcpy(buf, msg);
    strcat(buf, ": ");
    strcat(buf, strerror(errno));
    prn(buf);
    exit(1);
}

void mydaemon() {
    int pid = fork();
    switch (pid) {
      case -1: err("fork");
      case  0: break;
      default: _exit(0);
    }

    close(0);
    close(1);
    /* close(2); let keep stderr */
}

      

+3


source


After some research, I figured it out. Inshalla had a significant problem: "you cannot change the process group id to one from another session" which explains why mine setpgid()

was failing (with a misleading message). However, it looks like you can change it from any other process in the group (not necessarily the parent).



Because these processes were started by the FastCGI server and the FastCGI server was still running in the same process group. So the problem is not being able to restart the FastCGI server without killing the servers it spawned. I wrote a new CGI program that ran setpgid()

on the running servers, executed it via a web request and solved the problem!

+1


source


It sounds like you really want to unmount the process, not move the process groups. (Note: you can move process groups, but I believe you need to be in the same session and the target should already be a process group.)

But first, see if the daemon works for you:

#include <unistd.h>
#include <stdio.h>

int main() {
  if (fork() == 0) {
    setsid();
    if (fork() == 0) {
      printf("I'm still running! pid:%d", getpid());
      sleep(10);
    }
    _exit(0);
  }

  return 0;
}

      

Obviously you should really be checking for errors, etc. in real code, but above should work.

The internal process will continue to run even when the main process ends. Looking at the state of the internal process from /proc

, we find that it is indeed a child init

:

Name:   a.out
State:  S (sleeping)
Tgid:   21513
Pid:    21513
PPid:   1
TracerPid:      0

      

0


source







All Articles