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;
44 } mm_resource_manager_cb_s;
47 mm_resource_manager_res_type_e type;
48 mm_resource_manager_res_volume volume;
49 mm_resource_manager_res_state_e state;
50 gboolean is_acquire_failed;
51 } mm_resource_manager_res_s;
52 typedef mm_resource_manager_res_s *mm_resource_manager_res_p;
55 mm_resource_manager_id id;
59 mm_resource_manager_cb_s release_cb;
60 mm_resource_manager_cb_s status_cb;
62 GMutex resources_lock;
64 mm_resource_manager_res_volume __max_resource_volumes
65 [MM_RESOURCE_MANAGER_RES_TYPE_MAX];
66 mm_resource_manager_res_volume __condition_volumes
67 [MM_RESOURCE_MANAGER_RES_TYPE_MAX]
68 [MM_RESOURCE_MANAGER_RES_TYPE_COND_MAX];
69 int __max_instance[MM_RESOURCE_MANAGER_RES_TYPE_MAX];
71 MMResourceManager *dbus_proxy;
73 GMainContext *dispatcher_context;
74 GMainLoop *dispatcher_loop;
75 GThread *dispatcher_thread;
76 } mm_resource_manager_s;
78 static void __init_lib() __attribute__((constructor));
79 static void __deinit_lib() __attribute__((destructor));
80 static int __check_resource(mm_resource_manager_s *rm,
81 mm_resource_manager_res_type_e type,
82 mm_resource_manager_res_volume volume);
83 static int __create_resource(mm_resource_manager_s *rm,
84 mm_resource_manager_res_type_e type,
85 mm_resource_manager_res_volume volume, mm_resource_manager_res_p *res);
86 static void __destroy_resource(void *res);
87 static int __get_resource_index(mm_resource_manager_s *rm,
88 mm_resource_manager_res_p res);
89 static gboolean __mark_resource_for_release(GPtrArray *resources, int index,
90 mm_resource_manager_res_p resource); /* FALSE if resource is destroyed */
91 static void __send_release_cb_sync(mm_resource_manager_id id);
92 static void __mm_resource_manager_release_callback(mm_resource_manager_s *handle,
93 mm_resource_manager_id id,
94 mm_resource_manager_res_type_e type,
95 mm_resource_manager_res_volume volume);
96 static void __mm_resource_manager_status_callback(mm_resource_manager_s *handle,
97 mm_resource_manager_status_e status);
98 static void __mm_resource_handles_lock(void);
99 static void __mm_resource_handles_unlock(void);
100 static void __mm_resources_lock(mm_resource_manager_s *h);
101 static void __mm_resources_unlock(mm_resource_manager_s *h);
104 static int __dbus_init(mm_resource_manager_s *handle);
105 static int __dbus_deinit(mm_resource_manager_s *handle);
106 static int __dbus_init_conf(mm_resource_manager_s *handle);
107 static gboolean __check_rm_handle(mm_resource_manager_s *handle);
108 static int __dbus_create(mm_resource_manager_s *handle,
109 mm_resource_manager_app_class_e app_class);
110 static int __dbus_destroy(mm_resource_manager_s *handle);
111 static int __dbus_commit(mm_resource_manager_s *handle);
112 static void __dbus_release_callback(MMResourceManager *object, guint64 arg_id,
113 gint arg_resource_type, gint arg_volume);
114 static void __dbus_status_callback(MMResourceManager *object, gint arg_status);
115 static gpointer __dispatcher_thread(gpointer user_data);
116 static void __destroy_dispatcher(mm_resource_manager_s *handle);
119 int _mm_resource_manager_create(mm_resource_manager_app_class_e app_class,
120 mm_resource_manager_release_cb cb, void *cb_data,
121 mm_resource_manager_h *rm)
123 mm_resource_manager_s *handle = *rm = NULL;
125 GError *error = NULL;
127 handle = (mm_resource_manager_s *) calloc(1, sizeof(mm_resource_manager_s));
128 MM_RM_RETVM_IF(NULL == handle, MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
129 "Error allocating memory for Handle");
131 handle->dispatcher_context = g_main_context_new();
132 if (!handle->dispatcher_context) {
134 MM_RM_ERROR("g_main_context_new failed");
135 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
137 MM_RM_INFO("new main context %p", handle->dispatcher_context);
139 handle->dispatcher_loop = g_main_loop_new(handle->dispatcher_context, FALSE);
140 if (!handle->dispatcher_loop) {
141 g_main_context_unref(handle->dispatcher_context);
143 MM_RM_ERROR("g_main_loop_new failed");
144 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
146 MM_RM_INFO("new main loop %p", handle->dispatcher_loop);
148 ret = __dbus_init(handle);
149 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
150 __destroy_dispatcher(handle);
152 MM_RM_ERROR("Error initializing dbus client");
156 handle->dispatcher_thread = g_thread_try_new("dispatcher_thread", __dispatcher_thread, handle->dispatcher_loop, &error);
157 if (!handle->dispatcher_thread) {
159 MM_RM_ERROR("dispatcher_thread creation failed : %s", error->message);
162 __destroy_dispatcher(handle);
164 return MM_RESOURCE_MANAGER_ERROR_NOT_ENOUGH;
166 MM_RM_INFO("new dispatcher thread %p", handle->dispatcher_thread);
168 ret = __dbus_init_conf(handle);
169 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
170 __destroy_dispatcher(handle);
172 MM_RM_ERROR("Configuration cannot be requested");
176 ret = __dbus_create(handle, app_class);
177 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
178 __destroy_dispatcher(handle);
180 MM_RM_ERROR("Dbus create request failed");
184 handle->release_cb.cb = cb;
185 handle->release_cb.user_data = cb_data;
187 handle->resources = g_ptr_array_new_full(
188 MM_RESOURCE_MANAGER_RESERVED_RES_ARRAY_SIZE, __destroy_resource);
190 g_mutex_init(&handle->resources_lock);
192 *rm = (mm_resource_manager_h *) handle;
193 __mm_resource_handles_lock();
194 g_ptr_array_add(handles, handle);
196 MM_RM_INFO("Resource manager #%"PRIu64" is created", _mm_rm_hash64(handle->id));
197 __mm_resource_handles_unlock();
199 return MM_RESOURCE_MANAGER_ERROR_NONE;
202 int _mm_resource_manager_destroy(mm_resource_manager_h rm)
204 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
205 mm_resource_manager_id id;
206 int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
208 __mm_resource_handles_lock();
209 MM_RESOURCE_MANAGER_CHECK(handle);
210 g_ptr_array_remove_fast(handles, handle);
211 __mm_resource_handles_unlock();
215 MM_RM_INFO("Resource manager #%"PRIu64" would be destroyed", _mm_rm_hash64(id));
217 __mm_resources_lock(handle);
218 ret = __dbus_destroy(handle);
219 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
220 MM_RM_ERROR("Dbus destroy request failed 0x%x", ret);
222 __destroy_dispatcher(handle);
224 g_ptr_array_free(handle->resources, TRUE);
225 __mm_resources_unlock(handle);
227 g_mutex_clear(&handle->resources_lock);
230 if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
231 MM_RM_INFO("Resource manager #%"PRIu64" is destroyed", _mm_rm_hash64(id));
236 int _mm_resource_manager_mark_for_acquire(
237 mm_resource_manager_h rm, mm_resource_manager_res_type_e type,
238 mm_resource_manager_res_volume volume,
239 mm_resource_manager_res_h *resource_h)
241 int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
242 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
243 mm_resource_manager_res_p resource;
245 __mm_resource_handles_lock();
246 MM_RESOURCE_MANAGER_CHECK(handle);
247 __mm_resources_lock(handle);
248 __mm_resource_handles_unlock();
250 ret = __create_resource(handle, type, volume, &resource);
251 MM_RM_UNLOCK_RETVM_IF(ret != MM_RESOURCE_MANAGER_ERROR_NONE,
252 handle->resources_lock, ret, "Resource cannot be created");
253 g_ptr_array_add(handle->resources, resource);
255 *resource_h = resource;
257 MM_RM_INFO("Resource %p of type %d with volume %d is marked for acquire in "
258 "resource manager #%"PRIu64, *resource_h, type, volume,
259 _mm_rm_hash64(handle->id));
260 __mm_resources_unlock(handle);
265 int _mm_resource_manager_resize_marked(mm_resource_manager_h rm,
266 mm_resource_manager_res_h resource_h,
267 mm_resource_manager_res_volume new_volume)
269 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
270 mm_resource_manager_res_p resource = (mm_resource_manager_res_p) resource_h;
271 mm_resource_manager_res_p tmp_resource;
272 mm_resource_manager_res_volume add_volume;
274 int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
276 __mm_resource_handles_lock();
277 MM_RESOURCE_MANAGER_CHECK(handle);
278 __mm_resources_lock(handle);
279 __mm_resource_handles_unlock();
281 i = __get_resource_index(handle, resource);
282 MM_RM_UNLOCK_RETVM_IF(i == MM_RESOURCE_MANAGER_RES_NOT_FOUND,
283 handle->resources_lock,
284 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
285 "Invalid resource handle");
286 if (new_volume == resource->volume) {
287 __mm_resources_unlock(handle);
288 MM_RM_DEBUG("New volume equals the old. Resize is not needed.");
292 add_volume = resource->volume != MM_RESOURCE_MANAGER_RES_VOLUME_FULL &&
293 new_volume != MM_RESOURCE_MANAGER_RES_VOLUME_FULL &&
294 resource->volume < new_volume ? (new_volume - resource->volume) : 0;
296 switch (resource->state) {
297 case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
298 if (add_volume > 0) {
299 ret = __check_resource(handle, resource->type, add_volume);
300 MM_RM_UNLOCK_RETVM_IF(ret != MM_RESOURCE_MANAGER_ERROR_NONE,
301 handle->resources_lock, ret, "Resource check failed");
303 resource->volume = new_volume;
306 case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
307 case MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED:
308 ret = __create_resource(handle, resource->type, add_volume, &tmp_resource);
309 MM_RM_UNLOCK_RETVM_IF(ret != MM_RESOURCE_MANAGER_ERROR_NONE,
310 handle->resources_lock, ret, "Resource cannot be created");
312 tmp_resource->volume = resource->volume;
313 tmp_resource->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE;
315 g_ptr_array_add(handle->resources, resource);
316 resource->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE;
317 resource->volume = new_volume;
319 handle->resources->pdata[i] = tmp_resource;
323 MM_RM_INFO("Resource %p is resized for acquire in resource manager #%"PRIu64,
324 resource_h, _mm_rm_hash64(handle->id));
325 __mm_resources_unlock(handle);
330 int _mm_resource_manager_mark_for_release(mm_resource_manager_h rm,
331 mm_resource_manager_res_h resource_h)
333 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
334 mm_resource_manager_res_p resource = (mm_resource_manager_res_p) resource_h;
337 __mm_resource_handles_lock();
338 MM_RESOURCE_MANAGER_CHECK(handle);
339 __mm_resources_lock(handle);
340 __mm_resource_handles_unlock();
342 i = __get_resource_index(handle, resource);
343 MM_RM_UNLOCK_RETVM_IF(i == MM_RESOURCE_MANAGER_RES_NOT_FOUND,
344 handle->resources_lock,
345 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
346 "Invalid resource handle");
348 __mark_resource_for_release(handle->resources, i, resource);
350 MM_RM_INFO("Resource %p is marked for release in resource manager #%"PRIu64,
351 resource_h, _mm_rm_hash64(handle->id));
352 __mm_resources_unlock(handle);
354 return MM_RESOURCE_MANAGER_ERROR_NONE;
357 int _mm_resource_manager_mark_all_for_release(mm_resource_manager_h rm)
359 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
362 __mm_resource_handles_lock();
363 MM_RESOURCE_MANAGER_CHECK(handle);
364 __mm_resources_lock(handle);
365 __mm_resource_handles_unlock();
367 for (i = 0; i < handle->resources->len; i++) {
368 if (!__mark_resource_for_release(handle->resources, i,
369 (mm_resource_manager_res_p) handle->resources->pdata[i]))
373 MM_RM_INFO("All resources are marked for release in resource manager #%"PRIu64,
374 _mm_rm_hash64(handle->id));
375 __mm_resources_unlock(handle);
377 return MM_RESOURCE_MANAGER_ERROR_NONE;
380 int _mm_resource_manager_get_resource_info(mm_resource_manager_h rm,
381 mm_resource_manager_res_h resource_h,
382 mm_resource_manager_res_info_s *info)
384 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
385 mm_resource_manager_res_p resource = (mm_resource_manager_res_p) resource_h;
388 __mm_resource_handles_lock();
389 MM_RESOURCE_MANAGER_CHECK(handle);
390 __mm_resources_lock(handle);
391 __mm_resource_handles_unlock();
393 i = __get_resource_index(handle, resource);
394 MM_RM_UNLOCK_RETVM_IF(i == MM_RESOURCE_MANAGER_RES_NOT_FOUND,
395 handle->resources_lock,
396 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
397 "Invalid resource handle");
399 info->type = resource->type;
400 info->volume = resource->volume;
401 info->is_acquire_failed = resource->is_acquire_failed;
403 MM_RM_INFO("Info structure of resource %p in resource manager #%"PRIu64" is filled",
404 resource_h, _mm_rm_hash64(handle->id));
405 __mm_resources_unlock(handle);
407 return MM_RESOURCE_MANAGER_ERROR_NONE;
410 int _mm_resource_manager_commit(mm_resource_manager_h rm)
412 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
415 __mm_resource_handles_lock();
416 MM_RESOURCE_MANAGER_CHECK(handle);
417 __mm_resources_lock(handle);
418 __mm_resource_handles_unlock();
420 ret = __dbus_commit(handle);
421 if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
422 MM_RM_INFO("Changes in resource manager #%"PRIu64" have been committed successfully",
423 _mm_rm_hash64(handle->id));
425 MM_RM_ERROR("Dbus commit request failed");
426 __mm_resources_unlock(handle);
431 int _mm_resource_manager_set_status_cb(mm_resource_manager_h rm,
432 mm_resource_manager_status_cb cb, void *user_data)
434 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
436 __mm_resource_handles_lock();
437 MM_RESOURCE_MANAGER_CHECK(handle);
438 __mm_resources_lock(handle);
439 __mm_resource_handles_unlock();
441 handle->status_cb.cb = cb;
442 handle->status_cb.user_data = user_data;
443 __mm_resources_unlock(handle);
445 MM_RM_INFO("Status callback %p in resource manager #%"PRIu64" is set", cb,
446 _mm_rm_hash64(handle->id));
448 return MM_RESOURCE_MANAGER_ERROR_NONE;
451 int _mm_resource_manager_get_res_type_max_volume(mm_resource_manager_h rm,
452 mm_resource_manager_res_type_e type,
453 mm_resource_manager_res_volume *max_volume)
455 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
457 if (handle->__max_resource_volumes[type] == MM_RESOURCE_MANAGER_NO_RES) {
458 MM_RM_DEBUG("No resource for the platform");
459 return MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED;
461 *max_volume = handle->__max_resource_volumes[type];
462 return MM_RESOURCE_MANAGER_ERROR_NONE;
466 int _mm_resource_manager_get_res_type_volume(mm_resource_manager_h rm,
467 mm_resource_manager_res_type_e type,
468 mm_resource_manager_res_type_cond_e condition,
469 mm_resource_manager_res_volume *volume)
471 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
473 if (handle->__condition_volumes[type][condition] == MM_RESOURCE_MANAGER_NO_RES) {
474 MM_RM_DEBUG("No pair (resource, condition) for the platform");
475 return MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED;
477 *volume = handle->__condition_volumes[type][condition];
478 return MM_RESOURCE_MANAGER_ERROR_NONE;
482 int _mm_resource_manager_get_type_max_instance(mm_resource_manager_h rm,
483 mm_resource_manager_res_type_e type, int *max_instance)
485 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
487 if (handle->__max_instance[type] == MM_RESOURCE_MANAGER_NO_RES) {
488 MM_RM_DEBUG("No resource for the platform");
489 return MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED;
492 *max_instance = handle->__max_instance[type];
493 return MM_RESOURCE_MANAGER_ERROR_NONE;
496 void __mm_resource_manager_release_callback(mm_resource_manager_s *handle,
497 mm_resource_manager_id id,
498 mm_resource_manager_res_type_e type,
499 mm_resource_manager_res_volume volume)
501 mm_resource_manager_res_s *resource;
502 mm_resource_manager_id handle_id;
503 gboolean release_all = FALSE;
506 MM_RM_INFO("Release callback is emitted for %s of volume %d in RM #%"PRIu64,
507 _mm_resource_manager_get_res_str(type), volume, id);
509 handle_id = handle->id;
510 MM_RM_HASH64(handle_id);
511 if (handle_id == id) {
512 __mm_resources_lock(handle);
513 __mm_resource_handles_unlock();
515 for (i = 0; i < handle->resources->len; i++) {
516 resource = (mm_resource_manager_res_s*)handle->resources->pdata[i];
517 if (resource->type == type && resource->volume == volume) {
519 release_all = ((mm_resource_manager_release_cb)
520 handle->release_cb.cb)(
521 handle, resource, handle->release_cb.user_data);
523 __send_release_cb_sync(handle->id);
525 g_ptr_array_remove_index_fast(handle->resources, i);
529 __mm_resources_unlock(handle);
532 if (_mm_resource_manager_mark_all_for_release(handle) == MM_RESOURCE_MANAGER_ERROR_NONE &&
533 _mm_resource_manager_commit(handle) == MM_RESOURCE_MANAGER_ERROR_NONE) {
534 MM_RM_DEBUG("All resources are released after release cb");
536 MM_RM_ERROR("Resources cannot be released after release cb");
540 __mm_resource_handles_unlock();
544 void __mm_resource_manager_status_callback(mm_resource_manager_s *handle,
545 mm_resource_manager_status_e status)
547 __mm_resources_lock(handle);
548 __mm_resource_handles_unlock();
549 if (handle->status_cb.cb) {
550 ((mm_resource_manager_status_cb)handle->status_cb.cb)(handle, status,
551 handle->status_cb.user_data);
553 __mm_resources_unlock(handle);
556 static void __mm_resource_handles_lock(void)
558 g_mutex_lock(&handles_lock);
561 static void __mm_resource_handles_unlock(void)
563 g_mutex_unlock(&handles_lock);
566 static void __mm_resources_lock(mm_resource_manager_s *h)
568 MM_RM_RETM_IF(!h, "handle is NULL");
569 g_mutex_lock(&h->resources_lock);
572 static void __mm_resources_unlock(mm_resource_manager_s *h)
574 MM_RM_RETM_IF(!h, "handle is NULL");
575 g_mutex_unlock(&h->resources_lock);
578 static int __check_resource(mm_resource_manager_s *rm,
579 mm_resource_manager_res_type_e type,
580 mm_resource_manager_res_volume volume)
582 mm_resource_manager_res_volume local_volume = rm->__max_resource_volumes[type];
583 mm_resource_manager_res_p i_res;
586 MM_RM_INFO("[#%"PRIu64" type : %d] resource (#%d) for the platform", _mm_rm_hash64(rm->id), type, local_volume);
589 for (i = 0; i < rm->resources->len; i++) {
590 i_res = (mm_resource_manager_res_p) rm->resources->pdata[i];
591 if (i_res->type == type && i_res->state != MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE &&
592 (i_res->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL ||
593 (local_volume -= i_res->volume) < volume)) {
594 MM_RM_ERROR("Requested volume %d exceeds remaining local volume %d",
596 i_res->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL ?
598 return MM_RESOURCE_MANAGER_ERROR_NOT_ENOUGH;
603 return MM_RESOURCE_MANAGER_ERROR_NONE;
606 static int __create_resource(mm_resource_manager_s *rm,
607 mm_resource_manager_res_type_e type,
608 mm_resource_manager_res_volume volume, mm_resource_manager_res_p *res)
612 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
614 MM_RM_RETVM_IF(handle == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
615 "NULL handle pointer");
616 MM_RM_RETVM_IF(res == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "NULL pointer");
617 ret = __check_resource(rm, type, volume);
618 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
621 *res = g_new0(mm_resource_manager_res_s, 1);
623 (*res)->volume = volume;
625 return MM_RESOURCE_MANAGER_ERROR_NONE;
628 static void __destroy_resource(void *res)
633 static int __get_resource_index(mm_resource_manager_s *rm, mm_resource_manager_res_p res)
637 for (i = 0; i < rm->resources->len; i++) {
638 if (rm->resources->pdata[i] == (gpointer) res)
642 return MM_RESOURCE_MANAGER_RES_NOT_FOUND;
645 static gboolean __mark_resource_for_release(GPtrArray *resources, int index,
646 mm_resource_manager_res_p resource)
648 switch (resource->state) {
649 case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
650 g_ptr_array_remove_index_fast(resources, index);
651 MM_RM_DEBUG("Resource %p is removed implicitly", resource);
653 case MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED:
654 resource->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE;
656 case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
657 MM_RM_DEBUG("Resource %p is already marked", resource);
664 static gboolean __check_rm_handle(mm_resource_manager_s *handle)
668 for (i = 0; i < handles->len; i++) {
669 if (g_ptr_array_index(handles, i) == handle)
675 static void __send_release_cb_sync(mm_resource_manager_id id)
679 sync_fd = open(RELEASE_CB_SYNC_PATH, O_WRONLY);
680 MM_RM_RETM_IF(sync_fd == -1, "Sync FIFO cannot be opened");
682 if (write(sync_fd, &id, sizeof(id)) == sizeof(id))
683 MM_RM_DEBUG("Sync message is sent successfully");
685 MM_RM_ERROR("Sync message cannot be sent");
690 static void __init_lib()
692 handles = g_ptr_array_sized_new(MM_RESOURCE_MANAGER_RESERVED_HANDLE_ARRAY_SIZE);
693 MM_RM_RETM_IF(handles == NULL, "API lib cannot be initialized");
695 MM_RM_INFO("API lib is loaded");
698 static void __deinit_lib()
700 if (handles->len > 0) {
701 MM_RM_DEBUG("Handles array [%d] is not empty. It will be cleaned now.", handles->len);
702 while (handles->len > 0)
703 _mm_resource_manager_destroy(handles->pdata[0]);
706 g_ptr_array_free(handles, TRUE);
708 MM_RM_INFO("API lib is unloaded");
711 static int __dbus_init(mm_resource_manager_s *handle)
713 GError *error = NULL;
715 MM_RM_RETVM_IF(handle->dbus_proxy != NULL,
716 MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
717 "Dbus proxy is not NULL");
719 g_main_context_push_thread_default(handle->dispatcher_context);
720 handle->dbus_proxy = mmresource_manager_proxy_new_for_bus_sync(
721 G_BUS_TYPE_SYSTEM, 0, RMD_GDBUS_NAME, RMD_GDBUS_PATH, NULL, &error);
722 g_main_context_pop_thread_default(handle->dispatcher_context);
723 MM_RM_RET_IF_GERR(error, "Dbus proxy cannot be created");
725 if (g_signal_connect(handle->dbus_proxy, "release_callback",
726 (GCallback)__dbus_release_callback, NULL) < 1 ||
727 g_signal_connect(handle->dbus_proxy, "status_callback",
728 (GCallback)__dbus_status_callback, NULL) < 1) {
730 g_object_unref(handle->dbus_proxy);
731 handle->dbus_proxy = NULL;
732 MM_RM_ERROR("Release or status callback signals cannot be connected");
734 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
737 return MM_RESOURCE_MANAGER_ERROR_NONE;
740 static int __dbus_deinit(mm_resource_manager_s *handle)
742 MM_RM_RETVM_IF(handle->dbus_proxy == NULL,
743 MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Dbus proxy is NULL");
744 g_object_unref(handle->dbus_proxy);
745 handle->dbus_proxy = NULL;
746 return MM_RESOURCE_MANAGER_ERROR_NONE;
749 static int __dbus_init_conf(mm_resource_manager_s *handle)
752 GError *error = NULL;
753 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
754 GVariant *max_volume = NULL;
755 GVariant *cond_volume = NULL;
756 GVariant *max_instance = NULL;
758 GVariantIter volume_iter;
759 GVariantIter cond_volume_iter;
761 mmresource_manager_call_conf_sync(handle->dbus_proxy, &rm_error, &max_volume,
762 &cond_volume, &max_instance, NULL, &error);
763 MM_RM_RET_IF_GERR(error, "DBus conf msg cannot be sent");
765 MM_RM_RETVM_IF(max_volume == NULL || cond_volume == NULL,
766 MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Variant data are empty");
768 if (g_variant_iter_init(&volume_iter, max_volume) == MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
769 for (i = 0; g_variant_iter_next(&volume_iter, "i", &handle->__max_resource_volumes[i]); i++) {
770 if (handle->__max_resource_volumes[i] == MM_RESOURCE_MANAGER_NO_RES)
771 MM_RM_INFO("Maybe occur the error operation related dbus");
773 g_variant_unref(max_volume);
776 MM_RM_ERROR("Wrong max volume array size");
780 if (g_variant_iter_init(&volume_iter, cond_volume) == MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
781 for (i = 0; (tmp = g_variant_iter_next_value(&volume_iter)) != NULL; i++) {
782 if (g_variant_iter_init(&cond_volume_iter, tmp) == MM_RESOURCE_MANAGER_RES_TYPE_COND_MAX) {
783 for (j = 0; g_variant_iter_next(&cond_volume_iter, "i", &handle->__condition_volumes[i][j]); j++);
784 g_variant_unref(tmp);
786 g_variant_unref(tmp);
787 MM_RM_ERROR("Wrong condition volume array size");
788 rm_error = MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
792 g_variant_unref(cond_volume);
795 MM_RM_ERROR("Wrong condition volume array size");
799 if (g_variant_iter_init(&volume_iter, max_instance) == MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
800 for (i = 0; g_variant_iter_next(&volume_iter, "i", &handle->__max_instance[i]); i++);
801 g_variant_unref(max_instance);
804 MM_RM_ERROR("Wrong max instance array size");
810 g_variant_unref(max_volume);
811 g_variant_unref(cond_volume);
812 g_variant_unref(max_instance);
813 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
816 static int __dbus_create(mm_resource_manager_s *handle, mm_resource_manager_app_class_e app_class)
818 GError *error = NULL;
819 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
821 mmresource_manager_call_create_sync(handle->dbus_proxy, app_class, &handle->id,
822 &rm_error, NULL, &error);
823 MM_RM_RET_IF_GERR(error, "DBus create msg cannot be sent");
825 MM_RM_DEBUG("Create returned id - #%"PRIu64", error - %d",
826 _mm_rm_hash64(handle->id), rm_error);
831 static int __dbus_destroy(mm_resource_manager_s *handle)
833 GError *error = NULL;
834 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
836 mmresource_manager_call_destroy_sync(handle->dbus_proxy, handle->id, &rm_error,
838 MM_RM_RET_IF_GERR(error, "DBus destroy msg cannot be sent");
840 MM_RM_DEBUG("Destroy for id - #%"PRIu64" returned error - %d", _mm_rm_hash64(handle->id), rm_error);
842 return MM_RESOURCE_MANAGER_ERROR_NONE;
845 static int __dbus_commit(mm_resource_manager_s *handle)
849 GVariantBuilder *release_builder;
850 GVariantBuilder *acquire_builder;
851 GVariant *flags_variant;
852 GVariantIter flags_iter;
853 mm_resource_manager_res_p resource;
857 GError *error = NULL;
858 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
860 release_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
861 acquire_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
863 for (i = 0; i < handle->resources->len; i++) {
864 resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
866 switch (resource->state) {
867 case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
868 g_variant_builder_add_value(acquire_builder, g_variant_new("(ii)",
869 resource->type, resource->volume));
872 case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
873 g_variant_builder_add_value(release_builder, g_variant_new("(ii)",
874 resource->type, resource->volume));
882 if (release_num + acquire_num == 0) {
883 g_variant_builder_unref(release_builder);
884 g_variant_builder_unref(acquire_builder);
885 MM_RM_DEBUG("There is nothing to commit - dbus request is not sent [%d %d]",
886 release_num, acquire_num);
891 * Acquire and release arrays are ended with special element, because
892 * g_variant_builder_end crashes without at least one element
894 g_variant_builder_add_value(acquire_builder, g_variant_new("(ii)",
895 MM_RESOURCE_MANAGER_NO_RES, 0));
896 acquire = g_variant_builder_end(acquire_builder);
897 g_variant_builder_unref(acquire_builder);
899 g_variant_builder_add_value(release_builder, g_variant_new("(ii)",
900 MM_RESOURCE_MANAGER_NO_RES, 0));
901 release = g_variant_builder_end(release_builder);
902 g_variant_builder_unref(release_builder);
904 mmresource_manager_call_commit_sync(handle->dbus_proxy, handle->id, release,
905 acquire, &rm_error, &flags_variant, NULL, &error);
907 MM_RM_RET_IF_GERR(error, "DBus commit msg cannot be sent");
909 MM_RM_DEBUG("Commit for id - #%"PRIu64" returned error - %d",
910 _mm_rm_hash64(handle->id), rm_error);
912 if (rm_error == MM_RESOURCE_MANAGER_ERROR_NONE) {
913 for (i = 0; i < handle->resources->len; i++) {
914 resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
916 switch (resource->state) {
917 case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
918 resource->state = MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED;
919 resource->is_acquire_failed = FALSE;
921 case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
922 g_ptr_array_remove_index_fast(handle->resources, i--);
928 } else if (rm_error == MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY) {
929 g_variant_iter_init(&flags_iter, flags_variant);
931 for (i = 0; i < handle->resources->len; i++) {
932 resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
934 if (resource->state == MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE)
935 g_variant_iter_next(&flags_iter, "b", &resource->is_acquire_failed);
939 g_variant_unref(flags_variant);
944 static void __dbus_release_callback(MMResourceManager *object, guint64 arg_id,
945 gint arg_resource_type, gint arg_volume)
947 mm_resource_manager_s *handle;
948 mm_resource_manager_id handle_id;
951 __mm_resource_handles_lock();
953 for (i = 0; i < handles->len; i++) {
954 handle = (mm_resource_manager_s*)handles->pdata[i];
955 handle_id = handle->id;
956 MM_RM_HASH64(handle_id);
958 if (handle->dbus_proxy == object && handle_id == arg_id) {
959 __mm_resource_manager_release_callback(handle, arg_id,
960 arg_resource_type, arg_volume);
965 __mm_resource_handles_unlock();
968 static void __dbus_status_callback(MMResourceManager *object, gint arg_status)
970 mm_resource_manager_s *handle;
973 MM_RM_INFO("status callback status %d", arg_status);
974 __mm_resource_handles_lock();
976 for (i = 0; i < handles->len; i++) {
977 handle = (mm_resource_manager_s*)handles->pdata[i];
978 if (handle->dbus_proxy == object) {
979 __mm_resource_manager_status_callback(handle, arg_status);
984 __mm_resource_handles_unlock();
987 static gpointer __dispatcher_thread(gpointer user_data)
989 GMainLoop *ml = (GMainLoop *) user_data;
993 MM_RM_INFO("main loop %p quit", ml);
999 static void __destroy_dispatcher(mm_resource_manager_s *handle)
1001 if (__dbus_deinit(handle) != MM_RESOURCE_MANAGER_ERROR_NONE)
1002 MM_RM_ERROR("Error while dbus deinitializing");
1004 if (handle->dispatcher_loop) {
1005 if (g_main_loop_is_running(handle->dispatcher_loop)) {
1006 MM_RM_INFO("mainloop %p is running", handle->dispatcher_loop);
1007 g_main_loop_quit(handle->dispatcher_loop);
1009 g_main_loop_unref(handle->dispatcher_loop);
1010 handle->dispatcher_loop = NULL;
1013 if (handle->dispatcher_thread) {
1014 g_thread_join(handle->dispatcher_thread);
1015 MM_RM_INFO("dispatcher thread join %p", handle->dispatcher_thread);
1016 handle->dispatcher_thread = NULL;
1019 if (handle->dispatcher_context) {
1020 g_main_context_unref(handle->dispatcher_context);
1021 handle->dispatcher_context = NULL;