deadlock when stop gstreamer

Shuke shuke987 at qq.com
Thu Jan 17 09:49:16 UTC 2019


We call gst_alloc to start a gstreamer, which will create another thread to
do the main loop. And before EOF was retrieved, we'll call gst_destructor to
tell main loop to quit, which will call gst_element_set_state, which cause
deadlock with pipeline thread.

Deadlock is not always occurs, it occurs once in thousands.

Thanks a lot.


Source code is pasted below.


struct ausrc_st {
	const struct ausrc *as;     /**< Inheritance             */

	pthread_t tid;              /**< Thread ID               */
	bool run;                   /**< Running flag            */
   
    ...

	/* Gstreamer */
	char *uri;
	GstElement *pipeline, *bin, *source, *capsfilt, *sink;
	GMainLoop *loop;
};

static void *thread(void *arg)
{
	struct ausrc_st *st = arg;
	gst_element_set_state(st->pipeline, GST_STATE_PLAYING);

	while (st->run) {
		g_main_loop_run(st->loop);
	}

	//deadlock will happen in this line
	gst_element_set_state(st->pipeline, GST_STATE_NULL);
	return NULL;
}


static gboolean bus_watch_handler(GstBus *bus, GstMessage *msg, gpointer
data)
{
	struct ausrc_st *st = data;
	GMainLoop *loop = st->loop;
	(void)bus;
	switch (GST_MESSAGE_TYPE(msg)) {

	case GST_MESSAGE_EOS:

		break;

	case GST_MESSAGE_ERROR:
		st->run = false;
		g_main_loop_quit(loop);
		break;
	default:
		break;
	}

	return TRUE;
}


static void handoff_handler(GstFakeSink *fakesink, GstBuffer *buffer,
                            GstPad *pad, gpointer user_data)
{
	struct ausrc_st *st = user_data;

	(void)fakesink;
	(void)pad;

	// ... get data from buffer and sleep.
}

/**
 * Set up the Gstreamer pipeline. The playbin element is used to decode
 * all kinds of different formats. The capsfilter is used to deliver the
 * audio in a fixed format (X Hz, 1-2 channels, 16 bit signed)
 *
 * The pipeline looks like this:
 *
 * <pre>
 *  .--------------.    .------------------------------------------.
 *  |    playbin   |    |mybin    .------------.   .------------.  |
 *  |----.    .----|    |-----.   | capsfilter |   |  fakesink  |  |
 *  |sink|    |src |--->|ghost|   |----.   .---|   |----.   .---|  |   
handoff
 *  |----'    '----|    |pad  |-->|sink|   |src|-->|sink|   |src|--+-->
handler
 *  |              |    |-----'   '------------'   '------------'  |
 *  '--------------'    '------------------------------------------'
 * </pre>
 *
 * @param st Audio source state
 *
 * @return 0 if success, otherwise errorcode
 */

static int gst_setup(struct ausrc_st *st)
{
	GstBus *bus;
	GstPad *pad;

	st->loop = g_main_loop_new(NULL, FALSE);

	st->pipeline = gst_pipeline_new("pipeline");
	if (!st->pipeline) {
		warning("gst: failed to create pipeline element\n");
		return ENOMEM;
	}

	/********************* Player BIN **************************/

	st->source = gst_element_factory_make("playbin", "source");
	if (!st->source) {
		warning("gst: failed to create playbin source element\n");
		return ENOMEM;
	}

	/********************* My BIN **************************/

	st->bin = gst_bin_new("mybin");

	st->capsfilt = gst_element_factory_make("capsfilter", NULL);
	if (!st->capsfilt) {
		warning("gst: failed to create capsfilter element\n");
		return ENOMEM;
	}

	set_caps(st);

	st->sink = gst_element_factory_make("fakesink", "sink");
	if (!st->sink) {
		warning("gst: failed to create sink element\n");
		return ENOMEM;
	}

	gst_bin_add_many(GST_BIN(st->bin), st->capsfilt, st->sink, NULL);
	gst_element_link_many(st->capsfilt, st->sink, NULL);

	/* add ghostpad */
	pad = gst_element_get_pad(st->capsfilt, "sink");
	gst_element_add_pad(st->bin, gst_ghost_pad_new("sink", pad));
	gst_object_unref(GST_OBJECT(pad));

	/* put all elements in a bin */
	gst_bin_add_many(GST_BIN(st->pipeline), st->source, NULL);

	/* Override audio-sink handoff handler */
	g_object_set(G_OBJECT(st->sink), "signal-handoffs", TRUE, NULL);
	g_signal_connect(st->sink, "handoff", G_CALLBACK(handoff_handler), st);
	g_object_set(G_OBJECT(st->source), "audio-sink", st->bin, NULL);

	/********************* Misc **************************/

	/* Bus watch */
	bus = gst_pipeline_get_bus(GST_PIPELINE(st->pipeline));
	gst_bus_add_watch(bus, bus_watch_handler, st);
	gst_object_unref(bus);

	/* Set URI */
	g_object_set(G_OBJECT(st->source), "uri", st->uri, NULL);

	return 0;
}



static void gst_destructor(void *arg)
{
	struct ausrc_st *st = arg;
	int err = 0;
	if (st->run) {
		st->run = false;
		g_main_loop_quit(st->loop);
		err = pthread_join(st->tid, NULL);
	}
	//deadlock will happen in this line
	gst_element_set_state(st->pipeline, GST_STATE_NULL);
	gst_object_unref(GST_OBJECT(st->pipeline));
	mem_deref(st->call_id);
	mem_deref(st->uri);
	mem_deref(st->aubuf);
}


static int gst_alloc(struct ausrc_st **stp, const struct ausrc *as,
                     struct media_ctx **ctx,
                     struct ausrc_prm *prm, const char *device, const char
*call_id,
                     ausrc_read_h *rh, ausrc_error_h *errh, void *arg)
{
	struct ausrc_st *st;
	int err;
	(void)ctx;
	err = gst_setup(st);
	if (err)
		goto out;

	st->run  = true;
	err = pthread_create(&st->tid, NULL, thread, st);
	if (err) {
		st->run = false;
		goto out;
	}

out:
	if (err)
		mem_deref(st);
	else
		*stp = st;

	return err;
}



--
Sent from: http://gstreamer-devel.966125.n4.nabble.com/


More information about the gstreamer-devel mailing list