fixup! Iterate all type's information when checking if release callback invoking
[platform/core/multimedia/mm-resource-manager.git] / src / lib / mm_resource_manager_priv.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 "common/mm_resource_manager_utils.h"
18 #include "lib/mm_resource_manager_priv.h"
19 #include "common/mm_resource_manager_dbus.h"
20
21 static GMutex handles_lock;
22 static GPtrArray *handles;
23
24 #define MM_RESOURCE_MANAGER(x) ((mm_resource_manager_s *) (x))
25 #define MM_RESOURCE_MANAGER_CHECK(x) \
26         MM_RM_UNLOCK_RETVM_IF(!__check_rm_handle(x), handles_lock, \
27                 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, \
28                 "Invalid resource manager handle %p", x)
29 #define MM_RESOURCE_MANAGER_RESERVED_RES_ARRAY_SIZE 128
30 #define MM_RESOURCE_MANAGER_RESERVED_HANDLE_ARRAY_SIZE 64
31 #define MM_RESOURCE_MANAGER_RES_NOT_FOUND -1
32
33
34
35 typedef enum {
36         MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE,   /* uncommitted */
37         MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED,      /* committed   */
38         MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE    /* uncommitted */
39 } mm_resource_manager_res_state_e;
40
41 typedef struct {
42         void *cb;
43         void *user_data;
44         gboolean is_invoked;
45 } mm_resource_manager_cb_s;
46
47 typedef struct {
48         mm_resource_manager_id handle_id;
49         mm_resource_manager_res_type_e type;
50         mm_resource_manager_res_volume volume;
51         mm_resource_manager_res_state_e state;
52         gboolean is_acquire_failed;
53 } mm_resource_manager_res_s;
54 typedef mm_resource_manager_res_s *mm_resource_manager_res_p;
55
56 typedef struct {
57         mm_resource_manager_id id;
58
59         GPtrArray *resources;
60
61         mm_resource_manager_cb_s release_cb;
62         mm_resource_manager_cb_s status_cb;
63         int pid;
64
65         GMutex resources_lock;
66
67         gboolean is_release_marked[MM_RESOURCE_MANAGER_RES_TYPE_MAX];
68
69         mm_resource_manager_res_volume __max_resource_volumes
70                 [MM_RESOURCE_MANAGER_RES_TYPE_MAX];
71         mm_resource_manager_res_volume __condition_volumes
72                 [MM_RESOURCE_MANAGER_RES_TYPE_MAX]
73                 [MM_RESOURCE_MANAGER_RES_TYPE_COND_MAX];
74         int __max_instance[MM_RESOURCE_MANAGER_RES_TYPE_MAX];
75
76         MMResourceManager *dbus_proxy;
77
78         GMainContext *dispatcher_context;
79         GMainLoop *dispatcher_loop;
80         GThread *dispatcher_thread;
81 } mm_resource_manager_s;
82
83 static const char *res_state_str[] = {
84         "FOR ACQUIRE",
85         "ACQUIRED",
86         "FOR RELEASE",
87 };
88
89 static void __init_lib() __attribute__((constructor));
90 static void __deinit_lib() __attribute__((destructor));
91 static int __check_resource(mm_resource_manager_s *rm, mm_resource_manager_res_type_e type, mm_resource_manager_res_volume volume);
92 static int __create_resource(mm_resource_manager_s *rm, mm_resource_manager_res_type_e type,
93                 mm_resource_manager_res_volume volume, mm_resource_manager_res_p *res);
94 static void __destroy_resource(void *res);
95 static int __get_resource_index(mm_resource_manager_s *rm,
96                 mm_resource_manager_res_p res);
97  /* FALSE if resource is destroyed */
98 static gboolean __mark_resource_for_release(GPtrArray *resources, int index, mm_resource_manager_res_p resource);
99 static int __send_release_cb_sync(mm_resource_manager_id id);
100 static void __mm_resource_manager_release_callback(mm_resource_manager_s *handle,
101                 mm_resource_manager_id id, mm_resource_manager_res_type_e type, mm_resource_manager_res_volume volume);
102 static void __mm_resource_manager_status_callback(mm_resource_manager_s *handle, mm_resource_manager_status_e status);
103 static void __mm_resource_handles_lock(void);
104 static void __mm_resource_handles_unlock(void);
105 static void __mm_resources_lock(mm_resource_manager_s *h);
106 static void __mm_resources_unlock(mm_resource_manager_s *h);
107
108
109 static int __dbus_init(mm_resource_manager_s *handle);
110 static int __dbus_deinit(mm_resource_manager_s *handle);
111 static int __dbus_init_conf(mm_resource_manager_s *handle);
112 static gboolean __check_rm_handle(mm_resource_manager_s *handle);
113 static int __dbus_create(mm_resource_manager_s *handle, mm_resource_manager_app_class_e app_class);
114 static int __dbus_destroy(mm_resource_manager_s *handle);
115 static int __dbus_commit(mm_resource_manager_s *handle);
116 static void __dbus_release_callback(MMResourceManager *object, guint64 arg_id, gint arg_resource_type, gint arg_volume);
117 static void __dbus_status_callback(MMResourceManager *object, gint arg_status);
118 static gpointer __dispatcher_thread(gpointer user_data);
119 static void __destroy_dispatcher(mm_resource_manager_s *handle);
120
121
122 int _mm_resource_manager_create(mm_resource_manager_app_class_e app_class,
123                 mm_resource_manager_release_cb cb, void *cb_data, mm_resource_manager_h *rm)
124 {
125         mm_resource_manager_s *handle = *rm = NULL;
126         int ret;
127         GError *error = NULL;
128
129         handle = (mm_resource_manager_s *) calloc(1, sizeof(mm_resource_manager_s));
130         MM_RM_RETVM_IF(NULL == handle, MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Error allocating memory for Handle");
131
132         handle->dispatcher_context = g_main_context_new();
133         if (!handle->dispatcher_context) {
134                 free(handle);
135                 MM_RM_ERROR("g_main_context_new failed");
136                 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
137         }
138         MM_RM_INFO("new main context %p", handle->dispatcher_context);
139
140         handle->dispatcher_loop = g_main_loop_new(handle->dispatcher_context, FALSE);
141         if (!handle->dispatcher_loop) {
142                 g_main_context_unref(handle->dispatcher_context);
143                 free(handle);
144                 MM_RM_ERROR("g_main_loop_new failed");
145                 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
146         }
147         MM_RM_INFO("new main loop %p", handle->dispatcher_loop);
148
149         ret = __dbus_init(handle);
150         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
151                 __destroy_dispatcher(handle);
152                 free(handle);
153                 MM_RM_ERROR("Error initializing dbus client");
154                 return ret;
155         }
156
157         handle->dispatcher_thread = g_thread_try_new("mmrm:dispatcher", __dispatcher_thread, handle->dispatcher_loop, &error);
158         if (!handle->dispatcher_thread) {
159                 if (error) {
160                         MM_RM_ERROR("dispatcher_thread creation failed : %s", error->message);
161                         g_error_free(error);
162                 }
163                 __destroy_dispatcher(handle);
164                 free(handle);
165                 return MM_RESOURCE_MANAGER_ERROR_NOT_ENOUGH;
166         }
167         MM_RM_INFO("new dispatcher thread %p", handle->dispatcher_thread);
168
169         ret = __dbus_init_conf(handle);
170         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
171                 __destroy_dispatcher(handle);
172                 free(handle);
173                 MM_RM_ERROR("Configuration cannot be requested");
174                 return ret;
175         }
176
177         ret = __dbus_create(handle, app_class);
178         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
179                 __destroy_dispatcher(handle);
180                 free(handle);
181                 MM_RM_ERROR("Dbus create request failed");
182                 return ret;
183         }
184
185         handle->release_cb.cb = cb;
186         handle->release_cb.user_data = cb_data;
187
188         handle->resources = g_ptr_array_new_full(MM_RESOURCE_MANAGER_RESERVED_RES_ARRAY_SIZE, __destroy_resource);
189
190         g_mutex_init(&handle->resources_lock);
191
192         *rm = (mm_resource_manager_h *) handle;
193
194         MM_RM_INFO("adding handle %p", handle);
195
196         __mm_resource_handles_lock();
197         g_ptr_array_add(handles, handle);
198
199         MM_RM_INFO("RM #%"PRIu64" is created (%p)", _mm_rm_hash64(handle->id), handle);
200         __mm_resource_handles_unlock();
201
202         return MM_RESOURCE_MANAGER_ERROR_NONE;
203 }
204
205 int _mm_resource_manager_destroy(mm_resource_manager_h rm)
206 {
207         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
208         mm_resource_manager_id id;
209         int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
210
211         MM_RM_INFO("Enter %p", rm);
212
213         __mm_resource_handles_lock();
214         MM_RESOURCE_MANAGER_CHECK(handle);
215         g_ptr_array_remove_fast(handles, handle);
216         __mm_resources_lock(handle);
217         __mm_resource_handles_unlock();
218
219         id = handle->id;
220
221         MM_RM_INFO("RM #%"PRIu64" will be destroyed", _mm_rm_hash64(id));
222
223         ret = __dbus_destroy(handle);
224         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
225                 MM_RM_ERROR("Dbus destroy request failed 0x%x", ret);
226
227         __destroy_dispatcher(handle);
228
229         g_ptr_array_free(handle->resources, TRUE);
230         __mm_resources_unlock(handle);
231
232         g_mutex_clear(&handle->resources_lock);
233         free(handle);
234
235         if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
236                 MM_RM_INFO("RM #%"PRIu64" is destroyed", _mm_rm_hash64(id));
237
238         return ret;
239 }
240
241 int _mm_resource_manager_mark_for_acquire(mm_resource_manager_h rm, mm_resource_manager_res_type_e type,
242                 mm_resource_manager_res_volume volume, mm_resource_manager_res_h *resource_h)
243 {
244         int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
245         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
246         mm_resource_manager_res_p resource;
247
248         MM_RM_INFO("Enter %p", rm);
249
250         __mm_resource_handles_lock();
251         MM_RESOURCE_MANAGER_CHECK(handle);
252         if (handle->release_cb.is_invoked) {
253                 MM_RM_ERROR("RM #%"PRIu64" is releasing resource, so resource manager can't support your acquire request",
254                         _mm_rm_hash64(handle->id));
255                 __mm_resource_handles_unlock();
256                 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
257         }
258         __mm_resources_lock(handle);
259         __mm_resource_handles_unlock();
260
261         ret = __create_resource(handle, type, volume, &resource);
262         MM_RM_UNLOCK_RETVM_IF(ret != MM_RESOURCE_MANAGER_ERROR_NONE, handle->resources_lock, ret, "Resource cannot be created");
263         g_ptr_array_add(handle->resources, resource);
264
265         *resource_h = resource;
266
267         MM_RM_DEBUG("Resource %p of type %d with volume %d is marked for acquire in RM #%"PRIu64,
268                 *resource_h, type, volume, _mm_rm_hash64(handle->id));
269         __mm_resources_unlock(handle);
270
271         return ret;
272 }
273
274 int _mm_resource_manager_resize_marked(mm_resource_manager_h rm,
275                 mm_resource_manager_res_h resource_h, mm_resource_manager_res_volume new_volume)
276 {
277         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
278         mm_resource_manager_res_p resource = (mm_resource_manager_res_p) resource_h;
279         mm_resource_manager_res_p tmp_resource;
280         mm_resource_manager_res_volume add_volume;
281         int idx;
282         int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
283
284         MM_RM_INFO("Enter %p", rm);
285
286         __mm_resource_handles_lock();
287         MM_RESOURCE_MANAGER_CHECK(handle);
288         __mm_resources_lock(handle);
289         __mm_resource_handles_unlock();
290
291         idx = __get_resource_index(handle, resource);
292         MM_RM_UNLOCK_RETVM_IF(idx == MM_RESOURCE_MANAGER_RES_NOT_FOUND, handle->resources_lock,
293                 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "Invalid resource handle");
294         if (new_volume == resource->volume) {
295                 __mm_resources_unlock(handle);
296                 MM_RM_DEBUG("New volume equals the old. Resize is not needed.");
297                 return ret;
298         }
299
300         add_volume = resource->volume != MM_RESOURCE_MANAGER_RES_VOLUME_FULL && new_volume != MM_RESOURCE_MANAGER_RES_VOLUME_FULL &&
301                         resource->volume < new_volume ? (new_volume - resource->volume) : 0;
302
303         switch (resource->state) {
304         case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
305                 if (add_volume > 0) {
306                         ret = __check_resource(handle, resource->type, add_volume);
307                         MM_RM_UNLOCK_RETVM_IF(ret != MM_RESOURCE_MANAGER_ERROR_NONE, handle->resources_lock, ret, "Resource check failed");
308                 }
309                 resource->volume = new_volume;
310                 break;
311
312         case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
313         case MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED:
314                 ret = __create_resource(handle, resource->type, add_volume, &tmp_resource);
315                 MM_RM_UNLOCK_RETVM_IF(ret != MM_RESOURCE_MANAGER_ERROR_NONE, handle->resources_lock, ret, "Resource cannot be created");
316
317                 tmp_resource->volume = resource->volume;
318                 tmp_resource->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE;
319
320                 g_ptr_array_add(handle->resources, resource);
321                 resource->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE;
322                 resource->volume = new_volume;
323
324                 handle->resources->pdata[idx] = tmp_resource;
325                 break;
326         }
327
328         MM_RM_INFO("Resource %p is resized for acquire in RM #%"PRIu64, resource_h, _mm_rm_hash64(handle->id));
329         __mm_resources_unlock(handle);
330
331         return ret;
332 }
333
334 int _mm_resource_manager_mark_for_release(mm_resource_manager_h rm, mm_resource_manager_res_h resource_h)
335 {
336         mm_resource_manager_s *handle;
337         mm_resource_manager_res_p resource;
338         mm_resource_manager_id handle_id;
339         int idx = 0;
340         const char *res_name = NULL;
341
342         MM_RM_INFO("Enter %p", rm);
343
344         __mm_resource_handles_lock();
345
346         handle = MM_RESOURCE_MANAGER(rm);
347         MM_RESOURCE_MANAGER_CHECK(handle);
348         handle_id = handle->id;
349         MM_RM_HASH64(handle_id);
350
351         resource = (mm_resource_manager_res_p)resource_h;
352
353         MM_RM_RETVM_IF(resource->type < MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER ||
354                 resource->type >= MM_RESOURCE_MANAGER_RES_TYPE_MAX,
355                 MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Type [%d] is out of range", resource->type);
356         MM_RM_RETVM_IF(resource->state < MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE ||
357                 resource->state >= MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE,
358                 MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "State [%d] is out of range or already released", resource->state);
359
360         res_name = _mm_resource_manager_get_res_str(resource->type);
361
362         MM_RM_DEBUG("[invoked : %d state : %s] Resource %p is marked for release in resource #%"PRIu64,
363                 handle->release_cb.is_invoked, res_state_str[resource->state], resource_h, handle_id);
364
365         if (handle_id != _mm_rm_hash64(resource->handle_id))
366                 MM_RM_INFO("handle RM #%"PRIu64" is not resource RM #%"PRIu64, handle_id, _mm_rm_hash64(resource->handle_id));
367
368         /* FIXME : We should consider resource lock's vulnerability because of using global variable of 'handles_lock' */
369         if (handle->release_cb.is_invoked) {
370                 MM_RM_DEBUG("Skip resource %p (%s) of RM #%"PRIu64" because release cb will be executed soon", resource, res_name, handle_id);
371                 __mm_resource_handles_unlock();
372                 resource->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE;
373                 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
374         }
375
376         handle->is_release_marked[resource->type] = TRUE;
377         MM_RM_INFO("(%s) is marked for release in RM #%"PRIu64, res_name, handle_id);
378
379         __mm_resources_lock(handle);
380         __mm_resource_handles_unlock();
381
382         idx = __get_resource_index(handle, resource);
383         MM_RM_UNLOCK_RETVM_IF(idx == MM_RESOURCE_MANAGER_RES_NOT_FOUND,
384                         handle->resources_lock, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "Invalid resource handle");
385
386         MM_RM_UNLOCK_RETVM_IF(!__mark_resource_for_release(handle->resources, idx, resource),
387                         handle->resources_lock, MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Not in a release state");
388
389         __mm_resources_unlock(handle);
390
391         MM_RM_INFO("RM #%"PRIu64" is completed to mark", handle_id);
392
393         return MM_RESOURCE_MANAGER_ERROR_NONE;
394 }
395
396 int _mm_resource_manager_release_other_resources(mm_resource_manager_s *handle)
397 {
398         int idx;
399         int ret;
400         int len;
401
402         MM_RM_INFO("Enter %p", handle);
403
404         MM_RM_RETVM_IF(NULL == handle, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "NULL handle pointer");
405         handle->release_cb.is_invoked = TRUE;
406         MM_RM_INFO("other resource is released RM #%"PRIu64, _mm_rm_hash64(handle->id));
407
408         len = handle->resources->len;
409
410         for (idx = 0; idx < len; idx++) {
411                 if (!__mark_resource_for_release(handle->resources, idx, (mm_resource_manager_res_p) handle->resources->pdata[idx])) {
412                         MM_RM_WARNING("[idx %d] resource length %d", idx, len);
413
414                         return MM_RESOURCE_MANAGER_ERROR_NONE;
415                 }
416         }
417
418         MM_RM_INFO("[RELEASE] dbus_commit");
419         ret = __dbus_commit(handle);
420         if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
421                 MM_RM_DEBUG("Changes in RM #%"PRIu64" have been committed successfully", _mm_rm_hash64(handle->id));
422         else
423                 MM_RM_ERROR("Dbus commit request failed");
424
425         MM_RM_INFO("All resources are marked for release in RM #%"PRIu64, _mm_rm_hash64(handle->id));
426
427         return ret;
428 }
429
430 int _mm_resource_manager_mark_all_for_release(mm_resource_manager_h rm)
431 {
432         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
433         int idx;
434         int len;
435
436         MM_RM_INFO("Enter %p", rm);
437
438         __mm_resource_handles_lock();
439         MM_RESOURCE_MANAGER_CHECK(handle);
440         if (handle->release_cb.is_invoked) {
441                 MM_RM_ERROR("RM #%"PRIu64" is releasing resource, so resource manager can't support your mark all for release",
442                         _mm_rm_hash64(handle->id));
443                 __mm_resource_handles_unlock();
444                 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
445         }
446         __mm_resources_lock(handle);
447         __mm_resource_handles_unlock();
448
449         len = handle->resources->len;
450
451         for (idx = 0; idx < len; idx++) {
452                 if (!__mark_resource_for_release(handle->resources, idx, (mm_resource_manager_res_p) handle->resources->pdata[idx])) {
453                         MM_RM_WARNING("[idx %d] resource is already marked or released", idx);
454                         __mm_resources_unlock(handle);
455                         return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
456                 }
457                 handle->is_release_marked[idx] = TRUE;
458         }
459
460         MM_RM_INFO("All resources are marked for release in RM #%"PRIu64, _mm_rm_hash64(handle->id));
461         __mm_resources_unlock(handle);
462
463         return MM_RESOURCE_MANAGER_ERROR_NONE;
464 }
465
466 int _mm_resource_manager_get_resource_info(mm_resource_manager_h rm,
467                 mm_resource_manager_res_h resource_h, mm_resource_manager_res_info_s *info)
468 {
469         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
470         mm_resource_manager_res_p resource = (mm_resource_manager_res_p) resource_h;
471         int idx;
472
473         MM_RM_INFO("Enter %p", rm);
474
475         __mm_resource_handles_lock();
476         MM_RESOURCE_MANAGER_CHECK(handle);
477         __mm_resources_lock(handle);
478         __mm_resource_handles_unlock();
479
480         idx = __get_resource_index(handle, resource);
481         MM_RM_UNLOCK_RETVM_IF(idx == MM_RESOURCE_MANAGER_RES_NOT_FOUND, handle->resources_lock,
482                 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "Invalid RM #%"PRIu64"", _mm_rm_hash64(handle->id));
483
484         info->type = resource->type;
485         info->volume = resource->volume;
486         info->is_acquire_failed = resource->is_acquire_failed;
487
488         MM_RM_INFO("Info structure of resource %p in RM #%"PRIu64" is filled", resource_h, _mm_rm_hash64(handle->id));
489         __mm_resources_unlock(handle);
490
491         return MM_RESOURCE_MANAGER_ERROR_NONE;
492 }
493
494 int _mm_resource_manager_commit(mm_resource_manager_h rm)
495 {
496         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
497         int ret;
498
499         MM_RM_INFO("Enter %p", rm);
500
501         __mm_resource_handles_lock();
502         MM_RESOURCE_MANAGER_CHECK(handle);
503         if (handle->release_cb.is_invoked) {
504                 MM_RM_ERROR("RM #%"PRIu64" is releasing resource, so resource manager can't support your commit request",
505                         _mm_rm_hash64(handle->id));
506                 __mm_resource_handles_unlock();
507                 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
508         }
509         __mm_resources_lock(handle);
510         __mm_resource_handles_unlock();
511
512         handle->pid = (int)getpid();
513
514         MM_RM_INFO("[pid %d] dbus_commit RM #%"PRIu64, handle->pid, _mm_rm_hash64(handle->id));
515         ret = __dbus_commit(handle);
516         if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
517                 MM_RM_DEBUG("Changes in RM #%"PRIu64" have been committed successfully", _mm_rm_hash64(handle->id));
518         else
519                 MM_RM_ERROR("Dbus commit request failed");
520         __mm_resources_unlock(handle);
521
522         return ret;
523 }
524
525 int _mm_resource_manager_set_status_cb(mm_resource_manager_h rm, mm_resource_manager_status_cb cb, void *user_data)
526 {
527         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
528
529         MM_RM_INFO("Enter %p", rm);
530
531         __mm_resource_handles_lock();
532         MM_RESOURCE_MANAGER_CHECK(handle);
533         __mm_resources_lock(handle);
534         __mm_resource_handles_unlock();
535
536         handle->status_cb.cb = cb;
537         handle->status_cb.user_data = user_data;
538         __mm_resources_unlock(handle);
539
540         MM_RM_INFO("Status callback %p in RM #%"PRIu64" is set", cb, _mm_rm_hash64(handle->id));
541
542         return MM_RESOURCE_MANAGER_ERROR_NONE;
543 }
544
545 int _mm_resource_manager_get_res_type_max_volume(mm_resource_manager_h rm,
546                 mm_resource_manager_res_type_e type, mm_resource_manager_res_volume *max_volume)
547 {
548         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
549
550         if (handle->__max_resource_volumes[type] == MM_RESOURCE_MANAGER_NO_RES) {
551                 MM_RM_DEBUG("No resource for the platform");
552                 return MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED;
553         } else {
554                 *max_volume = handle->__max_resource_volumes[type];
555                 return MM_RESOURCE_MANAGER_ERROR_NONE;
556         }
557 }
558
559 int _mm_resource_manager_get_res_type_volume(mm_resource_manager_h rm, mm_resource_manager_res_type_e type,
560         mm_resource_manager_res_type_cond_e condition, mm_resource_manager_res_volume *volume)
561 {
562         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
563
564         if (handle->__condition_volumes[type][condition] == MM_RESOURCE_MANAGER_NO_RES) {
565                 MM_RM_DEBUG("No pair (resource, condition) for the platform");
566                 return MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED;
567         } else {
568                 *volume = handle->__condition_volumes[type][condition];
569                 return MM_RESOURCE_MANAGER_ERROR_NONE;
570         }
571 }
572
573 int _mm_resource_manager_get_type_max_instance(mm_resource_manager_h rm,
574                 mm_resource_manager_res_type_e type, int *max_instance)
575 {
576         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
577
578         if (handle->__max_instance[type] == MM_RESOURCE_MANAGER_NO_RES) {
579                 MM_RM_DEBUG("No resource for the platform");
580                 return MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED;
581         }
582
583         *max_instance = handle->__max_instance[type];
584         return MM_RESOURCE_MANAGER_ERROR_NONE;
585 }
586
587 static void __mm_resource_manager_release_callback(mm_resource_manager_s *handle, mm_resource_manager_id id,
588                 mm_resource_manager_res_type_e type, mm_resource_manager_res_volume volume)
589 {
590         mm_resource_manager_res_s *resource;
591         mm_resource_manager_id handle_id;
592         mm_resource_manager_res_type_e t;
593         gboolean release_all = FALSE;
594         int idx;
595         int prev_len;
596         const char *res_name = NULL;
597
598         handle_id = handle->id;
599         MM_RM_HASH64(handle_id);
600
601         res_name = _mm_resource_manager_get_res_str(type);
602
603         MM_RM_DEBUG("Release callback is invoked for %s of volume %d in handle RM #%"PRIu64" input RM #%"PRIu64,
604                 res_name, volume, handle_id, id);
605
606         if (handle_id != id) {
607                 MM_RM_WARNING("handle RM #%"PRIu64" input RM #%"PRIu64" is different", handle_id, id);
608                 __mm_resource_handles_unlock();
609                 return;
610         }
611
612         for (t = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER; t < MM_RESOURCE_MANAGER_RES_TYPE_MAX; t++) {
613                 if (handle->is_release_marked[t] && t == type) {
614                         MM_RM_WARNING("mark_for_release() of %s is executed, which means that we can sync with rm dmn right now RM #%"PRIu64,
615                                 res_name, handle_id);
616                         if (__send_release_cb_sync(handle->id) != MM_RESOURCE_MANAGER_ERROR_NONE)
617                                 MM_RM_ERROR("__send_release_cb_sync is failed");
618                         __mm_resource_handles_unlock();
619                         return;
620                 }
621         }
622
623         __mm_resources_lock(handle);
624         __mm_resource_handles_unlock();
625         prev_len = handle->resources->len;
626
627         MM_RM_DEBUG("resource %p length %d", handle->resources, prev_len);
628
629         for (idx = 0; idx < prev_len; idx++) {
630                 resource = (mm_resource_manager_res_s *)handle->resources->pdata[idx];
631                 if (resource->type == type && resource->volume == volume) {
632                         /* FIXME : Set true in advance release callback invoking to prevent deadlock with resource marking */
633                         handle->release_cb.is_invoked = TRUE;
634
635                         MM_RM_INFO("[res %p type %s volume %d] release_cb", resource, res_name, volume);
636                         release_all = ((mm_resource_manager_release_cb)handle->release_cb.cb)(handle, resource, handle->release_cb.user_data);
637                         MM_RM_INFO("[%d] release_cb is completed", release_all);
638
639                         if (__send_release_cb_sync(handle->id) != MM_RESOURCE_MANAGER_ERROR_NONE) {
640                                 MM_RM_ERROR("__send_release_cb_sync is failed");
641                                 handle->release_cb.is_invoked = FALSE;
642                                 break;
643                         }
644
645                         /* If there is only one resource, the release callback value must be reset considering return value in case the handle is reused. */
646                         if (!release_all)
647                                 handle->release_cb.is_invoked = FALSE;
648
649                         g_ptr_array_remove_index_fast(handle->resources, idx);
650
651                         MM_RM_DEBUG("resource length %d => %d", prev_len, handle->resources->len);
652
653                         break;
654                 }
655         }
656
657         MM_RM_DEBUG("[%d] RELEASE ALL", release_all);
658
659         if (release_all) {
660                 if (_mm_resource_manager_release_other_resources(handle) == MM_RESOURCE_MANAGER_ERROR_NONE) {
661                         MM_RM_DEBUG("All resources are released after release cb");
662                         handle->release_cb.is_invoked = FALSE;
663                         MM_RM_WARNING("Reset release_cb release_cb.is_invoked RM #%"PRIu64, handle_id);
664                 } else {
665                         MM_RM_WARNING("Resources cannot be released after release cb");
666                 }
667         }
668
669         __mm_resources_unlock(handle);
670 }
671
672 static void __mm_resource_manager_status_callback(mm_resource_manager_s *handle, mm_resource_manager_status_e status)
673 {
674         __mm_resources_lock(handle);
675         __mm_resource_handles_unlock();
676         if (handle->status_cb.cb)
677                 ((mm_resource_manager_status_cb)handle->status_cb.cb)(handle, status, handle->status_cb.user_data);
678
679         __mm_resources_unlock(handle);
680 }
681
682 static void __mm_resource_handles_lock(void)
683 {
684         LOGD(">>> handles lock");
685         g_mutex_lock(&handles_lock);
686 }
687
688 static void __mm_resource_handles_unlock(void)
689 {
690         g_mutex_unlock(&handles_lock);
691         LOGD("<<< handles unlock");
692 }
693
694 static void __mm_resources_lock(mm_resource_manager_s *h)
695 {
696         MM_RM_RETM_IF(!h, "handle is NULL");
697         LOGD(">> resource lock");
698         g_mutex_lock(&h->resources_lock);
699 }
700
701 static void __mm_resources_unlock(mm_resource_manager_s *h)
702 {
703         MM_RM_RETM_IF(!h, "handle is NULL");
704         g_mutex_unlock(&h->resources_lock);
705         LOGD("<< resource unlock");
706 }
707
708 static int __check_resource(mm_resource_manager_s *rm, mm_resource_manager_res_type_e type, mm_resource_manager_res_volume volume)
709 {
710         mm_resource_manager_res_volume local_volume = rm->__max_resource_volumes[type];
711         mm_resource_manager_res_p i_res;
712         int i;
713
714         MM_RM_DEBUG("[RM #%"PRIu64" type : %d] resource (#%d) for the platform", _mm_rm_hash64(rm->id), type, local_volume);
715
716         if (volume > 0) {
717                 for (i = 0; i < rm->resources->len; i++) {
718                         i_res = (mm_resource_manager_res_p) rm->resources->pdata[i];
719                         if (i_res->type == type && i_res->state != MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE &&
720                                 (i_res->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL ||(local_volume -= i_res->volume) < volume)) {
721                                 MM_RM_ERROR("Requested volume %d exceeds remaining local volume %d", volume, i_res->volume ==
722                                         MM_RESOURCE_MANAGER_RES_VOLUME_FULL ? 0 : local_volume);
723                                 return MM_RESOURCE_MANAGER_ERROR_NOT_ENOUGH;
724                         }
725                 }
726         }
727
728         return MM_RESOURCE_MANAGER_ERROR_NONE;
729 }
730
731 static int __create_resource(mm_resource_manager_s *rm,
732                 mm_resource_manager_res_type_e type, mm_resource_manager_res_volume volume, mm_resource_manager_res_p *res)
733 {
734         int ret;
735
736         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
737
738         MM_RM_RETVM_IF(handle == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "NULL handle pointer");
739         MM_RM_RETVM_IF(res == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "NULL pointer");
740
741         ret = __check_resource(rm, type, volume);
742         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
743                 return ret;
744
745         *res = g_new0(mm_resource_manager_res_s, 1);
746         (*res)->handle_id = handle->id;
747         (*res)->type = type;
748         if (handle->__max_resource_volumes[type] == MM_RESOURCE_MANAGER_RES_VOLUME_FULL &&
749                 volume != MM_RESOURCE_MANAGER_RES_VOLUME_FULL)
750                 (*res)->volume = MM_RESOURCE_MANAGER_RES_VOLUME_FULL;
751         else
752                 (*res)->volume = volume;
753
754         return MM_RESOURCE_MANAGER_ERROR_NONE;
755 }
756
757 static void __destroy_resource(void *res)
758 {
759         g_free(res);
760 }
761
762 static int __get_resource_index(mm_resource_manager_s *rm, mm_resource_manager_res_p res)
763 {
764         int i;
765
766         MM_RM_RETVM_IF(rm == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "NULL handle pointer");
767
768         for (i = 0; i < rm->resources->len; i++) {
769                 if (rm->resources->pdata[i] == (gpointer) res)
770                         return i;
771         }
772
773         MM_RM_WARNING("[%d] Resource %p is marked for release in RM #%"PRIu64,
774                 rm->resources->len, res, _mm_rm_hash64(rm->id));
775
776         return MM_RESOURCE_MANAGER_RES_NOT_FOUND;
777 }
778
779 static gboolean __mark_resource_for_release(GPtrArray *resources, int index, mm_resource_manager_res_p resource)
780 {
781         switch (resource->state) {
782         case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
783                 g_ptr_array_remove_index_fast(resources, index);
784                 MM_RM_DEBUG("Resource %p is removed implicitly", resource);
785                 return FALSE;
786         case MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED:
787                 resource->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE;
788                 MM_RM_DEBUG("Resource %p is successfully marked", resource);
789                 break;
790         case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
791                 MM_RM_DEBUG("Resource %p is already marked or released", resource);
792                 return FALSE;
793         }
794
795         return TRUE;
796 }
797
798 static gboolean __check_rm_handle(mm_resource_manager_s *handle)
799 {
800         int i;
801
802         for (i = 0; i < handles->len; i++) {
803                 if (g_ptr_array_index(handles, i) == handle)
804                         return TRUE;
805         }
806         return FALSE;
807 }
808
809 static int __send_release_cb_sync(mm_resource_manager_id id)
810 {
811         int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
812         int sync_fd;
813
814         MM_RM_DEBUG("Enter");
815         sync_fd = open(RELEASE_CB_SYNC_PATH, O_WRONLY | O_NONBLOCK);
816         MM_RM_DEBUG("[%d] opened %s", sync_fd, RELEASE_CB_SYNC_PATH);
817
818         MM_RM_RETVM_IF(sync_fd == -1, MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
819                 "Sync FIFO cannot be opened [errno %d]", errno);
820
821         if (write(sync_fd, &id, sizeof(id)) == sizeof(id)) {
822                 MM_RM_INFO("[SYNC] message is sent successfully RM #%"PRIu64, _mm_rm_hash64(id));
823         } else {
824                 MM_RM_ERROR("[SYNC] message cannot be sent RM #%"PRIu64, _mm_rm_hash64(id));
825                 ret = MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
826         }
827
828         MM_RM_RETVM_IF(close(sync_fd) == -1, MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
829                 "[%d] close failed [errno %d]", sync_fd, errno);
830         MM_RM_DEBUG("[%d] closed", sync_fd);
831
832         return ret;
833 }
834
835 static void __init_lib()
836 {
837         handles = g_ptr_array_sized_new(MM_RESOURCE_MANAGER_RESERVED_HANDLE_ARRAY_SIZE);
838         MM_RM_RETM_IF(handles == NULL, "API lib cannot be initialized");
839
840         MM_RM_INFO("API lib is loaded");
841 }
842
843 static void __deinit_lib()
844 {
845         if (handles->len > 0) {
846                 MM_RM_DEBUG("Handles array [%d] is not empty. It will be cleaned now.", handles->len);
847                 while (handles->len > 0)
848                         _mm_resource_manager_destroy(handles->pdata[0]);
849         }
850
851         g_ptr_array_free(handles, TRUE);
852
853         MM_RM_INFO("API lib is unloaded");
854 }
855
856 static int __dbus_init(mm_resource_manager_s *handle)
857 {
858         GError *error = NULL;
859
860         MM_RM_RETVM_IF(handle->dbus_proxy != NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Dbus proxy is not NULL");
861
862         g_main_context_push_thread_default(handle->dispatcher_context);
863         handle->dbus_proxy = mmresource_manager_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, 0, RMD_GDBUS_NAME, RMD_GDBUS_PATH, NULL, &error);
864         g_main_context_pop_thread_default(handle->dispatcher_context);
865         MM_RM_RET_IF_GERR(error, "Dbus proxy cannot be created");
866
867         if (g_signal_connect(handle->dbus_proxy, "release_callback", (GCallback)__dbus_release_callback, NULL) < 1 ||
868                 g_signal_connect(handle->dbus_proxy, "status_callback", (GCallback)__dbus_status_callback, NULL) < 1) {
869
870                 g_object_unref(handle->dbus_proxy);
871                 handle->dbus_proxy = NULL;
872                 MM_RM_ERROR("Release or status callback signals cannot be connected");
873
874                 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
875         }
876
877         return MM_RESOURCE_MANAGER_ERROR_NONE;
878 }
879
880 static int __dbus_deinit(mm_resource_manager_s *handle)
881 {
882         MM_RM_RETVM_IF(handle->dbus_proxy == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Dbus proxy is NULL");
883         g_object_unref(handle->dbus_proxy);
884         handle->dbus_proxy = NULL;
885         return MM_RESOURCE_MANAGER_ERROR_NONE;
886 }
887
888 static int __dbus_init_conf(mm_resource_manager_s *handle)
889 {
890         int i, j;
891         GError *error = NULL;
892         int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
893         GVariant *max_volume = NULL;
894         GVariant *cond_volume = NULL;
895         GVariant *max_instance = NULL;
896         GVariant *tmp;
897         GVariantIter volume_iter;
898         GVariantIter cond_volume_iter;
899
900         mmresource_manager_call_conf_sync(handle->dbus_proxy, &rm_error, &max_volume, &cond_volume, &max_instance, NULL, &error);
901         MM_RM_RET_IF_GERR(error, "DBus conf msg cannot be sent");
902
903         MM_RM_RETVM_IF(max_volume == NULL || cond_volume == NULL,
904                         MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Variant data are empty");
905
906         if (g_variant_iter_init(&volume_iter, max_volume) == MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
907                 for (i = 0; g_variant_iter_next(&volume_iter, "i", &handle->__max_resource_volumes[i]); i++);
908                 g_variant_unref(max_volume);
909                 max_volume = NULL;
910         } else {
911                 MM_RM_ERROR("Wrong max volume array size");
912                 goto out;
913         }
914
915         if (g_variant_iter_init(&volume_iter, cond_volume) == MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
916                 for (i = 0; (tmp = g_variant_iter_next_value(&volume_iter)) != NULL; i++) {
917                         if (g_variant_iter_init(&cond_volume_iter, tmp) == MM_RESOURCE_MANAGER_RES_TYPE_COND_MAX) {
918                                 for (j = 0; g_variant_iter_next(&cond_volume_iter, "i", &handle->__condition_volumes[i][j]); j++);
919                                 g_variant_unref(tmp);
920                         } else {
921                                 g_variant_unref(tmp);
922                                 MM_RM_ERROR("Wrong condition volume array size");
923                                 rm_error = MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
924                                 break;
925                         }
926                 }
927                 g_variant_unref(cond_volume);
928                 cond_volume = NULL;
929         } else {
930                 MM_RM_ERROR("Wrong condition volume array size");
931                 goto out;
932         }
933
934         if (g_variant_iter_init(&volume_iter, max_instance) == MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
935                 for (i = 0; g_variant_iter_next(&volume_iter, "i", &handle->__max_instance[i]); i++);
936                 g_variant_unref(max_instance);
937                 max_instance = NULL;
938         } else {
939                 MM_RM_ERROR("Wrong max instance array size");
940                 goto out;
941         }
942
943         return rm_error;
944 out:
945         g_variant_unref(max_volume);
946         g_variant_unref(cond_volume);
947         g_variant_unref(max_instance);
948         return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
949 }
950
951 static int __dbus_create(mm_resource_manager_s *handle, mm_resource_manager_app_class_e app_class)
952 {
953         GError *error = NULL;
954         int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
955
956         mmresource_manager_call_create_sync(handle->dbus_proxy, app_class, &handle->id, &rm_error, NULL, &error);
957         MM_RM_RET_IF_GERR(error, "DBus create msg cannot be sent");
958
959         MM_RM_DEBUG("Create returned id - RM #%"PRIu64", error - %d", _mm_rm_hash64(handle->id), rm_error);
960
961         return rm_error;
962 }
963
964 static int __dbus_destroy(mm_resource_manager_s *handle)
965 {
966         GError *error = NULL;
967         int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
968
969         mmresource_manager_call_destroy_sync(handle->dbus_proxy, handle->id, &rm_error, NULL, &error);
970         MM_RM_RET_IF_GERR(error, "DBus destroy msg cannot be sent");
971
972         MM_RM_DEBUG("Destroy for id - RM #%"PRIu64" returned error - %d", _mm_rm_hash64(handle->id), rm_error);
973
974         return MM_RESOURCE_MANAGER_ERROR_NONE;
975 }
976
977 static int __dbus_commit(mm_resource_manager_s *handle)
978 {
979         GVariant *release;
980         GVariant *acquire;
981         GVariantBuilder *release_builder;
982         GVariantBuilder *acquire_builder;
983         GVariant *flags_variant;
984         GVariantIter flags_iter;
985         mm_resource_manager_res_p resource;
986         int i;
987         int release_num = 0;
988         int acquire_num = 0;
989         GError *error = NULL;
990         int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
991
992         release_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
993         acquire_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
994
995         for (i = 0; i < handle->resources->len; i++) {
996                 resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
997
998                 switch (resource->state) {
999                 case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
1000                         g_variant_builder_add_value(acquire_builder, g_variant_new("(iii)", resource->type, resource->volume, handle->pid));
1001                         acquire_num++;
1002                         break;
1003                 case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
1004                         g_variant_builder_add_value(release_builder, g_variant_new("(iii)", resource->type, resource->volume, handle->pid));
1005                         release_num++;
1006                         break;
1007                 default:
1008                         break;
1009                 }
1010         }
1011
1012         if (release_num + acquire_num == 0) {
1013                 g_variant_builder_unref(release_builder);
1014                 g_variant_builder_unref(acquire_builder);
1015                 MM_RM_DEBUG("There is nothing to commit - dbus request is not sent [%d %d]", release_num, acquire_num);
1016                 return rm_error;
1017         }
1018
1019         /* Acquire and release arrays are ended with special element, because g_variant_builder_end crashes without at least one element */
1020         g_variant_builder_add_value(acquire_builder, g_variant_new("(iii)", MM_RESOURCE_MANAGER_NO_RES, 0, handle->pid));
1021         acquire = g_variant_builder_end(acquire_builder);
1022         g_variant_builder_unref(acquire_builder);
1023
1024         g_variant_builder_add_value(release_builder, g_variant_new("(iii)", MM_RESOURCE_MANAGER_NO_RES, 0, handle->pid));
1025         release = g_variant_builder_end(release_builder);
1026         g_variant_builder_unref(release_builder);
1027
1028         mmresource_manager_call_commit_sync(handle->dbus_proxy, handle->id, release, acquire, &rm_error, &flags_variant, NULL, &error);
1029         MM_RM_RET_IF_GERR(error, "DBus commit msg cannot be sent");
1030
1031         MM_RM_DEBUG("Commit for id - RM #%"PRIu64" returned error - %d", _mm_rm_hash64(handle->id), rm_error);
1032
1033         if (rm_error == MM_RESOURCE_MANAGER_ERROR_NONE) {
1034                 for (i = 0; i < handle->resources->len; i++) {
1035                         resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
1036
1037                         switch (resource->state) {
1038                         case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
1039                                 resource->state = MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED;
1040                                 resource->is_acquire_failed = FALSE;
1041                                 break;
1042                         case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
1043                                 handle->is_release_marked[resource->type] = FALSE;
1044                                 g_ptr_array_remove_index_fast(handle->resources, i--);
1045                                 break;
1046                         default:
1047                                 break;
1048                         }
1049                 }
1050         } else if (rm_error == MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY) {
1051                 g_variant_iter_init(&flags_iter, flags_variant);
1052
1053                 for (i = 0; i < handle->resources->len; i++) {
1054                         resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
1055
1056                         if (resource->state == MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE) {
1057                                 if (!g_variant_iter_next(&flags_iter, "b", &resource->is_acquire_failed))
1058                                         MM_RM_ERROR("g_variant_iter_next failed to get the value of is_acquire_failed");
1059                         }
1060                 }
1061         }
1062
1063         g_variant_unref(flags_variant);
1064
1065         return rm_error;
1066 }
1067
1068 static void __dbus_release_callback(MMResourceManager *object, guint64 arg_id, gint arg_resource_type, gint arg_volume)
1069 {
1070         mm_resource_manager_s *handle;
1071         mm_resource_manager_id handle_id;
1072         int i;
1073
1074         __mm_resource_handles_lock();
1075
1076         for (i = 0; i < handles->len; i++) {
1077                 handle = (mm_resource_manager_s *)handles->pdata[i];
1078                 handle_id = handle->id;
1079                 MM_RM_HASH64(handle_id);
1080
1081                 if (handle->dbus_proxy == object && handle_id == arg_id) {
1082                         if (handle->release_cb.is_invoked) {
1083                                 MM_RM_WARNING("other resource release cb is already executed RM #%"PRIu64, handle_id);
1084                                 if (__send_release_cb_sync(handle->id) != MM_RESOURCE_MANAGER_ERROR_NONE)
1085                                         MM_RM_ERROR("__send_release_cb_sync is failed");
1086                                 __mm_resource_handles_unlock();
1087                                 return;
1088                         }
1089                         MM_RM_INFO("[release_callback] RM #%"PRIu64, handle_id);
1090                         __mm_resource_manager_release_callback(handle, arg_id, arg_resource_type, arg_volume);
1091                         return;
1092                 }
1093         }
1094
1095         __mm_resource_handles_unlock();
1096 }
1097
1098 static void __dbus_status_callback(MMResourceManager *object, gint arg_status)
1099 {
1100         mm_resource_manager_s *handle;
1101         int i;
1102
1103         MM_RM_INFO("status callback status %d", arg_status);
1104         __mm_resource_handles_lock();
1105
1106         for (i = 0; i < handles->len; i++) {
1107                 handle = (mm_resource_manager_s *)handles->pdata[i];
1108                 if (handle->dbus_proxy == object) {
1109                         __mm_resource_manager_status_callback(handle, arg_status);
1110                         return;
1111                 }
1112         }
1113
1114         __mm_resource_handles_unlock();
1115 }
1116
1117 static gpointer __dispatcher_thread(gpointer user_data)
1118 {
1119         GMainLoop *ml = (GMainLoop *) user_data;
1120
1121         MM_RM_INFO("main loop %p", ml);
1122
1123         if (ml) {
1124                 g_main_loop_run(ml);
1125                 MM_RM_INFO("main loop %p quit", ml);
1126         }
1127
1128         return NULL;
1129 }
1130
1131 static void __destroy_dispatcher(mm_resource_manager_s *handle)
1132 {
1133         MM_RM_WARNING("handle %p", handle);
1134
1135         __mm_resource_handles_lock();
1136
1137         if (__dbus_deinit(handle) != MM_RESOURCE_MANAGER_ERROR_NONE)
1138                 MM_RM_ERROR("Error while dbus deinitializing");
1139
1140         MM_RM_INFO("dispatcher main loop %p", handle->dispatcher_loop);
1141         if (handle->dispatcher_loop) {
1142                 if (g_main_loop_is_running(handle->dispatcher_loop)) {
1143                         MM_RM_INFO("mainloop %p is running", handle->dispatcher_loop);
1144                         g_main_loop_quit(handle->dispatcher_loop);
1145                 }
1146
1147                 g_main_loop_unref(handle->dispatcher_loop);
1148                 handle->dispatcher_loop = NULL;
1149         }
1150
1151         MM_RM_INFO("dispatcher thread %p", handle->dispatcher_thread);
1152         if (handle->dispatcher_thread) {
1153                 g_thread_join(handle->dispatcher_thread);
1154                 MM_RM_INFO("dispatcher thread join %p", handle->dispatcher_thread);
1155                 handle->dispatcher_thread = NULL;
1156         }
1157
1158         MM_RM_INFO("dispatcher context %p", handle->dispatcher_context);
1159         if (handle->dispatcher_context) {
1160                 g_main_context_unref(handle->dispatcher_context);
1161                 handle->dispatcher_context = NULL;
1162         }
1163
1164         __mm_resource_handles_unlock();
1165 }