Resolve the memory leak issue
[platform/core/multimedia/mm-resource-manager.git] / src / daemon / backend / murphy / mm_resource_manager_mloop.c
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <murphy/common/glib-glue.h>
18 #include "lib/mm_resource_manager.h"
19 #include "daemon/mm_resource_manager_daemon_dbus.h"
20 #include "daemon/backend/murphy/mm_resource_manager_mloop.h"
21
22 static void __mm_resource_manager_mloop_state_callback(mrp_res_context_t *context,
23                 mrp_res_error_t err, void *user_data);
24 static gboolean __mm_resource_manager_mloop_list_resources(mrp_res_context_t *context);
25 static int __mm_resource_manager_mloop_wait_connection(mm_resource_manager_mloop_s *mrp);
26
27 #define RM_RESOURCE_TIMEOUT 5
28
29 static gpointer thread_func(mm_resource_manager_mloop_s *mrp)
30 {
31         MM_RM_DEBUG("Worker thread is active");
32
33         g_mutex_lock(&mrp->lock);
34
35         GMainContext *m_ctx = g_main_context_new();
36         if (!m_ctx) {
37                 MM_RM_ERROR("Failed to create main context for resource manager");
38                 g_mutex_unlock(&mrp->lock);
39                 goto EXIT;
40         }
41
42         mrp->m_loop = g_main_loop_new(m_ctx, FALSE);
43         g_main_context_unref(m_ctx);
44         if (!mrp->m_loop) {
45                 MM_RM_ERROR("Failed to create main loop for resource manager");
46                 g_mutex_unlock(&mrp->lock);
47                 goto EXIT;
48         }
49
50         mrp->mrp_loop = mrp_mainloop_glib_get(mrp->m_loop);
51         if (!mrp->mrp_loop) {
52                 MM_RM_ERROR("Failed to create mrp_loop for resource manager");
53                 g_mutex_unlock(&mrp->lock);
54                 goto EXIT;
55         }
56
57         mrp->mrp_ctx = mrp_res_create(mrp->mrp_loop,
58                 __mm_resource_manager_mloop_state_callback, mrp);
59         if (!mrp->mrp_ctx) {
60                 MM_RM_ERROR("Failed to create mrp_ctx for resource manager");
61                 mrp_mainloop_destroy(mrp->mrp_loop);
62                 g_mutex_unlock(&mrp->lock);
63                 goto EXIT;
64         }
65
66         g_mutex_unlock(&mrp->lock);
67
68         g_main_loop_run(mrp->m_loop);
69
70 EXIT:
71         return NULL;
72 }
73
74 int _mm_resource_manager_mloop_create(mm_resource_manager_mloop_s **mrp)
75 {
76         mm_resource_manager_mloop_s *handle = NULL;
77         int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
78
79         handle = (mm_resource_manager_mloop_s *) calloc(1,
80                         sizeof(mm_resource_manager_mloop_s));
81         MM_RM_RETVM_IF(NULL == handle, MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
82                         "Error allocating memory for Handle");
83
84         g_mutex_init(&handle->lock);
85         g_cond_init(&handle->cond);
86
87         handle->worker = g_thread_try_new(NULL, (GThreadFunc) thread_func, handle, NULL);
88         if (!handle->worker) {
89                 MM_RM_ERROR("Failed to create worker thread");
90                 _mm_resource_manager_mloop_destroy(handle);
91                 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
92         }
93
94         /* Wait while resource manager connects to Murphy.
95                  We assume that this condition is triggered only in case
96                  we successfully connected to Murphy. Otherwise an error
97                  is returned. And resulting handle is NULL */
98         if (MM_RESOURCE_MANAGER_ERROR_NONE !=
99                 __mm_resource_manager_mloop_wait_connection(handle)) {
100                 _mm_resource_manager_mloop_destroy(handle);
101                 return MM_RESOURCE_MANAGER_ERROR_INVALID_STATE;
102         }
103
104         *mrp = handle;
105
106         MM_RM_INFO("Successfully performed mloop create");
107
108         return ret;
109 }
110
111 int _mm_resource_manager_mloop_destroy(mm_resource_manager_mloop_s *mrp)
112 {
113         if (mrp == NULL) {
114                 MM_RM_ERROR("mrp is null");
115                 return MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER;
116         }
117
118         g_mutex_lock(&mrp->lock);
119
120         if (mrp->mrp_loop)
121                 mrp_mainloop_quit(mrp->mrp_loop, 0);
122
123         if (mrp->mrp_ctx) {
124                 mrp_res_destroy(mrp->mrp_ctx);
125                 mrp->mrp_ctx = NULL;
126         }
127
128         if (mrp->mrp_loop) {
129                 mrp_mainloop_destroy(mrp->mrp_loop);
130                 mrp->mrp_loop = NULL;
131         }
132
133         if (mrp->m_loop) {
134                 g_main_loop_quit(mrp->m_loop);
135                 g_main_loop_unref(mrp->m_loop);
136         }
137
138         if (mrp->worker) {
139                 MM_RM_DEBUG("Joining worker thread...");
140                 g_thread_join(mrp->worker);
141                 mrp->worker = NULL;
142                 MM_RM_DEBUG("Joined to worker thread");
143         }
144
145         g_mutex_unlock(&mrp->lock);
146
147         g_mutex_clear(&mrp->lock);
148         g_cond_clear(&mrp->cond);
149
150         free(mrp);
151
152         return MM_RESOURCE_MANAGER_ERROR_NONE;
153 }
154
155 int _mm_resource_manager_mloop_is_run(mm_resource_manager_mloop_s *mrp, gboolean *is_run)
156 {
157         *is_run = mrp->mrp_ctx->state == MRP_RES_CONNECTED ? TRUE : FALSE;
158
159         return MM_RESOURCE_MANAGER_ERROR_NONE;
160 }
161
162 int _mm_resource_manager_mloop_set_error_cb(mm_resource_manager_mloop_s *mrp,
163         mm_resource_manager_mloop_error_cb cb, void *user_data)
164 {
165         mrp->error_cb = cb;
166         mrp->user_data = user_data;
167
168         return MM_RESOURCE_MANAGER_ERROR_NONE;
169 }
170
171 static void __mm_resource_manager_mloop_state_callback(mrp_res_context_t *context,
172         mrp_res_error_t err, void *user_data)
173 {
174         mm_resource_manager_mloop_s *mrp = NULL;
175
176         MM_RM_DEBUG("enter");
177
178         if (!user_data) {
179                 MM_RM_ERROR("user data must be not NULL");
180                 return;
181         }
182
183         mrp = (mm_resource_manager_mloop_s *) user_data;
184
185         g_mutex_lock(&mrp->lock);
186
187         switch (err) {
188         case MRP_RES_ERROR_CONNECTION_LOST:
189         case MRP_RES_ERROR_INTERNAL:
190         case MRP_RES_ERROR_MALFORMED:
191                 MM_RM_ERROR("error message received from Murphy, err(0x%x)", err);
192                 if (mrp->error_cb)
193                         mrp->error_cb(mrp, err, mrp->user_data);
194
195                 g_mutex_unlock(&mrp->lock);
196                 break;
197         case MRP_RES_ERROR_NONE:
198         default:
199                 break;
200         }
201
202         switch (context->state) {
203         case MRP_RES_CONNECTED:
204                 MM_RM_DEBUG("Connected to Murphy");
205                 if (__mm_resource_manager_mloop_list_resources(context))
206                         g_cond_signal(&mrp->cond);
207
208                 break;
209         case MRP_RES_DISCONNECTED:
210                 MM_RM_DEBUG("Disconnected from Murphy");
211                 break;
212         default:
213                 break;
214         }
215
216         g_mutex_unlock(&mrp->lock);
217 }
218
219 static gboolean __mm_resource_manager_mloop_list_resources(mrp_res_context_t *context)
220 {
221         const mrp_res_resource_set_t *rset;
222         mrp_res_resource_t *resource = NULL;
223         int i = 0;
224
225         rset = mrp_res_list_resources(context);
226         if (rset) {
227                 mrp_res_string_array_t *resource_names = NULL;
228
229                 resource_names = mrp_res_list_resource_names(rset);
230                 if (!resource_names) {
231                         MM_RM_ERROR("no resources available");
232                         return FALSE;
233                 }
234
235                 for (i = 0; i < resource_names->num_strings; ++i) {
236                         resource = mrp_res_get_resource_by_name(rset, resource_names->strings[i]);
237                         if (resource)
238                                 MM_RM_DEBUG("available resource: %s", resource->name);
239                 }
240
241                 mrp_res_free_string_array(resource_names);
242         }
243
244         return TRUE;
245 }
246
247 static int __mm_resource_manager_mloop_wait_connection(mm_resource_manager_mloop_s *mrp)
248 {
249         MM_RM_RETVM_IF(mrp == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "mainloop_s is null");
250
251         g_mutex_lock(&mrp->lock);
252
253         if (mrp->mrp_ctx && MRP_RES_CONNECTED == mrp->mrp_ctx->state) {
254                 MM_RM_DEBUG("Already connected to resource server");
255         } else {
256                 gint64 end_time = g_get_monotonic_time() + RM_RESOURCE_TIMEOUT * G_TIME_SPAN_SECOND;
257
258                 MM_RM_DEBUG("Not connected to resource server yet. Waiting...");
259
260                 if (!g_cond_wait_until(&mrp->cond, &mrp->lock, end_time)) {
261                         MM_RM_ERROR("Could not connect to resource server");
262                         g_mutex_unlock(&mrp->lock);
263                         return MM_RESOURCE_MANAGER_ERROR_INVALID_STATE;
264                 } else {
265                         if (mrp->mrp_ctx && MRP_RES_CONNECTED == mrp->mrp_ctx->state) {
266                                 MM_RM_DEBUG("Successfully connected to resource server!");
267                         } else {
268                                 MM_RM_ERROR("Failed to connect to resource server");
269                                 g_mutex_unlock(&mrp->lock);
270                                 return MM_RESOURCE_MANAGER_ERROR_INVALID_STATE;
271                         }
272                 }
273         }
274
275         g_mutex_unlock(&mrp->lock);
276
277         return MM_RESOURCE_MANAGER_ERROR_NONE;
278 }