2009-11-16 18 views

回答

4

this answer by chaos

通常的做法是使用 殺(0,PID),並尋找返回 值輪詢-1,並將errno ESRCH來 表明進程是否已

基於man page for kill,它可能是kill(pid,0)。但這個想法是一樣的。

+0

Andomar - 感謝您的回答,並指出混亂的回答類似的問題。我應該在發佈這個之前發現它。 – Andrew

+1

這有點激烈,因爲pid可能溢出,然後被分配到一個新的進程,所以你最終可能會認爲另一個進程比你最初想象的要嚴重。 – user175104

+1

而且,在這段時間內輪詢這樣的事情確實很醜陋,因爲它會縮短電池壽命,並使您的應用出現在powertop上,人們會嘲笑你,直到你停下來恥辱地做到這一點。 – user175104

3

以乾淨的方式做到這一點的唯一方法(即沒有按時間間隔輪詢並且沒有PID溢出的風險)是使用Netlink cn_proc連接器(這是Linux專用的)。周圍沒有太多的示例代碼或文檔。這不是一個很好的API,但它基本上只適用於這個明智的API。

查找PROC_EVENT_EXIT,是事件您有興趣。

http://google.com/codesearch?q=PROC_EVENT_EXIT&hl=en&btnG=Search+Code

+0

看來,這個API確實是想要的,但我無法讓它工作。我在http://netsplit.com/2011/02/09/the-proc-connector-and-socket-filters/以及https://github.com/pturmel/startmon/blob/master/上嘗試了示例代碼main.c,但沒有任何東西是從套接字讀取的。如果你有關於如何完成這項工作的細節,我會非常感興趣。 – a3nm

1

這是工作示例如何申請及使用PROC_EVENT_EXIT/PROC_EVENT_FORK事件。 測試內核3.3.8

#include <sys/types.h> 
#include <sys/socket.h> 
#include <linux/netlink.h> 
#include <linux/connector.h> 
#include <linux/cn_proc.h> 

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

#define NL_MESSAGE_SIZE (sizeof(struct nlmsghdr) + sizeof(struct cn_msg) + \ 
        sizeof(int)) 

static int nl_sock; 

int connect_to_netlink() 
{ 
    struct sockaddr_nl sa_nl; /* netlink interface info */ 
    char buff[NL_MESSAGE_SIZE]; 
    struct nlmsghdr *hdr; /* for telling netlink what we want */ 
    struct cn_msg *msg; /* the actual connector message */ 

    /* connect to netlink socket */ 
    nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); 

    if (-1 == nl_sock) { 
     perror("socket failed"); 
     return errno; 
    } 

    bzero(&sa_nl, sizeof(sa_nl)); 
    sa_nl.nl_family = AF_NETLINK; 
    sa_nl.nl_groups = CN_IDX_PROC; 
    sa_nl.nl_pid = getpid(); 

    if (-1 == bind(nl_sock, (struct sockaddr *)&sa_nl, sizeof(sa_nl))) { 
     perror("bind failed"); 
     return errno; 
    } 

    /* Fill header */ 
    hdr = (struct nlmsghdr *)buff; 
    hdr->nlmsg_len = NL_MESSAGE_SIZE; 
    hdr->nlmsg_type = NLMSG_DONE; 
    hdr->nlmsg_flags = 0; 
    hdr->nlmsg_seq = 0; 
    hdr->nlmsg_pid = getpid(); 

    /* Fill message */ 
    msg = (struct cn_msg *)NLMSG_DATA(hdr); 
    msg->id.idx = CN_IDX_PROC; /* Connecting to process information */ 
    msg->id.val = CN_VAL_PROC; 
    msg->seq = 0; 
    msg->ack = 0; 
    msg->flags = 0; 
    msg->len = sizeof(int); 
    *(int*)msg->data = PROC_CN_MCAST_LISTEN; 

    if (-1 == send(nl_sock, hdr, hdr->nlmsg_len, 0)) { 
     perror("send failed"); 
     return errno; 
    } 

    return 0; 
} 

void handle_events() 
{ 
    char buff[CONNECTOR_MAX_MSG_SIZE]; 
    struct nlmsghdr *hdr; 
    struct proc_event *event; 

    fd_set fds; 

    while (1) { 
     FD_ZERO(&fds); 
     FD_SET(nl_sock, &fds); 

     if (0 > select(nl_sock + 1, &fds, NULL, NULL, NULL)) { 
      perror("select failed"); 
      return ; 
     } 

     /* If there were no events detected, return */ 
     if (! FD_ISSET(nl_sock, &fds)) { 
      return ; 
     } 

     /* if there are events, make calls */ 
     if (-1 == recv(nl_sock, buff, sizeof(buff), 0)) { 
      perror("recv failed"); 
      return ; 
     } 

     hdr = (struct nlmsghdr *)buff; 

     if (NLMSG_ERROR == hdr->nlmsg_type) { 
      perror("NLMSG_ERROR"); 
     } else if (NLMSG_DONE == hdr->nlmsg_type) { 

      event = (struct proc_event *)((struct cn_msg *)NLMSG_DATA(hdr))->data; 

      switch(event->what) { 
       case proc_event::PROC_EVENT_EXIT: 
        printf("Process %d (tgid %d) exit with code %d, signal %d\n", 
         event->event_data.exit.process_pid, 
         event->event_data.exit.process_tgid, 
         event->event_data.exit.exit_code, 
         event->event_data.exit.exit_signal); 
        break; 

       case proc_event::PROC_EVENT_FORK: 
        printf("New process %d (tgid %d), parent %d (tgid %d)\n", 
         event->event_data.fork.child_pid, 
         event->event_data.fork.child_tgid, 
         event->event_data.fork.parent_pid, 
         event->event_data.fork.parent_tgid); 
        break; 

       default: 
        break; 
      } 
     } 
    } 
} 

int main(int argc, char *argv[]) 
{ 
    if (!connect_to_netlink()) { 
     handle_events(); 
    } 
    return 0; 
} 

編譯&運行:

# g++ -o psev psev.cpp 
# ./psev 

輸出:

New process 27465 (tgid 27465), parent 2351 (tgid 2351) 
Process 27465 (tgid 27465) exit with code 0, signal 17 
+0

應該指出的是,這需要CAP_NET_ADMIN,並且不會在非特權用戶進程中工作。 –