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_WARNING("[idx %d] resource length %d", idx, len);
414 return MM_RESOURCE_MANAGER_ERROR_NONE;
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));
423 MM_RM_ERROR("Dbus commit request failed");
425 MM_RM_INFO("All resources are marked for release in RM #%"PRIu64, _mm_rm_hash64(handle->id));
430 int _mm_resource_manager_mark_all_for_release(mm_resource_manager_h rm)
432 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
436 MM_RM_INFO("Enter %p", rm);
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;
446 __mm_resources_lock(handle);
447 __mm_resource_handles_unlock();
449 len = handle->resources->len;
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;
457 handle->is_release_marked[idx] = TRUE;
460 MM_RM_INFO("All resources are marked for release in RM #%"PRIu64, _mm_rm_hash64(handle->id));
461 __mm_resources_unlock(handle);
463 return MM_RESOURCE_MANAGER_ERROR_NONE;
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)
469 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
470 mm_resource_manager_res_p resource = (mm_resource_manager_res_p) resource_h;
473 MM_RM_INFO("Enter %p", rm);
475 __mm_resource_handles_lock();
476 MM_RESOURCE_MANAGER_CHECK(handle);
477 __mm_resources_lock(handle);
478 __mm_resource_handles_unlock();
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));
484 info->type = resource->type;
485 info->volume = resource->volume;
486 info->is_acquire_failed = resource->is_acquire_failed;
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);
491 return MM_RESOURCE_MANAGER_ERROR_NONE;
494 int _mm_resource_manager_commit(mm_resource_manager_h rm)
496 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
499 MM_RM_INFO("Enter %p", rm);
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;
509 __mm_resources_lock(handle);
510 __mm_resource_handles_unlock();
512 handle->pid = (int)getpid();
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));
519 MM_RM_ERROR("Dbus commit request failed");
520 __mm_resources_unlock(handle);
525 int _mm_resource_manager_set_status_cb(mm_resource_manager_h rm, mm_resource_manager_status_cb cb, void *user_data)
527 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
529 MM_RM_INFO("Enter %p", rm);
531 __mm_resource_handles_lock();
532 MM_RESOURCE_MANAGER_CHECK(handle);
533 __mm_resources_lock(handle);
534 __mm_resource_handles_unlock();
536 handle->status_cb.cb = cb;
537 handle->status_cb.user_data = user_data;
538 __mm_resources_unlock(handle);
540 MM_RM_INFO("Status callback %p in RM #%"PRIu64" is set", cb, _mm_rm_hash64(handle->id));
542 return MM_RESOURCE_MANAGER_ERROR_NONE;
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)
548 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
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;
554 *max_volume = handle->__max_resource_volumes[type];
555 return MM_RESOURCE_MANAGER_ERROR_NONE;
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)
562 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
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;
568 *volume = handle->__condition_volumes[type][condition];
569 return MM_RESOURCE_MANAGER_ERROR_NONE;
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)
576 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
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;
583 *max_instance = handle->__max_instance[type];
584 return MM_RESOURCE_MANAGER_ERROR_NONE;
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)
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;
596 const char *res_name = NULL;
598 handle_id = handle->id;
599 MM_RM_HASH64(handle_id);
601 res_name = _mm_resource_manager_get_res_str(type);
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);
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();
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();
623 __mm_resources_lock(handle);
624 __mm_resource_handles_unlock();
625 prev_len = handle->resources->len;
627 MM_RM_DEBUG("resource %p length %d", handle->resources, prev_len);
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;
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);
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;
645 /* If there is only one resource, the release callback value must be reset considering return value in case the handle is reused. */
647 handle->release_cb.is_invoked = FALSE;
649 g_ptr_array_remove_index_fast(handle->resources, idx);
651 MM_RM_DEBUG("resource length %d => %d", prev_len, handle->resources->len);
657 MM_RM_DEBUG("[%d] RELEASE ALL", 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);
665 MM_RM_WARNING("Resources cannot be released after release cb");
669 __mm_resources_unlock(handle);
672 static void __mm_resource_manager_status_callback(mm_resource_manager_s *handle, mm_resource_manager_status_e status)
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);
679 __mm_resources_unlock(handle);
682 static void __mm_resource_handles_lock(void)
684 LOGD(">>> handles lock");
685 g_mutex_lock(&handles_lock);
688 static void __mm_resource_handles_unlock(void)
690 g_mutex_unlock(&handles_lock);
691 LOGD("<<< handles unlock");
694 static void __mm_resources_lock(mm_resource_manager_s *h)
696 MM_RM_RETM_IF(!h, "handle is NULL");
697 LOGD(">> resource lock");
698 g_mutex_lock(&h->resources_lock);
701 static void __mm_resources_unlock(mm_resource_manager_s *h)
703 MM_RM_RETM_IF(!h, "handle is NULL");
704 g_mutex_unlock(&h->resources_lock);
705 LOGD("<< resource unlock");
708 static int __check_resource(mm_resource_manager_s *rm, mm_resource_manager_res_type_e type, mm_resource_manager_res_volume volume)
710 mm_resource_manager_res_volume local_volume = rm->__max_resource_volumes[type];
711 mm_resource_manager_res_p i_res;
714 MM_RM_DEBUG("[RM #%"PRIu64" type : %d] resource (#%d) for the platform", _mm_rm_hash64(rm->id), type, local_volume);
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;
728 return MM_RESOURCE_MANAGER_ERROR_NONE;
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)
736 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
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");
741 ret = __check_resource(rm, type, volume);
742 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
745 *res = g_new0(mm_resource_manager_res_s, 1);
746 (*res)->handle_id = handle->id;
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;
752 (*res)->volume = volume;
754 return MM_RESOURCE_MANAGER_ERROR_NONE;
757 static void __destroy_resource(void *res)
762 static int __get_resource_index(mm_resource_manager_s *rm, mm_resource_manager_res_p res)
766 MM_RM_RETVM_IF(rm == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "NULL handle pointer");
768 for (i = 0; i < rm->resources->len; i++) {
769 if (rm->resources->pdata[i] == (gpointer) res)
773 MM_RM_WARNING("[%d] Resource %p is marked for release in RM #%"PRIu64,
774 rm->resources->len, res, _mm_rm_hash64(rm->id));
776 return MM_RESOURCE_MANAGER_RES_NOT_FOUND;
779 static gboolean __mark_resource_for_release(GPtrArray *resources, int index, mm_resource_manager_res_p resource)
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);
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);
790 case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
791 MM_RM_DEBUG("Resource %p is already marked or released", resource);
798 static gboolean __check_rm_handle(mm_resource_manager_s *handle)
802 for (i = 0; i < handles->len; i++) {
803 if (g_ptr_array_index(handles, i) == handle)
809 static int __send_release_cb_sync(mm_resource_manager_id id)
811 int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
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);
818 MM_RM_RETVM_IF(sync_fd == -1, MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
819 "Sync FIFO cannot be opened [errno %d]", errno);
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));
824 MM_RM_ERROR("[SYNC] message cannot be sent RM #%"PRIu64, _mm_rm_hash64(id));
825 ret = MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
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);
835 static void __init_lib()
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");
840 MM_RM_INFO("API lib is loaded");
843 static void __deinit_lib()
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]);
851 g_ptr_array_free(handles, TRUE);
853 MM_RM_INFO("API lib is unloaded");
856 static int __dbus_init(mm_resource_manager_s *handle)
858 GError *error = NULL;
860 MM_RM_RETVM_IF(handle->dbus_proxy != NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Dbus proxy is not NULL");
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");
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) {
870 g_object_unref(handle->dbus_proxy);
871 handle->dbus_proxy = NULL;
872 MM_RM_ERROR("Release or status callback signals cannot be connected");
874 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
877 return MM_RESOURCE_MANAGER_ERROR_NONE;
880 static int __dbus_deinit(mm_resource_manager_s *handle)
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;
888 static int __dbus_init_conf(mm_resource_manager_s *handle)
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;
897 GVariantIter volume_iter;
898 GVariantIter cond_volume_iter;
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");
903 MM_RM_RETVM_IF(max_volume == NULL || cond_volume == NULL,
904 MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Variant data are empty");
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);
911 MM_RM_ERROR("Wrong max volume array size");
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);
921 g_variant_unref(tmp);
922 MM_RM_ERROR("Wrong condition volume array size");
923 rm_error = MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
927 g_variant_unref(cond_volume);
930 MM_RM_ERROR("Wrong condition volume array size");
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);
939 MM_RM_ERROR("Wrong max instance array size");
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;
951 static int __dbus_create(mm_resource_manager_s *handle, mm_resource_manager_app_class_e app_class)
953 GError *error = NULL;
954 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
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");
959 MM_RM_DEBUG("Create returned id - RM #%"PRIu64", error - %d", _mm_rm_hash64(handle->id), rm_error);
964 static int __dbus_destroy(mm_resource_manager_s *handle)
966 GError *error = NULL;
967 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
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");
972 MM_RM_DEBUG("Destroy for id - RM #%"PRIu64" returned error - %d", _mm_rm_hash64(handle->id), rm_error);
974 return MM_RESOURCE_MANAGER_ERROR_NONE;
977 static int __dbus_commit(mm_resource_manager_s *handle)
981 GVariantBuilder *release_builder;
982 GVariantBuilder *acquire_builder;
983 GVariant *flags_variant;
984 GVariantIter flags_iter;
985 mm_resource_manager_res_p resource;
989 GError *error = NULL;
990 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
992 release_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
993 acquire_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
995 for (i = 0; i < handle->resources->len; i++) {
996 resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
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));
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));
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);
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);
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);
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");
1031 MM_RM_DEBUG("Commit for id - RM #%"PRIu64" returned error - %d", _mm_rm_hash64(handle->id), rm_error);
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];
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;
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--);
1050 } else if (rm_error == MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY) {
1051 g_variant_iter_init(&flags_iter, flags_variant);
1053 for (i = 0; i < handle->resources->len; i++) {
1054 resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
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");
1063 g_variant_unref(flags_variant);
1068 static void __dbus_release_callback(MMResourceManager *object, guint64 arg_id, gint arg_resource_type, gint arg_volume)
1070 mm_resource_manager_s *handle;
1071 mm_resource_manager_id handle_id;
1074 __mm_resource_handles_lock();
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);
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();
1089 MM_RM_INFO("[release_callback] RM #%"PRIu64, handle_id);
1090 __mm_resource_manager_release_callback(handle, arg_id, arg_resource_type, arg_volume);
1095 __mm_resource_handles_unlock();
1098 static void __dbus_status_callback(MMResourceManager *object, gint arg_status)
1100 mm_resource_manager_s *handle;
1103 MM_RM_INFO("status callback status %d", arg_status);
1104 __mm_resource_handles_lock();
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);
1114 __mm_resource_handles_unlock();
1117 static gpointer __dispatcher_thread(gpointer user_data)
1119 GMainLoop *ml = (GMainLoop *) user_data;
1121 MM_RM_INFO("main loop %p", ml);
1124 g_main_loop_run(ml);
1125 MM_RM_INFO("main loop %p quit", ml);
1131 static void __destroy_dispatcher(mm_resource_manager_s *handle)
1133 MM_RM_WARNING("handle %p", handle);
1135 __mm_resource_handles_lock();
1137 if (__dbus_deinit(handle) != MM_RESOURCE_MANAGER_ERROR_NONE)
1138 MM_RM_ERROR("Error while dbus deinitializing");
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);
1147 g_main_loop_unref(handle->dispatcher_loop);
1148 handle->dispatcher_loop = NULL;
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;
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;
1164 __mm_resource_handles_unlock();