pasuspender: Resume before exiting in case of SIGINT or fork() failure.

Pressing Ctrl-C in a terminal while pasuspender is running
causes the sinks and sources to stay suspended after
pasuspender has exited, which is very annoying. This patch
fixes that problem, and also a similar problem with fork()
failures.
This commit is contained in:
Tanu Kaskinen 2012-06-13 12:45:16 +03:00 committed by Arun Raghavan
parent a7567b78e3
commit 5237bab36e

View file

@ -52,6 +52,7 @@ static int child_argc = 0;
static pid_t child_pid = (pid_t) -1; static pid_t child_pid = (pid_t) -1;
static int child_ret = 0; static int child_ret = 0;
static int dead = 1; static int dead = 1;
static int fork_failed = 0;
static void quit(int ret) { static void quit(int ret) {
pa_assert(mainloop_api); pa_assert(mainloop_api);
@ -66,18 +67,22 @@ static void context_drain_complete(pa_context *c, void *userdata) {
static void drain(void) { static void drain(void) {
pa_operation *o; pa_operation *o;
if (!(o = pa_context_drain(context, context_drain_complete, NULL))) if (context) {
pa_context_disconnect(context); if (!(o = pa_context_drain(context, context_drain_complete, NULL)))
else pa_context_disconnect(context);
pa_operation_unref(o); else
pa_operation_unref(o);
} else
quit(0);
} }
static void start_child(void) { static int start_child(void) {
if ((child_pid = fork()) < 0) { if ((child_pid = fork()) < 0) {
fprintf(stderr, _("fork(): %s\n"), strerror(errno)); fprintf(stderr, _("fork(): %s\n"), strerror(errno));
quit(1); fork_failed = 1;
return -1;
} else if (child_pid == 0) { } else if (child_pid == 0) {
/* Child */ /* Child */
@ -96,21 +101,8 @@ static void start_child(void) {
/* parent */ /* parent */
dead = 0; dead = 0;
} }
}
static void suspend_complete(pa_context *c, int success, void *userdata) { return 0;
static int n = 0;
n++;
if (!success) {
fprintf(stderr, _("Failure to suspend: %s\n"), pa_strerror(pa_context_errno(c)));
quit(1);
return;
}
if (n >= 2)
start_child();
} }
static void resume_complete(pa_context *c, int success, void *userdata) { static void resume_complete(pa_context *c, int success, void *userdata) {
@ -128,6 +120,42 @@ static void resume_complete(pa_context *c, int success, void *userdata) {
drain(); /* drain and quit */ drain(); /* drain and quit */
} }
static void resume(void) {
static int n = 0;
n++;
if (n > 1)
return;
if (context) {
if (pa_context_is_local(context)) {
pa_operation_unref(pa_context_suspend_sink_by_index(context, PA_INVALID_INDEX, 0, resume_complete, NULL));
pa_operation_unref(pa_context_suspend_source_by_index(context, PA_INVALID_INDEX, 0, resume_complete, NULL));
} else
drain();
} else {
quit(0);
}
}
static void suspend_complete(pa_context *c, int success, void *userdata) {
static int n = 0;
n++;
if (!success) {
fprintf(stderr, _("Failure to suspend: %s\n"), pa_strerror(pa_context_errno(c)));
quit(1);
return;
}
if (n >= 2) {
if (start_child() < 0)
resume();
}
}
static void context_state_callback(pa_context *c, void *userdata) { static void context_state_callback(pa_context *c, void *userdata) {
pa_assert(c); pa_assert(c);
@ -143,7 +171,8 @@ static void context_state_callback(pa_context *c, void *userdata) {
pa_operation_unref(pa_context_suspend_source_by_index(c, PA_INVALID_INDEX, 1, suspend_complete, NULL)); pa_operation_unref(pa_context_suspend_source_by_index(c, PA_INVALID_INDEX, 1, suspend_complete, NULL));
} else { } else {
fprintf(stderr, _("WARNING: Sound server is not local, not suspending.\n")); fprintf(stderr, _("WARNING: Sound server is not local, not suspending.\n"));
start_child(); if (start_child() < 0)
drain();
} }
break; break;
@ -159,10 +188,11 @@ static void context_state_callback(pa_context *c, void *userdata) {
pa_context_unref(context); pa_context_unref(context);
context = NULL; context = NULL;
if (child_pid == (pid_t) -1) if (child_pid == (pid_t) -1) {
/* not started yet, then we do it now */ /* not started yet, then we do it now */
start_child(); if (start_child() < 0)
else if (dead) quit(1);
} else if (dead)
/* already started, and dead, so let's quit */ /* already started, and dead, so let's quit */
quit(1); quit(1);
@ -172,7 +202,7 @@ static void context_state_callback(pa_context *c, void *userdata) {
static void sigint_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) { static void sigint_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) {
fprintf(stderr, _("Got SIGINT, exiting.\n")); fprintf(stderr, _("Got SIGINT, exiting.\n"));
quit(0); resume();
} }
static void sigchld_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) { static void sigchld_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) {
@ -193,16 +223,7 @@ static void sigchld_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, vo
child_ret = 1; child_ret = 1;
} }
if (context) { resume();
if (pa_context_is_local(context)) {
/* A context is around, so let's resume */
pa_operation_unref(pa_context_suspend_sink_by_index(context, PA_INVALID_INDEX, 0, resume_complete, NULL));
pa_operation_unref(pa_context_suspend_source_by_index(context, PA_INVALID_INDEX, 0, resume_complete, NULL));
} else
drain();
} else
/* Hmm, no context here, so let's terminate right away */
quit(0);
} }
static void help(const char *argv0) { static void help(const char *argv0) {
@ -303,6 +324,9 @@ int main(int argc, char *argv[]) {
goto quit; goto quit;
} }
if (ret == 0 && fork_failed)
ret = 1;
quit: quit:
if (context) if (context)
pa_context_unref(context); pa_context_unref(context);