Могу ли я установить группу процессов существующего процесса? - PullRequest
2 голосов
/ 22 августа 2009

У меня запущено несколько процессов мини-сервера. Они находятся в той же группе процессов, что и сервер FastCGI, который мне нужно остановить. Сервер FastCGI уничтожит все в своей группе процессов, но мне нужны эти мини-серверы для продолжения работы.

Могу ли я изменить группу процессов запущенного, не дочернего процесса (они являются дочерними для PID 1)? setpgid() терпит неудачу с "Нет такого процесса", хотя я уверен, что он там.

Это на Fedora Core 10.

ПРИМЕЧАНИЕ процессы уже запущены . Новые серверы делают setsid(). Это некоторые серверы, порожденные более старым кодом, которого нет.

Ответы [ 3 ]

3 голосов
/ 22 августа 2009

Одна вещь, которую вы можете попробовать, - это установить setsid () на мини-серверах. Это сделает их сессионными и лидерами групп процессов.

Кроме того, имейте в виду, что вы не можете изменить идентификатор группы процессов на один из другого сеанса и что вам необходимо выполнить вызов, чтобы изменить группу процессов либо изнутри процесса, для которого вы хотите изменить группу процессов. или от родителя процесса.

Недавно я написал некоторый тестовый код для периодического изменения группы процессов набора процессов для очень похожей задачи. Вам не нужно периодически менять идентификатор группы, просто я подумал, что могу уклониться от определенного сценария, который периодически проверяет группу, которая работает дольше определенного времени. Это также может помочь вам отследить ошибку, полученную с помощью 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's 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's keep stderr */
}
1 голос
/ 23 августа 2009

После некоторых исследований я понял это. Inshalla получил существенную проблему: « Вы не можете изменить идентификатор группы процессов на один из другого сеанса », что объясняет, почему мой setpgid() не удался (с вводящим в заблуждение сообщением). Однако, похоже, вы можете изменить его из любого другого процесса в группе (не обязательно родительского).

Поскольку эти процессы были запущены сервером FastCGI и этот сервер FastCGI все еще работал и находился в той же группе процессов. Таким образом, проблема не может перезапустить сервер FastCGI без уничтожения серверов, которые он породил. Я написал новую CGI-программу, которая выполняла setpgid() на работающих серверах, выполняла ее через веб-запрос, и проблема решена!

0 голосов
/ 22 августа 2009

Звучит так, будто вы действительно хотите демонизировать процесс, а не перемещать группы процессов. (Примечание: можно перемещать группы процессов, но я считаю, что вы должны быть в одном сеансе, а целью должна быть уже группа процессов.)

Но сначала посмотрите, работает ли для вас демонизация:

#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;
}

Очевидно, что вы действительно должны проверять ошибки и тому подобное в реальном коде, но вышеприведенное должно работать.

Внутренний процесс будет продолжаться даже после выхода из основного процесса. Глядя на состояние внутреннего процесса с /proc, мы обнаруживаем, что это действительно ребенок init:

Name:   a.out
State:  S (sleeping)
Tgid:   21513
Pid:    21513
PPid:   1
TracerPid:      0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...