2009-11-16 19 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,并且不会在非特权用户进程中工作。 –