2009-08-21 48 views
2

我有一堆運行的迷你服務器進程。它們與我需要停止的FastCGI服務器位於同一個進程組中。 FastCGI服務器將終止其進程組中的所有內容,但我需要這些迷你服務器繼續運行。我可以設置現有流程的流程組嗎?

我可以更改正在運行的非子進程(它們是PID 1的子進程)的進程組嗎? setpgid()失敗,「沒有這樣的過程」,雖然我積極的那裏。

這是在Fedora Core 10

注意的過程已經運行。新服務器做setsid()。這些是由舊代碼產生的某些服務器產生的。

回答

3

你可以嘗試的一件事是在miniservers中做setsid()。這將使他們的會話進程組負責人。

另外,請記住,您無法將進程組ID從另一個會話更改爲一個,並且必須執行調用以更改進程組,以便從要更改組的進程中或來自過程的父母。

我最近編寫了一些測試代碼來定期更改一組進程的進程組,以執行非常類似的任務。您不需要定期更改組標識,這只是我認爲我可能會逃避某個腳本,該腳本會定期檢查運行時間超過一定時間的組。它也可以幫助你追蹤你與setpgid(領)錯誤:喜歡你真的想daemonise的過程,而不是移動過程組

#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 */ 
} 
0

聽起來。 (注:一個可以移動的過程組,但我相信你需要在同一會話和目標需要已經成爲一個進程組。)

但首先,看看是否daemonising工程給你:

#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 
1

經過一番研究,我想通了。 Inshalla得到的基本問題,「你不能改變進程組ID爲另一個會話」這解釋了爲什麼我的setpgid()失敗(帶有誤導性消息)。但是,你似乎可以改變它從組中的任何其他進程(不一定是父)。

由於這些進程是由FastCGI服務器啓動的,並且該FastCGI服務器仍在運行且處於相同進程組中。因此,這個問題不能重新啓動FastCGI服務器而不殺死它產生的服務器。我寫了一個新的CGI程序,在運行的服務器上執行setpgid(),通過Web請求執行它並解決問題!

+2

setpgid(2)中的錯誤值:'ESRCH ...對於setpgid([pid,pgid]):pid不是調用進程,也不是調用進程的子進程。「有趣的是,要了解可以從組內調用。 – Inshallah 2009-08-23 17:49:46

+0

是的,我得到的ESRCH在這種情況下很差,因爲「沒有這樣的過程」。 – Schwern 2009-08-24 03:52:29

相關問題