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 16 /* preallocated size */
30 #define MM_RESOURCE_MANAGER_RESERVED_HANDLE_ARRAY_SIZE 8 /* preallocated size */
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(void) __attribute__((constructor));
79 static void __deinit_lib(void) __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 if (local_volume == MM_RESOURCE_MANAGER_NO_RES)
587 MM_RM_ERROR("[#%"PRIu64" type : %d volume : %d] resource (#%d) for the platform",
588 _mm_rm_hash64(rm->id), type, volume, local_volume);
591 for (i = 0; i < rm->resources->len; i++) {
592 i_res = (mm_resource_manager_res_p) rm->resources->pdata[i];
593 if (i_res->type == type && i_res->state != MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE
594 && (i_res->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL
595 || (local_volume -= i_res->volume) < volume)) {
596 MM_RM_ERROR("Requested volume %d exceeds remaining local volume %d",
597 volume, i_res->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL ?
599 return MM_RESOURCE_MANAGER_ERROR_NOT_ENOUGH;
604 return MM_RESOURCE_MANAGER_ERROR_NONE;
607 static int __create_resource(mm_resource_manager_s *rm,
608 mm_resource_manager_res_type_e type,
609 mm_resource_manager_res_volume volume, mm_resource_manager_res_p *res)
613 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
615 MM_RM_RETVM_IF(handle == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
616 "NULL handle pointer");
617 MM_RM_RETVM_IF(res == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "NULL pointer");
618 ret = __check_resource(rm, type, volume);
619 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
622 *res = g_new0(mm_resource_manager_res_s, 1);
624 (*res)->volume = volume;
626 return MM_RESOURCE_MANAGER_ERROR_NONE;
629 static void __destroy_resource(void *res)
634 static int __get_resource_index(mm_resource_manager_s *rm, mm_resource_manager_res_p res)
638 for (i = 0; i < rm->resources->len; i++) {
639 if (rm->resources->pdata[i] == (gpointer) res)
643 return MM_RESOURCE_MANAGER_RES_NOT_FOUND;
646 static gboolean __mark_resource_for_release(GPtrArray *resources, int index,
647 mm_resource_manager_res_p resource)
649 switch (resource->state) {
650 case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
651 g_ptr_array_remove_index_fast(resources, index);
652 MM_RM_DEBUG("Resource %p is removed implicitly", resource);
654 case MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED:
655 resource->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE;
657 case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
658 MM_RM_DEBUG("Resource %p is already marked", resource);
665 static gboolean __check_rm_handle(mm_resource_manager_s *handle)
669 for (i = 0; i < handles->len; i++) {
670 if (g_ptr_array_index(handles, i) == handle)
676 static void __send_release_cb_sync(mm_resource_manager_id id)
680 sync_fd = open(RELEASE_CB_SYNC_PATH, O_WRONLY);
681 MM_RM_RETM_IF(sync_fd == -1, "Sync FIFO cannot be opened");
683 if (write(sync_fd, &id, sizeof(id)) == sizeof(id))
684 MM_RM_DEBUG("Sync message is sent successfully");
686 MM_RM_ERROR("Sync message cannot be sent");
691 static void __init_lib(void)
693 handles = g_ptr_array_sized_new(MM_RESOURCE_MANAGER_RESERVED_HANDLE_ARRAY_SIZE);
694 MM_RM_RETM_IF(handles == NULL, "API lib cannot be initialized");
696 MM_RM_INFO("API lib is loaded [%d] Set signal handler", _mm_resource_manager_set_signal_handlers());
699 static void __deinit_lib(void)
701 if (handles->len > 0) {
702 MM_RM_DEBUG("Handles array [%d] is not empty. It will be cleaned now.", handles->len);
703 while (handles->len > 0)
704 _mm_resource_manager_destroy(handles->pdata[0]);
707 g_ptr_array_free(handles, TRUE);
709 MM_RM_INFO("API lib is unloaded");
712 static int __dbus_init(mm_resource_manager_s *handle)
714 GError *error = NULL;
716 MM_RM_RETVM_IF(handle->dbus_proxy != NULL,
717 MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
718 "Dbus proxy is not NULL");
720 g_main_context_push_thread_default(handle->dispatcher_context);
721 handle->dbus_proxy = mmresource_manager_proxy_new_for_bus_sync(
722 G_BUS_TYPE_SYSTEM, 0, RMD_GDBUS_NAME, RMD_GDBUS_PATH, NULL, &error);
723 g_main_context_pop_thread_default(handle->dispatcher_context);
724 MM_RM_RET_IF_GERR(error, "Dbus proxy cannot be created");
726 if (g_signal_connect(handle->dbus_proxy, "release_callback",
727 (GCallback)__dbus_release_callback, NULL) < 1 ||
728 g_signal_connect(handle->dbus_proxy, "status_callback",
729 (GCallback)__dbus_status_callback, NULL) < 1) {
731 g_object_unref(handle->dbus_proxy);
732 handle->dbus_proxy = NULL;
733 MM_RM_ERROR("Release or status callback signals cannot be connected");
735 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
738 return MM_RESOURCE_MANAGER_ERROR_NONE;
741 static int __dbus_deinit(mm_resource_manager_s *handle)
743 MM_RM_RETVM_IF(handle->dbus_proxy == NULL,
744 MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Dbus proxy is NULL");
745 g_object_unref(handle->dbus_proxy);
746 handle->dbus_proxy = NULL;
747 return MM_RESOURCE_MANAGER_ERROR_NONE;
750 static int __dbus_init_conf(mm_resource_manager_s *handle)
753 GError *error = NULL;
754 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
755 GVariant *max_volume = NULL;
756 GVariant *cond_volume = NULL;
757 GVariant *max_instance = NULL;
759 GVariantIter volume_iter;
760 GVariantIter cond_volume_iter;
762 mmresource_manager_call_conf_sync(handle->dbus_proxy, &rm_error, &max_volume,
763 &cond_volume, &max_instance, NULL, &error);
764 MM_RM_RET_IF_GERR(error, "DBus conf msg cannot be sent");
766 MM_RM_RETVM_IF(max_volume == NULL || cond_volume == NULL,
767 MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Variant data are empty");
769 if (g_variant_iter_init(&volume_iter, max_volume) == MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
770 for (i = 0; g_variant_iter_next(&volume_iter, "i", &handle->__max_resource_volumes[i]); i++);
771 g_variant_unref(max_volume);
774 MM_RM_ERROR("Wrong max volume array size");
778 if (g_variant_iter_init(&volume_iter, cond_volume) == MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
779 for (i = 0; (tmp = g_variant_iter_next_value(&volume_iter)) != NULL; i++) {
780 if (g_variant_iter_init(&cond_volume_iter, tmp) == MM_RESOURCE_MANAGER_RES_TYPE_COND_MAX) {
781 for (j = 0; g_variant_iter_next(&cond_volume_iter, "i", &handle->__condition_volumes[i][j]); j++);
782 g_variant_unref(tmp);
784 g_variant_unref(tmp);
785 MM_RM_ERROR("Wrong condition volume array size");
786 rm_error = MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
790 g_variant_unref(cond_volume);
793 MM_RM_ERROR("Wrong condition volume array size");
797 if (g_variant_iter_init(&volume_iter, max_instance) == MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
798 for (i = 0; g_variant_iter_next(&volume_iter, "i", &handle->__max_instance[i]); i++);
799 g_variant_unref(max_instance);
802 MM_RM_ERROR("Wrong max instance array size");
808 g_variant_unref(max_volume);
809 g_variant_unref(cond_volume);
810 g_variant_unref(max_instance);
811 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
814 static int __dbus_create(mm_resource_manager_s *handle, mm_resource_manager_app_class_e app_class)
816 GError *error = NULL;
817 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
819 mmresource_manager_call_create_sync(handle->dbus_proxy, app_class, &handle->id,
820 &rm_error, NULL, &error);
821 MM_RM_RET_IF_GERR(error, "DBus create msg cannot be sent");
823 MM_RM_DEBUG("Create returned id - #%"PRIu64", error - %d",
824 _mm_rm_hash64(handle->id), rm_error);
829 static int __dbus_destroy(mm_resource_manager_s *handle)
831 GError *error = NULL;
832 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
834 mmresource_manager_call_destroy_sync(handle->dbus_proxy, handle->id, &rm_error,
836 MM_RM_RET_IF_GERR(error, "DBus destroy msg cannot be sent");
838 MM_RM_DEBUG("Destroy for id - #%"PRIu64" returned error - %d", _mm_rm_hash64(handle->id), rm_error);
840 return MM_RESOURCE_MANAGER_ERROR_NONE;
843 static int __dbus_commit(mm_resource_manager_s *handle)
847 GVariantBuilder *release_builder;
848 GVariantBuilder *acquire_builder;
849 GVariant *flags_variant;
850 GVariantIter flags_iter;
851 mm_resource_manager_res_p resource;
855 GError *error = NULL;
856 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
858 release_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
859 acquire_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
861 for (i = 0; i < handle->resources->len; i++) {
862 resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
864 switch (resource->state) {
865 case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
866 g_variant_builder_add_value(acquire_builder, g_variant_new("(ii)",
867 resource->type, resource->volume));
870 case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
871 g_variant_builder_add_value(release_builder, g_variant_new("(ii)",
872 resource->type, resource->volume));
880 if (release_num + acquire_num == 0) {
881 g_variant_builder_unref(release_builder);
882 g_variant_builder_unref(acquire_builder);
883 MM_RM_DEBUG("There is nothing to commit - dbus request is not sent [%d %d]",
884 release_num, acquire_num);
889 * Acquire and release arrays are ended with special element, because
890 * g_variant_builder_end crashes without at least one element
892 g_variant_builder_add_value(acquire_builder, g_variant_new("(ii)",
893 MM_RESOURCE_MANAGER_NO_RES, 0));
894 acquire = g_variant_builder_end(acquire_builder);
895 g_variant_builder_unref(acquire_builder);
897 g_variant_builder_add_value(release_builder, g_variant_new("(ii)",
898 MM_RESOURCE_MANAGER_NO_RES, 0));
899 release = g_variant_builder_end(release_builder);
900 g_variant_builder_unref(release_builder);
902 mmresource_manager_call_commit_sync(handle->dbus_proxy, handle->id, release,
903 acquire, &rm_error, &flags_variant, NULL, &error);
905 MM_RM_RET_IF_GERR(error, "DBus commit msg cannot be sent");
907 MM_RM_DEBUG("Commit for id - #%"PRIu64" returned error - %d",
908 _mm_rm_hash64(handle->id), rm_error);
910 if (rm_error == MM_RESOURCE_MANAGER_ERROR_NONE) {
911 for (i = 0; i < handle->resources->len; i++) {
912 resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
914 switch (resource->state) {
915 case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
916 resource->state = MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED;
917 resource->is_acquire_failed = FALSE;
919 case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
920 g_ptr_array_remove_index_fast(handle->resources, i--);
926 } else if (rm_error == MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY) {
927 g_variant_iter_init(&flags_iter, flags_variant);
929 for (i = 0; i < handle->resources->len; i++) {
930 resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
932 if (resource->state == MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE)
933 g_variant_iter_next(&flags_iter, "b", &resource->is_acquire_failed);
937 g_variant_unref(flags_variant);
942 static void __dbus_release_callback(MMResourceManager *object, guint64 arg_id,
943 gint arg_resource_type, gint arg_volume)
945 mm_resource_manager_s *handle;
946 mm_resource_manager_id handle_id;
947 gboolean unlock = TRUE;
950 __mm_resource_handles_lock();
952 for (i = 0; i < handles->len; i++) {
953 handle = (mm_resource_manager_s*)handles->pdata[i];
954 handle_id = handle->id;
955 MM_RM_HASH64(handle_id);
956 if (handle->dbus_proxy == object && handle_id == arg_id) {
957 __mm_resource_manager_release_callback(handle, arg_id,
958 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;
971 gboolean unlock = TRUE;
974 MM_RM_INFO("status callback status %d", arg_status);
975 __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);
986 __mm_resource_handles_unlock();
989 static gpointer __dispatcher_thread(gpointer user_data)
991 GMainLoop *ml = (GMainLoop *) user_data;
995 MM_RM_INFO("main loop %p quit", ml);
1001 static void __destroy_dispatcher(mm_resource_manager_s *handle)
1003 if (__dbus_deinit(handle) != MM_RESOURCE_MANAGER_ERROR_NONE)
1004 MM_RM_ERROR("Error while dbus deinitializing");
1006 if (handle->dispatcher_loop) {
1007 if (g_main_loop_is_running(handle->dispatcher_loop)) {
1008 MM_RM_INFO("mainloop %p is running", handle->dispatcher_loop);
1009 g_main_loop_quit(handle->dispatcher_loop);
1011 g_main_loop_unref(handle->dispatcher_loop);
1012 handle->dispatcher_loop = NULL;
1015 if (handle->dispatcher_thread) {
1016 g_thread_join(handle->dispatcher_thread);
1017 MM_RM_INFO("dispatcher thread join %p", handle->dispatcher_thread);
1018 handle->dispatcher_thread = NULL;
1021 if (handle->dispatcher_context) {
1022 g_main_context_unref(handle->dispatcher_context);
1023 handle->dispatcher_context = NULL;