2 * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "common/mm_resource_manager_utils.h"
18 #include "lib/mm_resource_manager_priv.h"
19 #include "common/mm_resource_manager_dbus.h"
21 static GMutex handles_lock;
22 static GPtrArray *handles;
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
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;
45 } mm_resource_manager_cb_s;
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;
57 mm_resource_manager_id id;
61 mm_resource_manager_cb_s release_cb;
62 mm_resource_manager_cb_s status_cb;
65 GMutex resources_lock;
67 gboolean is_release_marked[MM_RESOURCE_MANAGER_RES_TYPE_MAX];
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];
76 MMResourceManager *dbus_proxy;
78 GMainContext *dispatcher_context;
79 GMainLoop *dispatcher_loop;
80 GThread *dispatcher_thread;
81 } mm_resource_manager_s;
83 static const char *res_state_str[] = {
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);
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);
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)
125 mm_resource_manager_s *handle = *rm = NULL;
127 GError *error = NULL;
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");
132 handle->dispatcher_context = g_main_context_new();
133 if (!handle->dispatcher_context) {
135 MM_RM_ERROR("g_main_context_new failed");
136 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
138 MM_RM_INFO("new main context %p", handle->dispatcher_context);
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);
144 MM_RM_ERROR("g_main_loop_new failed");
145 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
147 MM_RM_INFO("new main loop %p", handle->dispatcher_loop);
149 ret = __dbus_init(handle);
150 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
151 __destroy_dispatcher(handle);
153 MM_RM_ERROR("Error initializing dbus client");
157 handle->dispatcher_thread = g_thread_try_new("mmrm:dispatcher", __dispatcher_thread, handle->dispatcher_loop, &error);
158 if (!handle->dispatcher_thread) {
160 MM_RM_ERROR("dispatcher_thread creation failed : %s", error->message);
163 __destroy_dispatcher(handle);
165 return MM_RESOURCE_MANAGER_ERROR_NOT_ENOUGH;
167 MM_RM_INFO("new dispatcher thread %p", handle->dispatcher_thread);
169 ret = __dbus_init_conf(handle);
170 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
171 __destroy_dispatcher(handle);
173 MM_RM_ERROR("Configuration cannot be requested");
177 ret = __dbus_create(handle, app_class);
178 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
179 __destroy_dispatcher(handle);
181 MM_RM_ERROR("Dbus create request failed");
185 handle->release_cb.cb = cb;
186 handle->release_cb.user_data = cb_data;
188 handle->resources = g_ptr_array_new_full(MM_RESOURCE_MANAGER_RESERVED_RES_ARRAY_SIZE, __destroy_resource);
190 g_mutex_init(&handle->resources_lock);
192 *rm = (mm_resource_manager_h *) handle;
194 MM_RM_INFO("adding handle %p", handle);
196 __mm_resource_handles_lock();
197 g_ptr_array_add(handles, handle);
199 MM_RM_INFO("RM #%"PRIu64" is created (%p)", _mm_rm_hash64(handle->id), handle);
200 __mm_resource_handles_unlock();
202 return MM_RESOURCE_MANAGER_ERROR_NONE;
205 int _mm_resource_manager_destroy(mm_resource_manager_h rm)
207 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
208 mm_resource_manager_id id;
209 int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
211 MM_RM_INFO("Enter %p", rm);
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();
221 MM_RM_INFO("RM #%"PRIu64" will be destroyed", _mm_rm_hash64(id));
223 ret = __dbus_destroy(handle);
224 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
225 MM_RM_ERROR("Dbus destroy request failed 0x%x", ret);
227 __destroy_dispatcher(handle);
229 g_ptr_array_free(handle->resources, TRUE);
230 __mm_resources_unlock(handle);
232 g_mutex_clear(&handle->resources_lock);
235 if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
236 MM_RM_INFO("RM #%"PRIu64" is destroyed", _mm_rm_hash64(id));
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)
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;
248 MM_RM_INFO("Enter %p", rm);
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;
258 __mm_resources_lock(handle);
259 __mm_resource_handles_unlock();
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);
265 *resource_h = resource;
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);
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)
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;
282 int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
284 MM_RM_INFO("Enter %p", rm);
286 __mm_resource_handles_lock();
287 MM_RESOURCE_MANAGER_CHECK(handle);
288 __mm_resources_lock(handle);
289 __mm_resource_handles_unlock();
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.");
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;
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");
309 resource->volume = new_volume;
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");
317 tmp_resource->volume = resource->volume;
318 tmp_resource->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE;
320 g_ptr_array_add(handle->resources, resource);
321 resource->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE;
322 resource->volume = new_volume;
324 handle->resources->pdata[idx] = tmp_resource;
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);
334 int _mm_resource_manager_mark_for_release(mm_resource_manager_h rm, mm_resource_manager_res_h resource_h)
336 mm_resource_manager_s *handle;
337 mm_resource_manager_res_p resource;
338 mm_resource_manager_id handle_id;
340 const char *res_name = NULL;
342 MM_RM_INFO("Enter %p", rm);
344 __mm_resource_handles_lock();
346 handle = MM_RESOURCE_MANAGER(rm);
347 MM_RESOURCE_MANAGER_CHECK(handle);
348 handle_id = handle->id;
349 MM_RM_HASH64(handle_id);
351 resource = (mm_resource_manager_res_p)resource_h;
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);
360 res_name = _mm_resource_manager_get_res_str(resource->type);
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);
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));
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;
376 handle->is_release_marked[resource->type] = TRUE;
377 MM_RM_INFO("(%s) is marked for release in RM #%"PRIu64, res_name, handle_id);
379 __mm_resources_lock(handle);
380 __mm_resource_handles_unlock();
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");
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");
389 __mm_resources_unlock(handle);
391 MM_RM_INFO("RM #%"PRIu64" is completed to mark", handle_id);
393 return MM_RESOURCE_MANAGER_ERROR_NONE;
396 int _mm_resource_manager_release_other_resources(mm_resource_manager_s *handle)
402 MM_RM_INFO("Enter %p", handle);
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));
408 len = handle->resources->len;
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_INFO("[idx %d] resource length %d", idx, len);
415 MM_RM_INFO("[RELEASE] dbus_commit");
416 ret = __dbus_commit(handle);
417 if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
418 MM_RM_DEBUG("Changes in RM #%"PRIu64" have been committed successfully", _mm_rm_hash64(handle->id));
420 MM_RM_ERROR("Dbus commit request failed");
422 MM_RM_INFO("All resources are marked for release in RM #%"PRIu64, _mm_rm_hash64(handle->id));
427 int _mm_resource_manager_mark_all_for_release(mm_resource_manager_h rm)
429 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
433 MM_RM_INFO("Enter %p", rm);
435 __mm_resource_handles_lock();
436 MM_RESOURCE_MANAGER_CHECK(handle);
437 if (handle->release_cb.is_invoked) {
438 MM_RM_ERROR("RM #%"PRIu64" is releasing resource, so resource manager can't support your mark all for release",
439 _mm_rm_hash64(handle->id));
440 __mm_resource_handles_unlock();
441 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
443 __mm_resources_lock(handle);
444 __mm_resource_handles_unlock();
446 len = handle->resources->len;
448 for (idx = 0; idx < len; idx++) {
449 if (!__mark_resource_for_release(handle->resources, idx, (mm_resource_manager_res_p) handle->resources->pdata[idx])) {
450 MM_RM_WARNING("[idx %d] resource is already marked or released", idx);
451 __mm_resources_unlock(handle);
452 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
454 handle->is_release_marked[idx] = TRUE;
457 MM_RM_INFO("All resources are marked for release in RM #%"PRIu64, _mm_rm_hash64(handle->id));
458 __mm_resources_unlock(handle);
460 return MM_RESOURCE_MANAGER_ERROR_NONE;
463 int _mm_resource_manager_get_resource_info(mm_resource_manager_h rm,
464 mm_resource_manager_res_h resource_h, mm_resource_manager_res_info_s *info)
466 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
467 mm_resource_manager_res_p resource = (mm_resource_manager_res_p) resource_h;
470 MM_RM_INFO("Enter %p", rm);
472 __mm_resource_handles_lock();
473 MM_RESOURCE_MANAGER_CHECK(handle);
474 __mm_resources_lock(handle);
475 __mm_resource_handles_unlock();
477 idx = __get_resource_index(handle, resource);
478 MM_RM_UNLOCK_RETVM_IF(idx == MM_RESOURCE_MANAGER_RES_NOT_FOUND, handle->resources_lock,
479 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "Invalid RM #%"PRIu64"", _mm_rm_hash64(handle->id));
481 info->type = resource->type;
482 info->volume = resource->volume;
483 info->is_acquire_failed = resource->is_acquire_failed;
485 MM_RM_INFO("Info structure of resource %p in RM #%"PRIu64" is filled", resource_h, _mm_rm_hash64(handle->id));
486 __mm_resources_unlock(handle);
488 return MM_RESOURCE_MANAGER_ERROR_NONE;
491 int _mm_resource_manager_commit(mm_resource_manager_h rm)
493 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
496 MM_RM_INFO("Enter %p", rm);
498 __mm_resource_handles_lock();
499 MM_RESOURCE_MANAGER_CHECK(handle);
500 if (handle->release_cb.is_invoked) {
501 MM_RM_ERROR("RM #%"PRIu64" is releasing resource, so resource manager can't support your commit request",
502 _mm_rm_hash64(handle->id));
503 __mm_resource_handles_unlock();
504 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
506 __mm_resources_lock(handle);
507 __mm_resource_handles_unlock();
509 handle->pid = (int)getpid();
511 MM_RM_INFO("[pid %d] dbus_commit RM #%"PRIu64, handle->pid, _mm_rm_hash64(handle->id));
512 ret = __dbus_commit(handle);
513 if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
514 MM_RM_DEBUG("Changes in RM #%"PRIu64" have been committed successfully", _mm_rm_hash64(handle->id));
516 MM_RM_ERROR("Dbus commit request failed");
517 __mm_resources_unlock(handle);
522 int _mm_resource_manager_set_status_cb(mm_resource_manager_h rm, mm_resource_manager_status_cb cb, void *user_data)
524 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
526 MM_RM_INFO("Enter %p", rm);
528 __mm_resource_handles_lock();
529 MM_RESOURCE_MANAGER_CHECK(handle);
530 __mm_resources_lock(handle);
531 __mm_resource_handles_unlock();
533 handle->status_cb.cb = cb;
534 handle->status_cb.user_data = user_data;
535 __mm_resources_unlock(handle);
537 MM_RM_INFO("Status callback %p in RM #%"PRIu64" is set", cb, _mm_rm_hash64(handle->id));
539 return MM_RESOURCE_MANAGER_ERROR_NONE;
542 int _mm_resource_manager_get_res_type_max_volume(mm_resource_manager_h rm,
543 mm_resource_manager_res_type_e type, mm_resource_manager_res_volume *max_volume)
545 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
547 if (handle->__max_resource_volumes[type] == MM_RESOURCE_MANAGER_NO_RES) {
548 MM_RM_DEBUG("No resource for the platform");
549 return MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED;
551 *max_volume = handle->__max_resource_volumes[type];
552 return MM_RESOURCE_MANAGER_ERROR_NONE;
556 int _mm_resource_manager_get_res_type_volume(mm_resource_manager_h rm, mm_resource_manager_res_type_e type,
557 mm_resource_manager_res_type_cond_e condition, mm_resource_manager_res_volume *volume)
559 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
561 if (handle->__condition_volumes[type][condition] == MM_RESOURCE_MANAGER_NO_RES) {
562 MM_RM_DEBUG("No pair (resource, condition) for the platform");
563 return MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED;
565 *volume = handle->__condition_volumes[type][condition];
566 return MM_RESOURCE_MANAGER_ERROR_NONE;
570 int _mm_resource_manager_get_type_max_instance(mm_resource_manager_h rm,
571 mm_resource_manager_res_type_e type, int *max_instance)
573 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
575 if (handle->__max_instance[type] == MM_RESOURCE_MANAGER_NO_RES) {
576 MM_RM_DEBUG("No resource for the platform");
577 return MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED;
580 *max_instance = handle->__max_instance[type];
581 return MM_RESOURCE_MANAGER_ERROR_NONE;
584 static void __mm_resource_manager_release_callback(mm_resource_manager_s *handle, mm_resource_manager_id id,
585 mm_resource_manager_res_type_e type, mm_resource_manager_res_volume volume)
587 mm_resource_manager_res_s *resource;
588 mm_resource_manager_id handle_id;
589 mm_resource_manager_res_type_e t;
590 gboolean release_all = FALSE;
593 const char *res_name = NULL;
595 handle_id = handle->id;
596 MM_RM_HASH64(handle_id);
598 res_name = _mm_resource_manager_get_res_str(type);
600 MM_RM_DEBUG("Release callback is invoked for %s of volume %d in handle RM #%"PRIu64" input RM #%"PRIu64,
601 res_name, volume, handle_id, id);
603 if (handle_id != id) {
604 MM_RM_WARNING("handle RM #%"PRIu64" input RM #%"PRIu64" is different", handle_id, id);
605 __mm_resource_handles_unlock();
609 for (t = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER; t < MM_RESOURCE_MANAGER_RES_TYPE_MAX; t++) {
610 if (handle->is_release_marked[t] && t == type) {
611 MM_RM_WARNING("mark_for_release() of %s is executed, which means that we can sync with rm dmn right now RM #%"PRIu64,
612 res_name, handle_id);
613 if (__send_release_cb_sync(handle->id) != MM_RESOURCE_MANAGER_ERROR_NONE)
614 MM_RM_ERROR("__send_release_cb_sync is failed");
615 __mm_resource_handles_unlock();
620 __mm_resources_lock(handle);
621 __mm_resource_handles_unlock();
622 prev_len = handle->resources->len;
624 MM_RM_DEBUG("resource %p length %d", handle->resources, prev_len);
626 for (idx = 0; idx < prev_len; idx++) {
627 resource = (mm_resource_manager_res_s *)handle->resources->pdata[idx];
628 if (resource->type == type && resource->volume == volume) {
629 /* FIXME : Set true in advance release callback invoking to prevent deadlock with resource marking */
630 handle->release_cb.is_invoked = TRUE;
632 MM_RM_INFO("[res %p type %s volume %d] release_cb", resource, res_name, volume);
633 release_all = ((mm_resource_manager_release_cb)handle->release_cb.cb)(handle, resource, handle->release_cb.user_data);
634 MM_RM_INFO("[%d] release_cb is completed", release_all);
636 if (__send_release_cb_sync(handle->id) != MM_RESOURCE_MANAGER_ERROR_NONE) {
637 MM_RM_ERROR("__send_release_cb_sync is failed");
638 handle->release_cb.is_invoked = FALSE;
642 /* If there is only one resource, the release callback value must be reset considering return value in case the handle is reused. */
644 handle->release_cb.is_invoked = FALSE;
646 g_ptr_array_remove_index_fast(handle->resources, idx);
648 MM_RM_DEBUG("resource length %d => %d", prev_len, handle->resources->len);
654 MM_RM_DEBUG("[%d] RELEASE ALL", release_all);
657 if (_mm_resource_manager_release_other_resources(handle) == MM_RESOURCE_MANAGER_ERROR_NONE) {
658 MM_RM_DEBUG("All resources are released after release cb");
659 handle->release_cb.is_invoked = FALSE;
660 MM_RM_WARNING("Reset release_cb release_cb.is_invoked RM #%"PRIu64, handle_id);
662 MM_RM_WARNING("Resources cannot be released after release cb");
666 __mm_resources_unlock(handle);
669 static void __mm_resource_manager_status_callback(mm_resource_manager_s *handle, mm_resource_manager_status_e status)
671 __mm_resources_lock(handle);
672 __mm_resource_handles_unlock();
673 if (handle->status_cb.cb)
674 ((mm_resource_manager_status_cb)handle->status_cb.cb)(handle, status, handle->status_cb.user_data);
676 __mm_resources_unlock(handle);
679 static void __mm_resource_handles_lock(void)
681 LOGD(">>> handles lock");
682 g_mutex_lock(&handles_lock);
685 static void __mm_resource_handles_unlock(void)
687 g_mutex_unlock(&handles_lock);
688 LOGD("<<< handles unlock");
691 static void __mm_resources_lock(mm_resource_manager_s *h)
693 MM_RM_RETM_IF(!h, "handle is NULL");
694 LOGD(">> resource lock");
695 g_mutex_lock(&h->resources_lock);
698 static void __mm_resources_unlock(mm_resource_manager_s *h)
700 MM_RM_RETM_IF(!h, "handle is NULL");
701 g_mutex_unlock(&h->resources_lock);
702 LOGD("<< resource unlock");
705 static int __check_resource(mm_resource_manager_s *rm, mm_resource_manager_res_type_e type, mm_resource_manager_res_volume volume)
707 mm_resource_manager_res_volume local_volume = rm->__max_resource_volumes[type];
708 mm_resource_manager_res_p i_res;
711 MM_RM_DEBUG("[RM #%"PRIu64" type : %d] resource (#%d) for the platform", _mm_rm_hash64(rm->id), type, local_volume);
714 for (i = 0; i < rm->resources->len; i++) {
715 i_res = (mm_resource_manager_res_p) rm->resources->pdata[i];
716 if (i_res->type == type && i_res->state != MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE &&
717 (i_res->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL ||(local_volume -= i_res->volume) < volume)) {
718 MM_RM_ERROR("Requested volume %d exceeds remaining local volume %d", volume, i_res->volume ==
719 MM_RESOURCE_MANAGER_RES_VOLUME_FULL ? 0 : local_volume);
720 return MM_RESOURCE_MANAGER_ERROR_NOT_ENOUGH;
725 return MM_RESOURCE_MANAGER_ERROR_NONE;
728 static int __create_resource(mm_resource_manager_s *rm,
729 mm_resource_manager_res_type_e type, mm_resource_manager_res_volume volume, mm_resource_manager_res_p *res)
733 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
735 MM_RM_RETVM_IF(handle == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "NULL handle pointer");
736 MM_RM_RETVM_IF(res == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "NULL pointer");
738 ret = __check_resource(rm, type, volume);
739 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
742 *res = g_new0(mm_resource_manager_res_s, 1);
743 (*res)->handle_id = handle->id;
745 if (handle->__max_resource_volumes[type] == MM_RESOURCE_MANAGER_RES_VOLUME_FULL &&
746 volume != MM_RESOURCE_MANAGER_RES_VOLUME_FULL)
747 (*res)->volume = MM_RESOURCE_MANAGER_RES_VOLUME_FULL;
749 (*res)->volume = volume;
751 return MM_RESOURCE_MANAGER_ERROR_NONE;
754 static void __destroy_resource(void *res)
759 static int __get_resource_index(mm_resource_manager_s *rm, mm_resource_manager_res_p res)
763 MM_RM_RETVM_IF(rm == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "NULL handle pointer");
765 for (i = 0; i < rm->resources->len; i++) {
766 if (rm->resources->pdata[i] == (gpointer) res)
770 MM_RM_WARNING("[%d] Resource %p is marked for release in RM #%"PRIu64,
771 rm->resources->len, res, _mm_rm_hash64(rm->id));
773 return MM_RESOURCE_MANAGER_RES_NOT_FOUND;
776 static gboolean __mark_resource_for_release(GPtrArray *resources, int index, mm_resource_manager_res_p resource)
778 switch (resource->state) {
779 case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
780 g_ptr_array_remove_index_fast(resources, index);
781 MM_RM_DEBUG("Resource %p is removed implicitly", resource);
783 case MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED:
784 resource->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE;
785 MM_RM_DEBUG("Resource %p is successfully marked", resource);
787 case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
788 MM_RM_DEBUG("Resource %p is already marked or released", resource);
795 static gboolean __check_rm_handle(mm_resource_manager_s *handle)
799 for (i = 0; i < handles->len; i++) {
800 if (g_ptr_array_index(handles, i) == handle)
806 static int __send_release_cb_sync(mm_resource_manager_id id)
808 int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
811 MM_RM_DEBUG("Enter");
812 sync_fd = open(RELEASE_CB_SYNC_PATH, O_WRONLY | O_NONBLOCK);
813 MM_RM_DEBUG("[%d] opened %s", sync_fd, RELEASE_CB_SYNC_PATH);
815 MM_RM_RETVM_IF(sync_fd == -1, MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
816 "Sync FIFO cannot be opened [errno %d]", errno);
818 if (write(sync_fd, &id, sizeof(id)) == sizeof(id)) {
819 MM_RM_INFO("[SYNC] message is sent successfully RM #%"PRIu64, _mm_rm_hash64(id));
821 MM_RM_ERROR("[SYNC] message cannot be sent RM #%"PRIu64, _mm_rm_hash64(id));
822 ret = MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
825 MM_RM_RETVM_IF(close(sync_fd) == -1, MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
826 "[%d] close failed [errno %d]", sync_fd, errno);
827 MM_RM_DEBUG("[%d] closed", sync_fd);
832 static void __init_lib()
834 handles = g_ptr_array_sized_new(MM_RESOURCE_MANAGER_RESERVED_HANDLE_ARRAY_SIZE);
835 MM_RM_RETM_IF(handles == NULL, "API lib cannot be initialized");
837 MM_RM_INFO("API lib is loaded");
840 static void __deinit_lib()
842 if (handles->len > 0) {
843 MM_RM_DEBUG("Handles array [%d] is not empty. It will be cleaned now.", handles->len);
844 while (handles->len > 0)
845 _mm_resource_manager_destroy(handles->pdata[0]);
848 g_ptr_array_free(handles, TRUE);
850 MM_RM_INFO("API lib is unloaded");
853 static int __dbus_init(mm_resource_manager_s *handle)
855 GError *error = NULL;
857 MM_RM_RETVM_IF(handle->dbus_proxy != NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Dbus proxy is not NULL");
859 g_main_context_push_thread_default(handle->dispatcher_context);
860 handle->dbus_proxy = mmresource_manager_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, 0, RMD_GDBUS_NAME, RMD_GDBUS_PATH, NULL, &error);
861 g_main_context_pop_thread_default(handle->dispatcher_context);
862 MM_RM_RET_IF_GERR(error, "Dbus proxy cannot be created");
864 if (g_signal_connect(handle->dbus_proxy, "release_callback", (GCallback)__dbus_release_callback, NULL) < 1 ||
865 g_signal_connect(handle->dbus_proxy, "status_callback", (GCallback)__dbus_status_callback, NULL) < 1) {
867 g_object_unref(handle->dbus_proxy);
868 handle->dbus_proxy = NULL;
869 MM_RM_ERROR("Release or status callback signals cannot be connected");
871 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
874 return MM_RESOURCE_MANAGER_ERROR_NONE;
877 static int __dbus_deinit(mm_resource_manager_s *handle)
879 MM_RM_RETVM_IF(handle->dbus_proxy == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Dbus proxy is NULL");
880 g_object_unref(handle->dbus_proxy);
881 handle->dbus_proxy = NULL;
882 return MM_RESOURCE_MANAGER_ERROR_NONE;
885 static int __dbus_init_conf(mm_resource_manager_s *handle)
888 GError *error = NULL;
889 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
890 GVariant *max_volume = NULL;
891 GVariant *cond_volume = NULL;
892 GVariant *max_instance = NULL;
894 GVariantIter volume_iter;
895 GVariantIter cond_volume_iter;
897 mmresource_manager_call_conf_sync(handle->dbus_proxy, &rm_error, &max_volume, &cond_volume, &max_instance, NULL, &error);
898 MM_RM_RET_IF_GERR(error, "DBus conf msg cannot be sent");
900 MM_RM_RETVM_IF(max_volume == NULL || cond_volume == NULL,
901 MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Variant data are empty");
903 if (g_variant_iter_init(&volume_iter, max_volume) == MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
904 for (i = 0; g_variant_iter_next(&volume_iter, "i", &handle->__max_resource_volumes[i]); i++);
905 g_variant_unref(max_volume);
908 MM_RM_ERROR("Wrong max volume array size");
912 if (g_variant_iter_init(&volume_iter, cond_volume) == MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
913 for (i = 0; (tmp = g_variant_iter_next_value(&volume_iter)) != NULL; i++) {
914 if (g_variant_iter_init(&cond_volume_iter, tmp) == MM_RESOURCE_MANAGER_RES_TYPE_COND_MAX) {
915 for (j = 0; g_variant_iter_next(&cond_volume_iter, "i", &handle->__condition_volumes[i][j]); j++);
916 g_variant_unref(tmp);
918 g_variant_unref(tmp);
919 MM_RM_ERROR("Wrong condition volume array size");
920 rm_error = MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
924 g_variant_unref(cond_volume);
927 MM_RM_ERROR("Wrong condition volume array size");
931 if (g_variant_iter_init(&volume_iter, max_instance) == MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
932 for (i = 0; g_variant_iter_next(&volume_iter, "i", &handle->__max_instance[i]); i++);
933 g_variant_unref(max_instance);
936 MM_RM_ERROR("Wrong max instance array size");
942 g_variant_unref(max_volume);
943 g_variant_unref(cond_volume);
944 g_variant_unref(max_instance);
945 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
948 static int __dbus_create(mm_resource_manager_s *handle, mm_resource_manager_app_class_e app_class)
950 GError *error = NULL;
951 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
953 mmresource_manager_call_create_sync(handle->dbus_proxy, app_class, &handle->id, &rm_error, NULL, &error);
954 MM_RM_RET_IF_GERR(error, "DBus create msg cannot be sent");
956 MM_RM_DEBUG("Create returned id - RM #%"PRIu64", error - %d", _mm_rm_hash64(handle->id), rm_error);
961 static int __dbus_destroy(mm_resource_manager_s *handle)
963 GError *error = NULL;
964 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
966 mmresource_manager_call_destroy_sync(handle->dbus_proxy, handle->id, &rm_error, NULL, &error);
967 MM_RM_RET_IF_GERR(error, "DBus destroy msg cannot be sent");
969 MM_RM_DEBUG("Destroy for id - RM #%"PRIu64" returned error - %d", _mm_rm_hash64(handle->id), rm_error);
971 return MM_RESOURCE_MANAGER_ERROR_NONE;
974 static int __dbus_commit(mm_resource_manager_s *handle)
978 GVariantBuilder *release_builder;
979 GVariantBuilder *acquire_builder;
980 GVariant *flags_variant;
981 GVariantIter flags_iter;
982 mm_resource_manager_res_p resource;
986 GError *error = NULL;
987 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
989 release_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
990 acquire_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
992 for (i = 0; i < handle->resources->len; i++) {
993 resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
995 switch (resource->state) {
996 case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
997 g_variant_builder_add_value(acquire_builder, g_variant_new("(iii)", resource->type, resource->volume, handle->pid));
1000 case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
1001 g_variant_builder_add_value(release_builder, g_variant_new("(iii)", resource->type, resource->volume, handle->pid));
1009 if (release_num + acquire_num == 0) {
1010 g_variant_builder_unref(release_builder);
1011 g_variant_builder_unref(acquire_builder);
1012 MM_RM_DEBUG("There is nothing to commit - dbus request is not sent [%d %d]", release_num, acquire_num);
1016 /* Acquire and release arrays are ended with special element, because g_variant_builder_end crashes without at least one element */
1017 g_variant_builder_add_value(acquire_builder, g_variant_new("(iii)", MM_RESOURCE_MANAGER_NO_RES, 0, handle->pid));
1018 acquire = g_variant_builder_end(acquire_builder);
1019 g_variant_builder_unref(acquire_builder);
1021 g_variant_builder_add_value(release_builder, g_variant_new("(iii)", MM_RESOURCE_MANAGER_NO_RES, 0, handle->pid));
1022 release = g_variant_builder_end(release_builder);
1023 g_variant_builder_unref(release_builder);
1025 mmresource_manager_call_commit_sync(handle->dbus_proxy, handle->id, release, acquire, &rm_error, &flags_variant, NULL, &error);
1026 MM_RM_RET_IF_GERR(error, "DBus commit msg cannot be sent");
1028 MM_RM_DEBUG("Commit for id - RM #%"PRIu64" returned error - %d", _mm_rm_hash64(handle->id), rm_error);
1030 if (rm_error == MM_RESOURCE_MANAGER_ERROR_NONE) {
1031 for (i = 0; i < handle->resources->len; i++) {
1032 resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
1034 switch (resource->state) {
1035 case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
1036 resource->state = MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED;
1037 resource->is_acquire_failed = FALSE;
1039 case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
1040 handle->is_release_marked[resource->type] = FALSE;
1041 g_ptr_array_remove_index_fast(handle->resources, i--);
1047 } else if (rm_error == MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY) {
1048 g_variant_iter_init(&flags_iter, flags_variant);
1050 for (i = 0; i < handle->resources->len; i++) {
1051 resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
1053 if (resource->state == MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE) {
1054 if (!g_variant_iter_next(&flags_iter, "b", &resource->is_acquire_failed))
1055 MM_RM_ERROR("g_variant_iter_next failed to get the value of is_acquire_failed");
1060 g_variant_unref(flags_variant);
1065 static void __dbus_release_callback(MMResourceManager *object, guint64 arg_id, gint arg_resource_type, gint arg_volume)
1067 mm_resource_manager_s *handle;
1068 mm_resource_manager_id handle_id;
1071 __mm_resource_handles_lock();
1073 for (i = 0; i < handles->len; i++) {
1074 handle = (mm_resource_manager_s *)handles->pdata[i];
1075 handle_id = handle->id;
1076 MM_RM_HASH64(handle_id);
1078 if (handle->dbus_proxy == object && handle_id == arg_id) {
1079 if (handle->release_cb.is_invoked) {
1080 MM_RM_WARNING("other resource release cb is already executed RM #%"PRIu64, handle_id);
1081 if (__send_release_cb_sync(handle->id) != MM_RESOURCE_MANAGER_ERROR_NONE)
1082 MM_RM_ERROR("__send_release_cb_sync is failed");
1083 __mm_resource_handles_unlock();
1086 MM_RM_INFO("[release_callback] RM #%"PRIu64, handle_id);
1087 __mm_resource_manager_release_callback(handle, arg_id, arg_resource_type, arg_volume);
1092 __mm_resource_handles_unlock();
1095 static void __dbus_status_callback(MMResourceManager *object, gint arg_status)
1097 mm_resource_manager_s *handle;
1100 MM_RM_INFO("status callback status %d", arg_status);
1101 __mm_resource_handles_lock();
1103 for (i = 0; i < handles->len; i++) {
1104 handle = (mm_resource_manager_s *)handles->pdata[i];
1105 if (handle->dbus_proxy == object) {
1106 __mm_resource_manager_status_callback(handle, arg_status);
1111 __mm_resource_handles_unlock();
1114 static gpointer __dispatcher_thread(gpointer user_data)
1116 GMainLoop *ml = (GMainLoop *) user_data;
1118 MM_RM_INFO("main loop %p", ml);
1121 g_main_loop_run(ml);
1122 MM_RM_INFO("main loop %p quit", ml);
1128 static void __destroy_dispatcher(mm_resource_manager_s *handle)
1130 MM_RM_WARNING("handle %p", handle);
1132 __mm_resource_handles_lock();
1134 if (__dbus_deinit(handle) != MM_RESOURCE_MANAGER_ERROR_NONE)
1135 MM_RM_ERROR("Error while dbus deinitializing");
1137 MM_RM_INFO("dispatcher main loop %p", handle->dispatcher_loop);
1138 if (handle->dispatcher_loop) {
1139 if (g_main_loop_is_running(handle->dispatcher_loop)) {
1140 MM_RM_INFO("mainloop %p is running", handle->dispatcher_loop);
1141 g_main_loop_quit(handle->dispatcher_loop);
1144 g_main_loop_unref(handle->dispatcher_loop);
1145 handle->dispatcher_loop = NULL;
1148 MM_RM_INFO("dispatcher thread %p", handle->dispatcher_thread);
1149 if (handle->dispatcher_thread) {
1150 g_thread_join(handle->dispatcher_thread);
1151 MM_RM_INFO("dispatcher thread join %p", handle->dispatcher_thread);
1152 handle->dispatcher_thread = NULL;
1155 MM_RM_INFO("dispatcher context %p", handle->dispatcher_context);
1156 if (handle->dispatcher_context) {
1157 g_main_context_unref(handle->dispatcher_context);
1158 handle->dispatcher_context = NULL;
1161 __mm_resource_handles_unlock();