Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c

linux

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,NULL,0);

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

like image 651
Andrew Avatar asked Nov 16 '09 14:11

Andrew


People also ask

What happens if wait () is called by a process with no children?

When wait() returns they also define exit status (which tells our, a process why terminated) via pointer, If status are not NULL. If any process has no child process then wait() returns immediately “-1”.

Does wait null wait for all child processes?

while(wait(NULL) > 0); This ensures that you wait for ALL the child processes and only when all have returned, you move to the next instruction.

How does wait () work?

wait() and waitpid() The wait() system call suspends execution of the calling thread until one of its children terminates. The call wait(&wstatus) is equivalent to: waitpid(-1, &wstatus, 0); The waitpid() system call suspends execution of the calling thread until a child specified by pid argument has changed state.


2 Answers

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
like image 86
agile Avatar answered Oct 06 '22 00:10

agile


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.

like image 32
Andomar Avatar answered Oct 06 '22 00:10

Andomar