summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRom Lemarchand2013-03-20 15:46:53 -0500
committerRom Lemarchand2013-03-20 18:26:22 -0500
commit6ad53df6335520befee74efafca41d625baa9023 (patch)
tree9322d7f88f97f808bfe4bccc98c130589ff4dc67 /logwrapper/logwrap.c
parent7bce39cac65166f39d0f26453da6e59e236d2ab5 (diff)
downloadplatform-system-core-6ad53df6335520befee74efafca41d625baa9023.tar.gz
platform-system-core-6ad53df6335520befee74efafca41d625baa9023.tar.xz
platform-system-core-6ad53df6335520befee74efafca41d625baa9023.zip
liblogwrap: use POLLHUP flag to check when a child dies
Replace the old signal handling mechanism with a check of POLLHUP to check when the child has died. See http://b/8333626 Change-Id: Ic9909b6660b1c3d1ed3015568b1a1ee1c25afe20
Diffstat (limited to 'logwrapper/logwrap.c')
-rw-r--r--logwrapper/logwrap.c151
1 files changed, 49 insertions, 102 deletions
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 129ffb131..bf9197759 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -17,7 +17,6 @@
17#include <string.h> 17#include <string.h>
18#include <sys/types.h> 18#include <sys/types.h>
19#include <sys/socket.h> 19#include <sys/socket.h>
20#include <signal.h>
21#include <poll.h> 20#include <poll.h>
22#include <sys/wait.h> 21#include <sys/wait.h>
23#include <stdio.h> 22#include <stdio.h>
@@ -35,7 +34,6 @@
35 34
36#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) 35#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
37 36
38static int signal_fd_write;
39static pthread_mutex_t fd_mutex = PTHREAD_MUTEX_INITIALIZER; 37static pthread_mutex_t fd_mutex = PTHREAD_MUTEX_INITIALIZER;
40 38
41#define ERROR(fmt, args...) \ 39#define ERROR(fmt, args...) \
@@ -50,94 +48,77 @@ do { \
50 _exit(-1); \ 48 _exit(-1); \
51} while(0) 49} while(0)
52 50
53static int parent(const char *tag, int parent_read, int signal_fd, pid_t pid, 51static int parent(const char *tag, int parent_read, pid_t pid, int *chld_sts,
54 int *chld_sts, bool logwrap) { 52 bool logwrap) {
55 int status = 0; 53 int status = 0;
56 char buffer[4096]; 54 char buffer[4096];
57 struct pollfd poll_fds[] = { 55 struct pollfd poll_fds[] = {
58 [0] = { 56 [0] = {
59 .fd = signal_fd,
60 .events = POLLIN,
61 },
62 [1] = {
63 .fd = parent_read, 57 .fd = parent_read,
64 .events = POLLIN, 58 .events = POLLIN,
65 }, 59 },
66 }; 60 };
67 int rc = 0; 61 int rc = 0;
68 sigset_t chldset;
69 62
70 int a = 0; // start index of unprocessed data 63 int a = 0; // start index of unprocessed data
71 int b = 0; // end index of unprocessed data 64 int b = 0; // end index of unprocessed data
72 int sz; 65 int sz;
73 bool remote_hung = false;
74 bool found_child = false; 66 bool found_child = false;
75 67
76 char *btag = basename(tag); 68 char *btag = basename(tag);
77 if (!btag) btag = (char*) tag; 69 if (!btag) btag = (char*) tag;
78 70
79 sigemptyset(&chldset);
80 sigaddset(&chldset, SIGCHLD);
81 pthread_sigmask(SIG_UNBLOCK, &chldset, NULL);
82
83 while (!found_child) { 71 while (!found_child) {
84 if (TEMP_FAILURE_RETRY(poll(poll_fds, remote_hung ? 1 : 2, -1)) < 0) { 72 if (TEMP_FAILURE_RETRY(poll(poll_fds, ARRAY_SIZE(poll_fds), -1)) < 0) {
85 ERROR("poll failed\n"); 73 ERROR("poll failed\n");
86 rc = -1; 74 rc = -1;
87 goto err_poll; 75 goto err_poll;
88 } 76 }
89 77
90 if (!remote_hung) { 78 if (poll_fds[0].revents & POLLIN) {
91 if (poll_fds[1].revents & POLLIN) { 79 sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b);
92 sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b);
93
94 sz += b;
95 // Log one line at a time
96 for (b = 0; b < sz; b++) {
97 if (buffer[b] == '\r') {
98 buffer[b] = '\0';
99 } else if (buffer[b] == '\n') {
100 buffer[b] = '\0';
101 if (logwrap)
102 ALOG(LOG_INFO, btag, "%s", &buffer[a]);
103 a = b + 1;
104 }
105 }
106 80
107 if (a == 0 && b == sizeof(buffer) - 1) { 81 sz += b;
108 // buffer is full, flush 82 // Log one line at a time
83 for (b = 0; b < sz; b++) {
84 if (buffer[b] == '\r') {
85 buffer[b] = '\0';
86 } else if (buffer[b] == '\n') {
109 buffer[b] = '\0'; 87 buffer[b] = '\0';
110 if (logwrap) 88 if (logwrap)
111 ALOG(LOG_INFO, btag, "%s", &buffer[a]); 89 ALOG(LOG_INFO, btag, "%s", &buffer[a]);
112 b = 0; 90 a = b + 1;
113 } else if (a != b) {
114 // Keep left-overs
115 b -= a;
116 memmove(buffer, &buffer[a], b);
117 a = 0;
118 } else {
119 a = 0;
120 b = 0;
121 } 91 }
122 } 92 }
123 93
124 if (poll_fds[1].revents & POLLHUP) { 94 if (a == 0 && b == sizeof(buffer) - 1) {
125 remote_hung = true; 95 // buffer is full, flush
96 buffer[b] = '\0';
97 if (logwrap)
98 ALOG(LOG_INFO, btag, "%s", &buffer[a]);
99 b = 0;
100 } else if (a != b) {
101 // Keep left-overs
102 b -= a;
103 memmove(buffer, &buffer[a], b);
104 a = 0;
105 } else {
106 a = 0;
107 b = 0;
126 } 108 }
127 } 109 }
128 110
129 if (poll_fds[0].revents & POLLIN) { 111 if (poll_fds[0].revents & POLLHUP) {
130 char tmp[32];
131 int ret; 112 int ret;
132 113
133 read(signal_fd, tmp, sizeof(tmp)); 114 ret = waitpid(pid, &status, WNOHANG);
134 while (!found_child) { 115 if (ret < 0) {
135 ret = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG)); 116 rc = errno;
136 117 ALOG(LOG_ERROR, "logwrap", "waitpid failed with %s\n", strerror(errno));
137 if (ret <= 0) 118 goto err_waitpid;
138 break; 119 }
139 120 if (ret > 0) {
140 found_child = (pid == ret); 121 found_child = true;
141 } 122 }
142 } 123 }
143 } 124 }
@@ -171,6 +152,7 @@ static int parent(const char *tag, int parent_read, int signal_fd, pid_t pid,
171 } 152 }
172 } 153 }
173 154
155err_waitpid:
174err_poll: 156err_poll:
175 return rc; 157 return rc;
176} 158}
@@ -187,23 +169,16 @@ static void child(int argc, char* argv[], bool logwrap) {
187 } 169 }
188} 170}
189 171
190static void sigchld_handler(int sig) {
191 write(signal_fd_write, &sig, 1);
192}
193
194int android_fork_execvp(int argc, char* argv[], int *status, bool ignore_int_quit, 172int android_fork_execvp(int argc, char* argv[], int *status, bool ignore_int_quit,
195 bool logwrap) { 173 bool logwrap) {
196 pid_t pid; 174 pid_t pid;
197 int parent_ptty; 175 int parent_ptty;
198 int child_ptty; 176 int child_ptty;
199 char *child_devname = NULL; 177 char *child_devname = NULL;
200 struct sigaction chldact;
201 struct sigaction oldchldact;
202 struct sigaction intact; 178 struct sigaction intact;
203 struct sigaction quitact; 179 struct sigaction quitact;
204 sigset_t blockset; 180 sigset_t blockset;
205 sigset_t oldset; 181 sigset_t oldset;
206 int sockets[2];
207 int rc = 0; 182 int rc = 0;
208 183
209 rc = pthread_mutex_lock(&fd_mutex); 184 rc = pthread_mutex_lock(&fd_mutex);
@@ -227,14 +202,21 @@ int android_fork_execvp(int argc, char* argv[], int *status, bool ignore_int_qui
227 goto err_ptty; 202 goto err_ptty;
228 } 203 }
229 204
205 child_ptty = open(child_devname, O_RDWR);
206 if (child_ptty < 0) {
207 ERROR("Cannot open child_ptty\n");
208 rc = -1;
209 goto err_child_ptty;
210 }
211
230 sigemptyset(&blockset); 212 sigemptyset(&blockset);
231 sigaddset(&blockset, SIGINT); 213 sigaddset(&blockset, SIGINT);
232 sigaddset(&blockset, SIGQUIT); 214 sigaddset(&blockset, SIGQUIT);
233 sigaddset(&blockset, SIGCHLD);
234 pthread_sigmask(SIG_BLOCK, &blockset, &oldset); 215 pthread_sigmask(SIG_BLOCK, &blockset, &oldset);
235 216
236 pid = fork(); 217 pid = fork();
237 if (pid < 0) { 218 if (pid < 0) {
219 close(child_ptty);
238 ERROR("Failed to fork\n"); 220 ERROR("Failed to fork\n");
239 rc = -1; 221 rc = -1;
240 goto err_fork; 222 goto err_fork;
@@ -243,12 +225,6 @@ int android_fork_execvp(int argc, char* argv[], int *status, bool ignore_int_qui
243 pthread_sigmask(SIG_SETMASK, &oldset, NULL); 225 pthread_sigmask(SIG_SETMASK, &oldset, NULL);
244 close(parent_ptty); 226 close(parent_ptty);
245 227
246 child_ptty = open(child_devname, O_RDWR);
247 if (child_ptty < 0) {
248 FATAL_CHILD("Problem with child ptty\n");
249 return -1;
250 }
251
252 // redirect stdout and stderr 228 // redirect stdout and stderr
253 dup2(child_ptty, 1); 229 dup2(child_ptty, 1);
254 dup2(child_ptty, 2); 230 dup2(child_ptty, 2);
@@ -256,55 +232,26 @@ int android_fork_execvp(int argc, char* argv[], int *status, bool ignore_int_qui
256 232
257 child(argc, argv, logwrap); 233 child(argc, argv, logwrap);
258 } else { 234 } else {
259 struct sigaction ignact; 235 close(child_ptty);
260
261 memset(&chldact, 0, sizeof(chldact));
262 chldact.sa_handler = sigchld_handler;
263 chldact.sa_flags = SA_NOCLDSTOP;
264
265 sigaction(SIGCHLD, &chldact, &oldchldact);
266 if ((!(oldchldact.sa_flags & SA_SIGINFO) &&
267 oldchldact.sa_handler != SIG_DFL &&
268 oldchldact.sa_handler != SIG_IGN) ||
269 ((oldchldact.sa_flags & SA_SIGINFO) &&
270 oldchldact.sa_sigaction != NULL)) {
271 ALOG(LOG_WARN, "logwrapper", "logwrap replaced the SIGCHLD "
272 "handler and might cause interaction issues");
273 }
274
275 if (ignore_int_quit) { 236 if (ignore_int_quit) {
237 struct sigaction ignact;
238
276 memset(&ignact, 0, sizeof(ignact)); 239 memset(&ignact, 0, sizeof(ignact));
277 ignact.sa_handler = SIG_IGN; 240 ignact.sa_handler = SIG_IGN;
278 sigaction(SIGINT, &ignact, &intact); 241 sigaction(SIGINT, &ignact, &intact);
279 sigaction(SIGQUIT, &ignact, &quitact); 242 sigaction(SIGQUIT, &ignact, &quitact);
280 } 243 }
281 244
282 rc = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets); 245 rc = parent(argv[0], parent_ptty, pid, status, logwrap);
283 if (rc == -1) {
284 ERROR("socketpair failed: %s\n", strerror(errno));
285 goto err_socketpair;
286 }
287
288 fcntl(sockets[0], F_SETFD, FD_CLOEXEC);
289 fcntl(sockets[0], F_SETFL, O_NONBLOCK);
290 fcntl(sockets[1], F_SETFD, FD_CLOEXEC);
291 fcntl(sockets[1], F_SETFL, O_NONBLOCK);
292
293 signal_fd_write = sockets[0];
294
295 rc = parent(argv[0], parent_ptty, sockets[1], pid, status, logwrap);
296 } 246 }
297 247
298 close(sockets[0]);
299 close(sockets[1]);
300err_socketpair:
301 if (ignore_int_quit) { 248 if (ignore_int_quit) {
302 sigaction(SIGINT, &intact, NULL); 249 sigaction(SIGINT, &intact, NULL);
303 sigaction(SIGQUIT, &quitact, NULL); 250 sigaction(SIGQUIT, &quitact, NULL);
304 } 251 }
305 sigaction(SIGCHLD, &oldchldact, NULL);
306err_fork: 252err_fork:
307 pthread_sigmask(SIG_SETMASK, &oldset, NULL); 253 pthread_sigmask(SIG_SETMASK, &oldset, NULL);
254err_child_ptty:
308err_ptty: 255err_ptty:
309 close(parent_ptty); 256 close(parent_ptty);
310err_open: 257err_open: