1 // Copyright (C) 2012 The SBCELT Developers. All rights reserved.
2 // Use of this source code is governed by a BSD-style license
3 // that can be found in the LICENSE-file.
4
5 #include <sys/types.h>
6 #include <sys/event.h>
7 #include <sys/time.h>
8 #include <unistd.h>
9 #include <pthread.h>
10 #include <errno.h>
11
12 #include "eintr.h"
13
14 static int kqfd = -1;
15
pdeath_monitor(void * udata)16 static void *pdeath_monitor(void *udata) {
17 (void) udata;
18 while (1) {
19 struct kevent ke;
20 int ret = HANDLE_EINTR(kevent(kqfd, NULL, 0, &ke, 1, NULL));
21 if (ret == 0) {
22 // No events for us.
23 continue;
24 } else if (ret > 0) {
25 // Our parent has died.
26 _exit(0);
27 } else if (ret == -1) {
28 // Most of kevent()'s returned errors are programmer errors,
29 // except ENOMEM and ESRCH.
30 //
31 // In case of ENOMEM, we might as well exit. It's not clear
32 // when ESRCH is returned, but the racy case of the parent
33 // going away before we set up our kevent struct is handled
34 // by the pdeath function below, so it should be safe to ignore.
35 if (errno == ENOMEM) {
36 _exit(50);
37 }
38 return NULL;
39 }
40 }
41 return NULL;
42 }
43
pdeath()44 int pdeath() {
45 struct kevent ke;
46 pid_t ppid;
47
48 kqfd = kqueue();
49 if (kqfd == -1) {
50 return -1;
51 }
52
53 ppid = getppid();
54 if (ppid <= 1) {
55 _exit(0);
56 }
57
58 EV_SET(&ke, ppid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
59 if (HANDLE_EINTR(kevent(kqfd, &ke, 1, NULL, 0, NULL)) == -1) {
60 // Parent seemingly already dead.
61 if (errno == ESRCH) {
62 _exit(0);
63 }
64 return -1;
65 }
66
67 pthread_t thr;
68 if (pthread_create(&thr, NULL, pdeath_monitor, NULL) == -1) {
69 return -1;
70 }
71
72 if (getppid() <= 1) {
73 _exit(0);
74 }
75
76 return 0;
77 }
78