Skip to content

Commit 267ebf6

Browse files
committed
Merge branch 'ti/glibc-stdio-mutex-from-signal-handler' into maint
Allocation related functions and stdio are unsafe things to call inside a signal handler, and indeed killing the pager can cause glibc to deadlock waiting on allocation mutex as our signal handler tries to free() some data structures in wait_for_pager(). Reduce these unsafe calls. * ti/glibc-stdio-mutex-from-signal-handler: pager: don't use unsafe functions in signal handlers
2 parents f4892a3 + 507d780 commit 267ebf6

File tree

3 files changed

+34
-14
lines changed

3 files changed

+34
-14
lines changed

pager.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,29 @@
1414
static const char *pager_argv[] = { NULL, NULL };
1515
static struct child_process pager_process = CHILD_PROCESS_INIT;
1616

17-
static void wait_for_pager(void)
17+
static void wait_for_pager(int in_signal)
1818
{
19-
fflush(stdout);
20-
fflush(stderr);
19+
if (!in_signal) {
20+
fflush(stdout);
21+
fflush(stderr);
22+
}
2123
/* signal EOF to pager */
2224
close(1);
2325
close(2);
24-
finish_command(&pager_process);
26+
if (in_signal)
27+
finish_command_in_signal(&pager_process);
28+
else
29+
finish_command(&pager_process);
30+
}
31+
32+
static void wait_for_pager_atexit(void)
33+
{
34+
wait_for_pager(0);
2535
}
2636

2737
static void wait_for_pager_signal(int signo)
2838
{
29-
wait_for_pager();
39+
wait_for_pager(1);
3040
sigchain_pop(signo);
3141
raise(signo);
3242
}
@@ -90,7 +100,7 @@ void setup_pager(void)
90100

91101
/* this makes sure that the parent terminates after the pager */
92102
sigchain_push_common(wait_for_pager_signal);
93-
atexit(wait_for_pager);
103+
atexit(wait_for_pager_atexit);
94104
}
95105

96106
int pager_in_use(void)

run-command.c

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,27 @@ struct child_to_clean {
1818
static struct child_to_clean *children_to_clean;
1919
static int installed_child_cleanup_handler;
2020

21-
static void cleanup_children(int sig)
21+
static void cleanup_children(int sig, int in_signal)
2222
{
2323
while (children_to_clean) {
2424
struct child_to_clean *p = children_to_clean;
2525
children_to_clean = p->next;
2626
kill(p->pid, sig);
27-
free(p);
27+
if (!in_signal)
28+
free(p);
2829
}
2930
}
3031

3132
static void cleanup_children_on_signal(int sig)
3233
{
33-
cleanup_children(sig);
34+
cleanup_children(sig, 1);
3435
sigchain_pop(sig);
3536
raise(sig);
3637
}
3738

3839
static void cleanup_children_on_exit(void)
3940
{
40-
cleanup_children(SIGTERM);
41+
cleanup_children(SIGTERM, 0);
4142
}
4243

4344
static void mark_child_for_cleanup(pid_t pid)
@@ -220,14 +221,16 @@ static inline void set_cloexec(int fd)
220221
fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
221222
}
222223

223-
static int wait_or_whine(pid_t pid, const char *argv0)
224+
static int wait_or_whine(pid_t pid, const char *argv0, int in_signal)
224225
{
225226
int status, code = -1;
226227
pid_t waiting;
227228
int failed_errno = 0;
228229

229230
while ((waiting = waitpid(pid, &status, 0)) < 0 && errno == EINTR)
230231
; /* nothing */
232+
if (in_signal)
233+
return 0;
231234

232235
if (waiting < 0) {
233236
failed_errno = errno;
@@ -437,7 +440,7 @@ int start_command(struct child_process *cmd)
437440
* At this point we know that fork() succeeded, but execvp()
438441
* failed. Errors have been reported to our stderr.
439442
*/
440-
wait_or_whine(cmd->pid, cmd->argv[0]);
443+
wait_or_whine(cmd->pid, cmd->argv[0], 0);
441444
failed_errno = errno;
442445
cmd->pid = -1;
443446
}
@@ -536,12 +539,18 @@ int start_command(struct child_process *cmd)
536539

537540
int finish_command(struct child_process *cmd)
538541
{
539-
int ret = wait_or_whine(cmd->pid, cmd->argv[0]);
542+
int ret = wait_or_whine(cmd->pid, cmd->argv[0], 0);
540543
argv_array_clear(&cmd->args);
541544
argv_array_clear(&cmd->env_array);
542545
return ret;
543546
}
544547

548+
int finish_command_in_signal(struct child_process *cmd)
549+
{
550+
return wait_or_whine(cmd->pid, cmd->argv[0], 1);
551+
}
552+
553+
545554
int run_command(struct child_process *cmd)
546555
{
547556
int code;
@@ -772,7 +781,7 @@ int start_async(struct async *async)
772781
int finish_async(struct async *async)
773782
{
774783
#ifdef NO_PTHREADS
775-
return wait_or_whine(async->pid, "child process");
784+
return wait_or_whine(async->pid, "child process", 0);
776785
#else
777786
void *ret = (void *)(intptr_t)(-1);
778787

run-command.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ void child_process_init(struct child_process *);
5050

5151
int start_command(struct child_process *);
5252
int finish_command(struct child_process *);
53+
int finish_command_in_signal(struct child_process *);
5354
int run_command(struct child_process *);
5455

5556
/*

0 commit comments

Comments
 (0)