From b5a7d0ae48d7ae6077328d6260e7911d6b6ad805 Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Sat, 16 Mar 2024 00:07:49 +0900 Subject: [PATCH] gst: Add gst_deinit_register_notify() API Add an API so that user can install a callback function to be called when gst_deinit() is executed, then performs library specific teardown operations such as clearing resources or reporting live objects. --- subprojects/gstreamer/gst/gst.c | 58 +++++++++++++++++++ subprojects/gstreamer/gst/gst.h | 12 ++++ .../gstreamer/tests/check/gst/gstdeinit2.c | 49 ++++++++++++++++ subprojects/gstreamer/tests/check/meson.build | 1 + 4 files changed, 120 insertions(+) create mode 100644 subprojects/gstreamer/tests/check/gst/gstdeinit2.c diff --git a/subprojects/gstreamer/gst/gst.c b/subprojects/gstreamer/gst/gst.c index d766d16d56..b7874c9204 100644 --- a/subprojects/gstreamer/gst/gst.c +++ b/subprojects/gstreamer/gst/gst.c @@ -172,6 +172,23 @@ static gboolean parse_goption_arg (const gchar * s_opt, GSList *_priv_gst_preload_plugins = NULL; +/* deinit callbacks */ +static GList *_gst_deinit_notifies = NULL; + +typedef struct _GstDeinitNotify +{ + GstDeinitNotifyFunc func; + gpointer user_data; +} GstDeinitNotify; + +static void +gst_deinit_notify_free (GstDeinitNotify * cb) +{ + if (cb->func) + cb->func (cb->user_data); + g_free (cb); +} + enum { ARG_VERSION = 1, @@ -1092,6 +1109,10 @@ gst_deinit (void) } GST_INFO ("deinitializing GStreamer"); + + g_list_free_full (_gst_deinit_notifies, + (GDestroyNotify) gst_deinit_notify_free); + g_thread_pool_set_max_unused_threads (0); bin_class = (GstBinClass *) g_type_class_peek (gst_bin_get_type ()); if (bin_class && bin_class->pool != NULL) { @@ -1326,3 +1347,40 @@ gst_segtrap_set_enabled (gboolean enabled) { _gst_disable_segtrap = !enabled; } + +/** + * gst_deinit_register_notify: + * @func: (scope async): a #GstDeinitNotifyFunc + * @user_data: (nullable): private user data + * + * Registers a callback notified when gst_deinit() is called. + * This could be useful for a GStreamer library where the library holds + * persistent resources but prefers the resources to be released + * when gst_deinit() is called, so that any expected resource leaks + * (either GStreamer object or native handle/memory) can be addressed. + * + * Applications or GStreamer components can register callbacks + * before GStreamer is initialized, but installing notify after gst_deinit() + * is not allowed. + * + * Since: 1.26 + */ +void +gst_deinit_register_notify (GstDeinitNotifyFunc func, gpointer user_data) +{ + GstDeinitNotify *cb; + + g_rec_mutex_lock (&init_lock); + if (gst_deinitialized) { + g_warning ("GStreamer was deinitialized already."); + g_rec_mutex_unlock (&init_lock); + return; + } + + cb = g_new0 (GstDeinitNotify, 1); + cb->func = func; + cb->user_data = user_data; + + _gst_deinit_notifies = g_list_prepend (_gst_deinit_notifies, cb); + g_rec_mutex_unlock (&init_lock); +} diff --git a/subprojects/gstreamer/gst/gst.h b/subprojects/gstreamer/gst/gst.h index 25010b3631..d7c577ab35 100644 --- a/subprojects/gstreamer/gst/gst.h +++ b/subprojects/gstreamer/gst/gst.h @@ -144,6 +144,18 @@ gboolean gst_update_registry (void); GST_API const gchar * gst_get_main_executable_path (void); +/** + * GstDeinitNotifyFunc: + * @user_data: User data registered along with this function via gst_deinit_register_notify() + * + * Since: 1.26 + */ +typedef void (*GstDeinitNotifyFunc) (gpointer user_data); + +GST_API +void gst_deinit_register_notify (GstDeinitNotifyFunc func, + gpointer user_data); + G_END_DECLS #endif /* __GST_H__ */ diff --git a/subprojects/gstreamer/tests/check/gst/gstdeinit2.c b/subprojects/gstreamer/tests/check/gst/gstdeinit2.c new file mode 100644 index 0000000000..a530f87e8e --- /dev/null +++ b/subprojects/gstreamer/tests/check/gst/gstdeinit2.c @@ -0,0 +1,49 @@ +/* GStreamer + * Copyright (C) 2024 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +static void +deinit_cb (guint * cb_count) +{ + *cb_count += 1; +} + +int +main (int argc, char **argv) +{ + guint cb_count = 0; + + /* Installing callback before gst_init() is allowed */ + gst_deinit_register_notify ((GstDeinitNotifyFunc) deinit_cb, &cb_count); + + gst_init (NULL, NULL); + + /* Install callback again */ + gst_deinit_register_notify ((GstDeinitNotifyFunc) deinit_cb, &cb_count); + + gst_deinit (); + + g_assert (cb_count == 2); + + return 0; +} diff --git a/subprojects/gstreamer/tests/check/meson.build b/subprojects/gstreamer/tests/check/meson.build index 65402791aa..d7dac6b40d 100644 --- a/subprojects/gstreamer/tests/check/meson.build +++ b/subprojects/gstreamer/tests/check/meson.build @@ -16,6 +16,7 @@ core_tests = [ [ 'gst/gstcapsfeatures.c' ], [ 'gst/gstdatetime.c' ], [ 'gst/gstdeinit.c' ], + [ 'gst/gstdeinit2.c' ], [ 'gst/gstdevice.c' ], [ 'gst/gstelement.c', not gst_registry or not gst_parse], [ 'gst/gstelementfactory.c', not gst_registry ],