2009-11-16 7 views

Odpowiedz

4

Zobacz this answer by chaos:

Normalną praktyką jest do sondowania za pomocą kill (0, PID) i patrząc na powrót wartość -1, a errno z ESRCH do wskazują, że proces ten jest już

Na podstawie numeru man page for kill może to być kill(pid,0). Ale pomysł jest taki sam.

+0

Andomar - dzięki za odpowiedź i wskazując chaos odpowiedź na podobne pytanie. Powinienem był to zauważyć przed opublikowaniem tego. – Andrew

+1

To jest trochę zbytnio pikantne, ponieważ pid może się przepełnić, a następnie zostać przypisany do nowego procesu, więc możesz skończyć się innym procesem, niż początkowo sądziłeś. – user175104

+1

Ponadto, odpytywanie o takie rzeczy w odstępach czasowych jest naprawdę brzydkie, ponieważ skraca czas pracy baterii i sprawia, że ​​aplikacje pojawiają się na powertop, a ludzie będą się z ciebie śmiać, dopóki nie zrobisz tego ze wstydem. – user175104

3

Jedynym sposobem zrobienia tego w czysty sposób (tj. Bez odpytywania w odstępach czasu i bez ryzyka przekroczenia PID) jest użycie złącza cn_proc Netlink (co jest specyficzne dla systemu Linux). Nie ma tu wiele przykładowego kodu lub dokumentacji. To nie jest przyjemny interfejs API, ale w zasadzie jest to tylko rozsądny interfejs API.

Look dla PROC_EVENT_EXIT, który jest sytuacja, są zainteresowani.

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

+0

Wygląda na to, że ten interfejs API działa dokładnie tak, jak powinien, ale nie mogę go uruchomić. Próbowałem kodu przykładowego pod adresem http://netsplit.com/2011/02/09/the-proc-connector-and-socket-filters/, a także https://github.com/pturmel/startmon/blob/master/ main.c, ale nic nie jest czytane z gniazda. Byłbym bardzo zainteresowany, gdybyś miał szczegóły, jak to zrobić. – a3nm

1

Próbka ta działa jak się zapisać i użyć zdarzenia PROC_EVENT_EXIT/PROC_EVENT_FORK. Testowane na kernelu 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; 
} 

Compile & Run:

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

wyjściowa:

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

Należy zauważyć, że wymaga to CAP_NET_ADMIN i nie będzie działać w nieuprzywilejowanym procesie użytkownika. –

Powiązane problemy