Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1-only */
2 : /**
3 : * NNStreamer watchdog
4 : * Copyright (C) 2024 Gichan Jang <gichan2.jang@samsung.com>
5 : */
6 : /**
7 : * @file nnstreamer_watchdog.c
8 : * @date 30 Oct 2024
9 : * @brief NNStreamer watchdog to manage the schedule in the element.
10 : * @see https://github.com/nnstreamer/nnstreamer
11 : * @author Gichan Jang <gichan2.jang@samsung.com>
12 : * @bug No known bugs except for NYI items
13 : */
14 :
15 : #include <nnstreamer_log.h>
16 : #include "nnstreamer_watchdog.h"
17 :
18 : /**
19 : * @brief Structure for NNStreamer watchdog.
20 : */
21 : typedef struct _NnstWatchdog
22 : {
23 : GMainContext *context;
24 : GMainLoop *loop;
25 : GThread *thread;
26 : GSource *source;
27 : GMutex lock;
28 : GCond cond;
29 : } NnstWatchdog;
30 :
31 : /**
32 : * @brief Called when loop is running
33 : */
34 : static gboolean
35 5 : _loop_running_cb (NnstWatchdog * watchdog)
36 : {
37 5 : g_mutex_lock (&watchdog->lock);
38 5 : g_cond_signal (&watchdog->cond);
39 5 : g_mutex_unlock (&watchdog->lock);
40 :
41 5 : return G_SOURCE_REMOVE;
42 : }
43 :
44 : /**
45 : * @brief Watchdog thread.
46 : */
47 : static gpointer
48 5 : _nnstreamer_watchdog_thread (gpointer ptr)
49 : {
50 5 : NnstWatchdog *watchdog = (NnstWatchdog *) ptr;
51 : GSource *idle_source;
52 :
53 5 : g_main_context_push_thread_default (watchdog->context);
54 :
55 5 : idle_source = g_idle_source_new ();
56 5 : g_source_set_callback (idle_source,
57 : (GSourceFunc) _loop_running_cb, watchdog, NULL);
58 5 : g_source_attach (idle_source, watchdog->context);
59 5 : g_source_unref (idle_source);
60 :
61 5 : g_main_loop_run (watchdog->loop);
62 :
63 5 : g_main_context_pop_thread_default (watchdog->context);
64 :
65 5 : return NULL;
66 : }
67 :
68 : /**
69 : * @brief Create nnstreamer watchdog. Recommended using watchdog handle with proper lock (e.g., GST_OBJECT_LOCK())
70 : */
71 : gboolean
72 6 : nnstreamer_watchdog_create (nns_watchdog_h * watchdog_h)
73 : {
74 : gint64 end_time;
75 6 : gboolean ret = TRUE;
76 6 : GError *error = NULL;
77 : NnstWatchdog *watchdog;
78 :
79 6 : if (!watchdog_h) {
80 1 : ml_loge ("Invalid parameter: watchdog handle is NULL.");
81 6 : return FALSE;
82 : }
83 :
84 5 : watchdog = g_try_new0 (NnstWatchdog, 1);
85 5 : if (!watchdog) {
86 0 : ml_loge ("Failed to allocate memory for watchdog.");
87 0 : return FALSE;
88 : }
89 :
90 5 : watchdog->context = g_main_context_new ();
91 5 : watchdog->loop = g_main_loop_new (watchdog->context, FALSE);
92 :
93 5 : g_mutex_init (&watchdog->lock);
94 5 : g_cond_init (&watchdog->cond);
95 5 : g_mutex_lock (&watchdog->lock);
96 5 : watchdog->thread =
97 5 : g_thread_try_new ("suspend_watchdog", _nnstreamer_watchdog_thread,
98 : watchdog, &error);
99 :
100 5 : if (!watchdog->thread) {
101 0 : ml_loge ("Failed to create watchdog thread: %s", error->message);
102 0 : g_clear_error (&error);
103 0 : ret = FALSE;
104 0 : goto done;
105 : }
106 :
107 5 : end_time = g_get_monotonic_time () + 5 * G_TIME_SPAN_SECOND;
108 10 : while (!g_main_loop_is_running (watchdog->loop)) {
109 5 : if (!g_cond_wait_until (&watchdog->cond, &watchdog->lock, end_time)) {
110 0 : ml_loge ("Failed to wait main loop running.");
111 0 : ret = FALSE;
112 0 : goto done;
113 : }
114 : }
115 :
116 5 : done:
117 5 : g_mutex_unlock (&watchdog->lock);
118 5 : g_mutex_clear (&watchdog->lock);
119 5 : g_cond_clear (&watchdog->cond);
120 5 : if (!ret) {
121 0 : nnstreamer_watchdog_destroy (watchdog);
122 0 : watchdog = NULL;
123 : }
124 5 : *watchdog_h = watchdog;
125 :
126 5 : return ret;
127 : }
128 :
129 : /**
130 : * @brief Destroy watchdog source. Recommended using watchdog handle with proper lock (e.g., GST_OBJECT_LOCK())
131 : */
132 : void
133 6 : nnstreamer_watchdog_destroy (nns_watchdog_h watchdog_h)
134 : {
135 6 : NnstWatchdog *watchdog = (NnstWatchdog *) watchdog_h;
136 6 : nnstreamer_watchdog_release (watchdog);
137 :
138 6 : if (watchdog && watchdog->context) {
139 5 : g_main_loop_quit (watchdog->loop);
140 5 : g_thread_join (watchdog->thread);
141 5 : watchdog->thread = NULL;
142 :
143 5 : g_main_loop_unref (watchdog->loop);
144 5 : watchdog->loop = NULL;
145 :
146 5 : g_main_context_unref (watchdog->context);
147 5 : watchdog->context = NULL;
148 :
149 5 : g_free (watchdog_h);
150 : }
151 6 : }
152 :
153 : /**
154 : * @brief Release watchdog source. Recommended using watchdog handle with proper lock (e.g., GST_OBJECT_LOCK())
155 : */
156 : void
157 8 : nnstreamer_watchdog_release (nns_watchdog_h watchdog_h)
158 : {
159 8 : NnstWatchdog *watchdog = (NnstWatchdog *) watchdog_h;
160 8 : if (watchdog && watchdog->source) {
161 4 : g_source_destroy (watchdog->source);
162 4 : g_source_unref (watchdog->source);
163 4 : watchdog->source = NULL;
164 : }
165 8 : }
166 :
167 : /**
168 : * @brief Set watchdog timeout. Recommended using watchdog handle with proper lock (e.g., GST_OBJECT_LOCK())
169 : */
170 : gboolean
171 6 : nnstreamer_watchdog_feed (nns_watchdog_h watchdog_h, GSourceFunc func,
172 : guint interval, void *user_data)
173 : {
174 6 : NnstWatchdog *watchdog = (NnstWatchdog *) watchdog_h;
175 :
176 6 : if (!watchdog || !func) {
177 2 : ml_loge ("Invalid parameter: watchdog handle or func is NULL.");
178 2 : return FALSE;
179 : }
180 :
181 4 : if (watchdog->context) {
182 4 : watchdog->source = g_timeout_source_new (interval);
183 4 : g_source_set_callback (watchdog->source, func, user_data, NULL);
184 4 : g_source_attach (watchdog->source, watchdog->context);
185 : } else {
186 0 : ml_loge
187 : ("Failed to feed to watchdog. Watchdog is not created or context is invalid.");
188 0 : return FALSE;
189 : }
190 :
191 4 : return TRUE;
192 : }
|