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