mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
gst-launch: Use g_unix_signal_add() to handle keyboard interruption
Current implementation uses a traditional signal handler and a 250ms timeout callback in the event loop. Adding a GSource with g_unix_signal_add() to the GMainLoop is a much more elegant solution. The signal handler with this approach can send a message to the bus directly rather than set a flag as all dispatching intricacies are handled by GLib. https://bugzilla.gnome.org/show_bug.cgi?id=693481
This commit is contained in:
parent
651ed1acd8
commit
6099b35f7e
1 changed files with 29 additions and 118 deletions
|
@ -25,36 +25,25 @@
|
||||||
# include "config.h"
|
# include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* FIXME: hack alert */
|
#include <glib.h>
|
||||||
#ifdef HAVE_WIN32
|
|
||||||
#define DISABLE_FAULT_HANDLER
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
#ifndef DISABLE_FAULT_HANDLER
|
#ifdef G_OS_UNIX
|
||||||
|
#include <glib-unix.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#endif
|
#endif
|
||||||
#include <locale.h> /* for LC_ALL */
|
#include <locale.h> /* for LC_ALL */
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
/* FIXME: This is just a temporary hack. We should have a better
|
|
||||||
* check for siginfo handling. */
|
|
||||||
#ifdef SA_SIGINFO
|
|
||||||
#define USE_SIGINFO
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern volatile gboolean glib_on_error_halt;
|
extern volatile gboolean glib_on_error_halt;
|
||||||
|
|
||||||
#ifndef DISABLE_FAULT_HANDLER
|
#ifdef G_OS_UNIX
|
||||||
static void fault_restore (void);
|
static void fault_restore (void);
|
||||||
static void fault_spin (void);
|
static void fault_spin (void);
|
||||||
static void sigint_restore (void);
|
|
||||||
static gboolean caught_intr = FALSE;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* event_loop return codes */
|
/* event_loop return codes */
|
||||||
|
@ -77,8 +66,7 @@ static gboolean waiting_eos = FALSE;
|
||||||
/* convenience macro so we don't have to litter the code with if(!quiet) */
|
/* convenience macro so we don't have to litter the code with if(!quiet) */
|
||||||
#define PRINT if(!quiet)g_print
|
#define PRINT if(!quiet)g_print
|
||||||
|
|
||||||
#ifndef DISABLE_FAULT_HANDLER
|
#ifdef G_OS_UNIX
|
||||||
#ifndef USE_SIGINFO
|
|
||||||
static void
|
static void
|
||||||
fault_handler_sighandler (int signum)
|
fault_handler_sighandler (int signum)
|
||||||
{
|
{
|
||||||
|
@ -102,34 +90,6 @@ fault_handler_sighandler (int signum)
|
||||||
fault_spin ();
|
fault_spin ();
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* USE_SIGINFO */
|
|
||||||
|
|
||||||
static void
|
|
||||||
fault_handler_sigaction (int signum, siginfo_t * si, void *misc)
|
|
||||||
{
|
|
||||||
fault_restore ();
|
|
||||||
|
|
||||||
/* printf is used instead of g_print(), since it's less likely to
|
|
||||||
* deadlock */
|
|
||||||
switch (si->si_signo) {
|
|
||||||
case SIGSEGV:
|
|
||||||
fprintf (stderr, "Caught SIGSEGV accessing address %p\n", si->si_addr);
|
|
||||||
break;
|
|
||||||
case SIGQUIT:
|
|
||||||
if (!quiet)
|
|
||||||
printf ("Caught SIGQUIT\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf (stderr, "signo: %d\n", si->si_signo);
|
|
||||||
fprintf (stderr, "errno: %d\n", si->si_errno);
|
|
||||||
fprintf (stderr, "code: %d\n", si->si_code);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
fault_spin ();
|
|
||||||
}
|
|
||||||
#endif /* USE_SIGINFO */
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fault_spin (void)
|
fault_spin (void)
|
||||||
{
|
{
|
||||||
|
@ -167,17 +127,12 @@ fault_setup (void)
|
||||||
struct sigaction action;
|
struct sigaction action;
|
||||||
|
|
||||||
memset (&action, 0, sizeof (action));
|
memset (&action, 0, sizeof (action));
|
||||||
#ifdef USE_SIGINFO
|
|
||||||
action.sa_sigaction = fault_handler_sigaction;
|
|
||||||
action.sa_flags = SA_SIGINFO;
|
|
||||||
#else
|
|
||||||
action.sa_handler = fault_handler_sighandler;
|
action.sa_handler = fault_handler_sighandler;
|
||||||
#endif
|
|
||||||
|
|
||||||
sigaction (SIGSEGV, &action, NULL);
|
sigaction (SIGSEGV, &action, NULL);
|
||||||
sigaction (SIGQUIT, &action, NULL);
|
sigaction (SIGQUIT, &action, NULL);
|
||||||
}
|
}
|
||||||
#endif /* DISABLE_FAULT_HANDLER */
|
#endif /* G_OS_UNIX */
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
typedef struct _GstIndexStats
|
typedef struct _GstIndexStats
|
||||||
|
@ -503,70 +458,27 @@ print_toc_entry (gpointer data, gpointer user_data)
|
||||||
g_list_foreach (subentries, print_toc_entry, GUINT_TO_POINTER (indent));
|
g_list_foreach (subentries, print_toc_entry, GUINT_TO_POINTER (indent));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef DISABLE_FAULT_HANDLER
|
#ifdef G_OS_UNIX
|
||||||
/* we only use sighandler here because the registers are not important */
|
/* As the interrupt handler is dispatched from GMainContext as a GSourceFunc
|
||||||
static void
|
* handler, we can react to this by posting a message. */
|
||||||
sigint_handler_sighandler (int signum)
|
|
||||||
{
|
|
||||||
PRINT ("Caught interrupt -- ");
|
|
||||||
|
|
||||||
/* If we were waiting for an EOS, we still want to catch
|
|
||||||
* the next signal to shutdown properly (and the following one
|
|
||||||
* will quit the program). */
|
|
||||||
if (waiting_eos) {
|
|
||||||
waiting_eos = FALSE;
|
|
||||||
} else {
|
|
||||||
sigint_restore ();
|
|
||||||
}
|
|
||||||
/* we set a flag that is checked by the mainloop, we cannot do much in the
|
|
||||||
* interrupt handler (no mutex or other blocking stuff) */
|
|
||||||
caught_intr = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* is called every 250 milliseconds (4 times a second), the interrupt handler
|
|
||||||
* will set a flag for us. We react to this by posting a message. */
|
|
||||||
static gboolean
|
static gboolean
|
||||||
check_intr (GstElement * pipeline)
|
intr_handler (gpointer user_data)
|
||||||
{
|
{
|
||||||
if (!caught_intr) {
|
GstElement *pipeline = (GstElement *) user_data;
|
||||||
return TRUE;
|
|
||||||
} else {
|
|
||||||
caught_intr = FALSE;
|
|
||||||
PRINT ("handling interrupt.\n");
|
|
||||||
|
|
||||||
/* post an application specific message */
|
PRINT ("handling interrupt.\n");
|
||||||
gst_element_post_message (GST_ELEMENT (pipeline),
|
|
||||||
gst_message_new_application (GST_OBJECT (pipeline),
|
|
||||||
gst_structure_new ("GstLaunchInterrupt",
|
|
||||||
"message", G_TYPE_STRING, "Pipeline interrupted", NULL)));
|
|
||||||
|
|
||||||
/* remove timeout handler */
|
/* post an application specific message */
|
||||||
return FALSE;
|
gst_element_post_message (GST_ELEMENT (pipeline),
|
||||||
}
|
gst_message_new_application (GST_OBJECT (pipeline),
|
||||||
|
gst_structure_new ("GstLaunchInterrupt",
|
||||||
|
"message", G_TYPE_STRING, "Pipeline interrupted", NULL)));
|
||||||
|
|
||||||
|
/* remove signal handler */
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
#endif /* G_OS_UNIX */
|
||||||
sigint_setup (void)
|
|
||||||
{
|
|
||||||
struct sigaction action;
|
|
||||||
|
|
||||||
memset (&action, 0, sizeof (action));
|
|
||||||
action.sa_handler = sigint_handler_sighandler;
|
|
||||||
|
|
||||||
sigaction (SIGINT, &action, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
sigint_restore (void)
|
|
||||||
{
|
|
||||||
struct sigaction action;
|
|
||||||
|
|
||||||
memset (&action, 0, sizeof (action));
|
|
||||||
action.sa_handler = SIG_DFL;
|
|
||||||
|
|
||||||
sigaction (SIGINT, &action, NULL);
|
|
||||||
}
|
|
||||||
#endif /* DISABLE_FAULT_HANDLER */
|
|
||||||
|
|
||||||
/* returns ELR_ERROR if there was an error
|
/* returns ELR_ERROR if there was an error
|
||||||
* or ELR_INTERRUPT if we caught a keyboard interrupt
|
* or ELR_INTERRUPT if we caught a keyboard interrupt
|
||||||
|
@ -574,8 +486,8 @@ sigint_restore (void)
|
||||||
static EventLoopResult
|
static EventLoopResult
|
||||||
event_loop (GstElement * pipeline, gboolean blocking, GstState target_state)
|
event_loop (GstElement * pipeline, gboolean blocking, GstState target_state)
|
||||||
{
|
{
|
||||||
#ifndef DISABLE_FAULT_HANDLER
|
#ifdef G_OS_UNIX
|
||||||
gulong timeout_id;
|
guint signal_watch_id;
|
||||||
#endif
|
#endif
|
||||||
GstBus *bus;
|
GstBus *bus;
|
||||||
GstMessage *message = NULL;
|
GstMessage *message = NULL;
|
||||||
|
@ -584,8 +496,9 @@ event_loop (GstElement * pipeline, gboolean blocking, GstState target_state)
|
||||||
|
|
||||||
bus = gst_element_get_bus (GST_ELEMENT (pipeline));
|
bus = gst_element_get_bus (GST_ELEMENT (pipeline));
|
||||||
|
|
||||||
#ifndef DISABLE_FAULT_HANDLER
|
#ifdef G_OS_UNIX
|
||||||
timeout_id = g_timeout_add (250, (GSourceFunc) check_intr, pipeline);
|
signal_watch_id =
|
||||||
|
g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
|
@ -856,8 +769,8 @@ exit:
|
||||||
if (message)
|
if (message)
|
||||||
gst_message_unref (message);
|
gst_message_unref (message);
|
||||||
gst_object_unref (bus);
|
gst_object_unref (bus);
|
||||||
#ifndef DISABLE_FAULT_HANDLER
|
#ifdef G_OS_UNIX
|
||||||
g_source_remove (timeout_id);
|
g_source_remove (signal_watch_id);
|
||||||
#endif
|
#endif
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -981,11 +894,9 @@ main (int argc, char *argv[])
|
||||||
|
|
||||||
gst_tools_print_version ();
|
gst_tools_print_version ();
|
||||||
|
|
||||||
#ifndef DISABLE_FAULT_HANDLER
|
#ifdef G_OS_UNIX
|
||||||
if (!no_fault)
|
if (!no_fault)
|
||||||
fault_setup ();
|
fault_setup ();
|
||||||
|
|
||||||
sigint_setup ();
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* make a null-terminated version of argv */
|
/* make a null-terminated version of argv */
|
||||||
|
|
Loading…
Reference in a new issue