开发者

How do I wait for PID X to exit if X is not a child process?

开发者 https://www.devze.com 2022-12-11 08:08 出处:网络
using c how do I wait for PID X to exit when it is not a child of my current process? Kill(pid, SIGTERM);

using c how do I wait for PID X to exit when it is not a child of my current process?

Kill(pid, SIGTERM);
waitpid(pid,NUL开发者_如何学编程L,0);

The above does not work as 'pid' is not a child process.


This is working sample how to subscribe and use PROC_EVENT_EXIT / PROC_EVENT_FORK events. Tested on kernel 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

Output:

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


See this answer by chaos:

The usual practice is to poll using kill(0, pid) and looking for return value -1 and errno of ESRCH to indicate that the process is gone

Based on the man page for kill, it might be kill(pid,0) instead. But the idea is the same.


The only way to do this in a clean way (i.e. without polling in time intervals, and without risking PID overflows) is to use the Netlink cn_proc connector (which is Linux specific). There's not much example code or documentation around. It's not a nice API, but it's basically to only sensible API for this.

Look for PROC_EVENT_EXIT, which is the event your are interested in.

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

0

精彩评论

暂无评论...
验证码 换一张
取 消