tor  0.4.1.0-alpha-dev
waitpid.c
Go to the documentation of this file.
1 /* Copyright (c) 2003-2004, Roger Dingledine
2  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3  * Copyright (c) 2007-2019, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
5 
11 #include "orconfig.h"
12 
13 #ifndef _WIN32
14 
15 #include "lib/process/waitpid.h"
16 #include "lib/log/log.h"
17 #include "lib/log/util_bug.h"
18 #include "lib/malloc/malloc.h"
19 #include "ext/ht.h"
20 
21 #ifdef HAVE_SYS_WAIT_H
22 #include <sys/wait.h>
23 #endif
24 
25 #include <string.h>
26 
27 /* ================================================== */
28 /* Convenience structures for handlers for waitpid().
29  *
30  * The tor_process_monitor*() code above doesn't use them, since it is for
31  * monitoring a non-child process.
32  */
33 
36  HT_ENTRY(waitpid_callback_t) node;
37  pid_t pid;
38 
39  void (*userfn)(int, void *userdata);
40  void *userdata;
41 
42  unsigned running;
43 };
44 
45 static inline unsigned int
46 process_map_entry_hash_(const waitpid_callback_t *ent)
47 {
48  return (unsigned) ent->pid;
49 }
50 
51 static inline unsigned int
52 process_map_entries_eq_(const waitpid_callback_t *a,
53  const waitpid_callback_t *b)
54 {
55  return a->pid == b->pid;
56 }
57 
58 static HT_HEAD(process_map, waitpid_callback_t) process_map = HT_INITIALIZER();
59 
60 HT_PROTOTYPE(process_map, waitpid_callback_t, node, process_map_entry_hash_,
61  process_map_entries_eq_)
62 HT_GENERATE2(process_map, waitpid_callback_t, node, process_map_entry_hash_,
63  process_map_entries_eq_, 0.6, tor_reallocarray_, tor_free_)
64 
65 
74 set_waitpid_callback(pid_t pid, void (*fn)(int, void *), void *arg)
75 {
76  waitpid_callback_t *old_ent;
77  waitpid_callback_t *ent = tor_malloc_zero(sizeof(waitpid_callback_t));
78  ent->pid = pid;
79  ent->userfn = fn;
80  ent->userdata = arg;
81  ent->running = 1;
82 
83  old_ent = HT_REPLACE(process_map, &process_map, ent);
84  if (old_ent) {
85  log_warn(LD_BUG, "Replaced a waitpid monitor on pid %u. That should be "
86  "impossible.", (unsigned) pid);
87  old_ent->running = 0;
88  }
89 
90  return ent;
91 }
92 
97 void
99 {
100  waitpid_callback_t *old_ent;
101  if (ent == NULL)
102  return;
103 
104  if (ent->running) {
105  old_ent = HT_REMOVE(process_map, &process_map, ent);
106  if (old_ent != ent) {
107  log_warn(LD_BUG, "Couldn't remove waitpid monitor for pid %u.",
108  (unsigned) ent->pid);
109  return;
110  }
111  }
112 
113  tor_free(ent);
114 }
115 
118 static void
119 notify_waitpid_callback_by_pid(pid_t pid, int status)
120 {
121  waitpid_callback_t search, *ent;
122 
123  search.pid = pid;
124  ent = HT_REMOVE(process_map, &process_map, &search);
125  if (!ent || !ent->running) {
126  log_info(LD_GENERAL, "Child process %u has exited; no callback was "
127  "registered", (unsigned)pid);
128  return;
129  }
130 
131  log_info(LD_GENERAL, "Child process %u has exited; running callback.",
132  (unsigned)pid);
133 
134  ent->running = 0;
135  ent->userfn(status, ent->userdata);
136 }
137 
140 void
142 {
143  /* I was going to call this function reap_zombie_children(), but
144  * that makes it sound way more exciting than it really is. */
145  pid_t child;
146  int status = 0;
147 
148  while ((child = waitpid(-1, &status, WNOHANG)) > 0) {
149  notify_waitpid_callback_by_pid(child, status);
150  status = 0; /* should be needless */
151  }
152 }
153 
154 #endif /* !defined(_WIN32) */
void notify_pending_waitpid_callbacks(void)
Definition: waitpid.c:141
Headers for waitpid.c.
#define LD_GENERAL
Definition: log.h:58
HT_PROTOTYPE(HT_GENERATE2(strmap_impl, HT_GENERATE2(strmap_entry_t, HT_GENERATE2(node, HT_GENERATE2(strmap_entry_hash, HT_GENERATE2(strmap_entries_eq)
Definition: map.c:87
void clear_waitpid_callback(waitpid_callback_t *ent)
Definition: waitpid.c:98
#define tor_free(p)
Definition: malloc.h:52
Headers for util_malloc.c.
void * tor_reallocarray_(void *ptr, size_t sz1, size_t sz2)
Definition: malloc.c:146
void tor_free_(void *mem)
Definition: malloc.c:227
static void notify_waitpid_callback_by_pid(pid_t pid, int status)
Definition: waitpid.c:119
Headers for log.c.
Macros to manage assertions, fatal and non-fatal.
#define LD_BUG
Definition: log.h:82