używając c jak mam czekać na zakończenie PID X, gdy nie jest on dzieckiem mojego obecnego procesu?Jak mogę poczekać na zakończenie PID X, jeśli X nie jest procesem podrzędnym?
Powyższe nie działa, ponieważ "pid" nie jest procesem podrzędnym.
używając c jak mam czekać na zakończenie PID X, gdy nie jest on dzieckiem mojego obecnego procesu?Jak mogę poczekać na zakończenie PID X, jeśli X nie jest procesem podrzędnym?
Powyższe nie działa, ponieważ "pid" nie jest procesem podrzędnym.
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.
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
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
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
Należy zauważyć, że wymaga to CAP_NET_ADMIN i nie będzie działać w nieuprzywilejowanym procesie użytkownika. –
Andomar - dzięki za odpowiedź i wskazując chaos odpowiedź na podobne pytanie. Powinienem był to zauważyć przed opublikowaniem tego. – Andrew
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
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