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];
70 MMResourceManager *dbus_proxy;
72 GMainContext *dispatcher_context;
73 GMainLoop *dispatcher_loop;
74 GThread *dispatcher_thread;
75 } mm_resource_manager_s;
77 static void __init_lib() __attribute__((constructor));
78 static void __deinit_lib() __attribute__((destructor));
79 static int __check_resource(mm_resource_manager_s *rm,
80 mm_resource_manager_res_type_e type,
81 mm_resource_manager_res_volume volume);
82 static int __create_resource(mm_resource_manager_s *rm,
83 mm_resource_manager_res_type_e type,
84 mm_resource_manager_res_volume volume, mm_resource_manager_res_p *res);
85 static void __destroy_resource(void *res);
86 static int __get_resource_index(mm_resource_manager_s *rm,
87 mm_resource_manager_res_p res);
88 static gboolean __mark_resource_for_release(GPtrArray *resources, int index,
89 mm_resource_manager_res_p resource); /* FALSE if resource is destroyed */
90 static void __send_release_cb_sync(mm_resource_manager_id id);
91 static void __mm_resource_manager_release_callback(mm_resource_manager_s *handle,
92 mm_resource_manager_id id,
93 mm_resource_manager_res_type_e type,
94 mm_resource_manager_res_volume volume);
95 static void __mm_resource_manager_status_callback(mm_resource_manager_s *handle,
96 mm_resource_manager_status_e status);
97 static void __mm_resource_handles_lock(void);
98 static void __mm_resource_handles_unlock(void);
99 static void __mm_resources_lock(mm_resource_manager_s *h);
100 static void __mm_resources_unlock(mm_resource_manager_s *h);
103 static int __dbus_init(mm_resource_manager_s *handle);
104 static int __dbus_deinit(mm_resource_manager_s *handle);
105 static int __dbus_init_conf(mm_resource_manager_s *handle);
106 static gboolean __check_rm_handle(mm_resource_manager_s *handle);
107 static int __dbus_create(mm_resource_manager_s *handle,
108 mm_resource_manager_app_class_e app_class);
109 static int __dbus_destroy(mm_resource_manager_s *handle);
110 static int __dbus_commit(mm_resource_manager_s *handle);
111 static void __dbus_release_callback(MMResourceManager *object, guint64 arg_id,
112 gint arg_resource_type, gint arg_volume);
113 static void __dbus_status_callback(MMResourceManager *object, gint arg_status);
114 static gpointer __dispatcher_thread(gpointer user_data);
115 static void __destroy_dispatcher(mm_resource_manager_s *handle);
118 int _mm_resource_manager_create(mm_resource_manager_app_class_e app_class,
119 mm_resource_manager_release_cb cb, void *cb_data,
120 mm_resource_manager_h *rm)
122 mm_resource_manager_s *handle = *rm = NULL;
124 GError *error = NULL;
126 handle = (mm_resource_manager_s *) calloc(1, sizeof(mm_resource_manager_s));
127 MM_RM_RETVM_IF(NULL == handle, MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
128 "Error allocating memory for Handle");
130 handle->dispatcher_context = g_main_context_new();
131 if (!handle->dispatcher_context) {
133 MM_RM_ERROR("g_main_context_new failed");
134 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
136 MM_RM_INFO("new main context %p", handle->dispatcher_context);
138 handle->dispatcher_loop = g_main_loop_new(handle->dispatcher_context, FALSE);
139 if (!handle->dispatcher_loop) {
140 g_main_context_unref(handle->dispatcher_context);
142 MM_RM_ERROR("g_main_loop_new failed");
143 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
145 MM_RM_INFO("new main loop %p", handle->dispatcher_loop);
147 ret = __dbus_init(handle);
148 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
149 __destroy_dispatcher(handle);
151 MM_RM_ERROR("Error initializing dbus client");
155 handle->dispatcher_thread = g_thread_try_new("dispatcher_thread", __dispatcher_thread, handle->dispatcher_loop, &error);
156 if (!handle->dispatcher_thread) {
158 MM_RM_ERROR("dispatcher_thread creation failed : %s", error->message);
161 __destroy_dispatcher(handle);
163 return MM_RESOURCE_MANAGER_ERROR_NOT_ENOUGH;
165 MM_RM_INFO("new dispatcher thread %p", handle->dispatcher_thread);
167 ret = __dbus_init_conf(handle);
168 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
169 __destroy_dispatcher(handle);
171 MM_RM_ERROR("Configuration cannot be requested");
175 ret = __dbus_create(handle, app_class);
176 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
177 __destroy_dispatcher(handle);
179 MM_RM_ERROR("Dbus create request failed");
183 handle->release_cb.cb = cb;
184 handle->release_cb.user_data = cb_data;
186 handle->resources = g_ptr_array_new_full(
187 MM_RESOURCE_MANAGER_RESERVED_RES_ARRAY_SIZE, __destroy_resource);
189 g_mutex_init(&handle->resources_lock);
191 *rm = (mm_resource_manager_h *) handle;
192 __mm_resource_handles_lock();
193 g_ptr_array_add(handles, handle);
195 MM_RM_INFO("Resource manager #%"PRIu64" is created", _mm_rm_hash64(handle->id));
196 __mm_resource_handles_unlock();
198 return MM_RESOURCE_MANAGER_ERROR_NONE;
201 int _mm_resource_manager_destroy(mm_resource_manager_h rm)
203 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
204 mm_resource_manager_id id;
205 int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
207 __mm_resource_handles_lock();
208 MM_RESOURCE_MANAGER_CHECK(handle);
209 g_ptr_array_remove_fast(handles, handle);
210 __mm_resource_handles_unlock();
214 MM_RM_INFO("Resource manager #%"PRIu64" would be destroyed", _mm_rm_hash64(id));
216 __mm_resources_lock(handle);
217 ret = __dbus_destroy(handle);
218 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
219 MM_RM_ERROR("Dbus destroy request failed 0x%x", ret);
221 __destroy_dispatcher(handle);
223 g_ptr_array_free(handle->resources, TRUE);
224 __mm_resources_unlock(handle);
226 g_mutex_clear(&handle->resources_lock);
229 if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
230 MM_RM_INFO("Resource manager #%"PRIu64" is destroyed", _mm_rm_hash64(id));
235 int _mm_resource_manager_mark_for_acquire(
236 mm_resource_manager_h rm, mm_resource_manager_res_type_e type,
237 mm_resource_manager_res_volume volume,
238 mm_resource_manager_res_h *resource_h)
240 int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
241 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
242 mm_resource_manager_res_p resource;
244 __mm_resource_handles_lock();
245 MM_RESOURCE_MANAGER_CHECK(handle);
246 __mm_resources_lock(handle);
247 __mm_resource_handles_unlock();
249 ret = __create_resource(handle, type, volume, &resource);
250 MM_RM_UNLOCK_RETVM_IF(ret != MM_RESOURCE_MANAGER_ERROR_NONE,
251 handle->resources_lock, ret, "Resource cannot be created");
252 g_ptr_array_add(handle->resources, resource);
254 *resource_h = resource;
256 MM_RM_INFO("Resource %p of type %d with volume %d is marked for acquire in "
257 "resource manager #%"PRIu64, *resource_h, type, volume,
258 _mm_rm_hash64(handle->id));
259 __mm_resources_unlock(handle);
264 int _mm_resource_manager_resize_marked(mm_resource_manager_h rm,
265 mm_resource_manager_res_h resource_h,
266 mm_resource_manager_res_volume new_volume)
268 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
269 mm_resource_manager_res_p resource = (mm_resource_manager_res_p) resource_h;
270 mm_resource_manager_res_p tmp_resource;
271 mm_resource_manager_res_volume add_volume;
273 int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
275 __mm_resource_handles_lock();
276 MM_RESOURCE_MANAGER_CHECK(handle);
277 __mm_resources_lock(handle);
278 __mm_resource_handles_unlock();
280 i = __get_resource_index(handle, resource);
281 MM_RM_UNLOCK_RETVM_IF(i == MM_RESOURCE_MANAGER_RES_NOT_FOUND,
282 handle->resources_lock,
283 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
284 "Invalid resource handle");
285 if (new_volume == resource->volume) {
286 __mm_resources_unlock(handle);
287 MM_RM_DEBUG("New volume equals the old. Resize is not needed.");
291 add_volume = resource->volume != MM_RESOURCE_MANAGER_RES_VOLUME_FULL &&
292 new_volume != MM_RESOURCE_MANAGER_RES_VOLUME_FULL &&
293 resource->volume < new_volume ? (new_volume - resource->volume) : 0;
295 switch (resource->state) {
296 case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
297 if (add_volume > 0) {
298 ret = __check_resource(handle, resource->type, add_volume);
299 MM_RM_UNLOCK_RETVM_IF(ret != MM_RESOURCE_MANAGER_ERROR_NONE,
300 handle->resources_lock, ret, "Resource check failed");
302 resource->volume = new_volume;
305 case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
306 case MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED:
307 ret = __create_resource(handle, resource->type, add_volume, &tmp_resource);
308 MM_RM_UNLOCK_RETVM_IF(ret != MM_RESOURCE_MANAGER_ERROR_NONE,
309 handle->resources_lock, ret, "Resource cannot be created");
311 tmp_resource->volume = resource->volume;
312 tmp_resource->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE;
314 g_ptr_array_add(handle->resources, resource);
315 resource->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE;
316 resource->volume = new_volume;
318 handle->resources->pdata[i] = tmp_resource;
322 MM_RM_INFO("Resource %p is resized for acquire in resource manager #%"PRIu64,
323 resource_h, _mm_rm_hash64(handle->id));
324 __mm_resources_unlock(handle);
329 int _mm_resource_manager_mark_for_release(mm_resource_manager_h rm,
330 mm_resource_manager_res_h resource_h)
332 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
333 mm_resource_manager_res_p resource = (mm_resource_manager_res_p) resource_h;
336 __mm_resource_handles_lock();
337 MM_RESOURCE_MANAGER_CHECK(handle);
338 __mm_resources_lock(handle);
339 __mm_resource_handles_unlock();
341 i = __get_resource_index(handle, resource);
342 MM_RM_UNLOCK_RETVM_IF(i == MM_RESOURCE_MANAGER_RES_NOT_FOUND,
343 handle->resources_lock,
344 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
345 "Invalid resource handle");
347 __mark_resource_for_release(handle->resources, i, resource);
349 MM_RM_INFO("Resource %p is marked for release in resource manager #%"PRIu64,
350 resource_h, _mm_rm_hash64(handle->id));
351 __mm_resources_unlock(handle);
353 return MM_RESOURCE_MANAGER_ERROR_NONE;
356 int _mm_resource_manager_mark_all_for_release(mm_resource_manager_h rm)
358 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
361 __mm_resource_handles_lock();
362 MM_RESOURCE_MANAGER_CHECK(handle);
363 __mm_resources_lock(handle);
364 __mm_resource_handles_unlock();
366 for (i = 0; i < handle->resources->len; i++) {
367 if (!__mark_resource_for_release(handle->resources, i,
368 (mm_resource_manager_res_p) handle->resources->pdata[i]))
372 MM_RM_INFO("All resources are marked for release in resource manager #%"PRIu64,
373 _mm_rm_hash64(handle->id));
374 __mm_resources_unlock(handle);
376 return MM_RESOURCE_MANAGER_ERROR_NONE;
379 int _mm_resource_manager_get_resource_info(mm_resource_manager_h rm,
380 mm_resource_manager_res_h resource_h,
381 mm_resource_manager_res_info_s *info)
383 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
384 mm_resource_manager_res_p resource = (mm_resource_manager_res_p) resource_h;
387 __mm_resource_handles_lock();
388 MM_RESOURCE_MANAGER_CHECK(handle);
389 __mm_resources_lock(handle);
390 __mm_resource_handles_unlock();
392 i = __get_resource_index(handle, resource);
393 MM_RM_UNLOCK_RETVM_IF(i == MM_RESOURCE_MANAGER_RES_NOT_FOUND,
394 handle->resources_lock,
395 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
396 "Invalid resource handle");
398 info->type = resource->type;
399 info->volume = resource->volume;
400 info->is_acquire_failed = resource->is_acquire_failed;
402 MM_RM_INFO("Info structure of resource %p in resource manager #%"PRIu64" is filled",
403 resource_h, _mm_rm_hash64(handle->id));
404 __mm_resources_unlock(handle);
406 return MM_RESOURCE_MANAGER_ERROR_NONE;
409 int _mm_resource_manager_commit(mm_resource_manager_h rm)
411 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
414 __mm_resource_handles_lock();
415 MM_RESOURCE_MANAGER_CHECK(handle);
416 __mm_resources_lock(handle);
417 __mm_resource_handles_unlock();
419 ret = __dbus_commit(handle);
420 if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
421 MM_RM_INFO("Changes in resource manager #%"PRIu64" have been committed successfully",
422 _mm_rm_hash64(handle->id));
424 MM_RM_ERROR("Dbus commit request failed");
425 __mm_resources_unlock(handle);
430 int _mm_resource_manager_set_status_cb(mm_resource_manager_h rm,
431 mm_resource_manager_status_cb cb, void *user_data)
433 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
435 __mm_resource_handles_lock();
436 MM_RESOURCE_MANAGER_CHECK(handle);
437 __mm_resources_lock(handle);
438 __mm_resource_handles_unlock();
440 handle->status_cb.cb = cb;
441 handle->status_cb.user_data = user_data;
442 __mm_resources_unlock(handle);
444 MM_RM_INFO("Status callback %p in resource manager #%"PRIu64" is set", cb,
445 _mm_rm_hash64(handle->id));
447 return MM_RESOURCE_MANAGER_ERROR_NONE;
450 int _mm_resource_manager_get_res_type_max_volume(mm_resource_manager_h rm,
451 mm_resource_manager_res_type_e type,
452 mm_resource_manager_res_volume *max_volume)
454 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
456 if (handle->__max_resource_volumes[type] == MM_RESOURCE_MANAGER_NO_RES) {
457 MM_RM_DEBUG("No resource for the platform");
458 return MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED;
460 *max_volume = handle->__max_resource_volumes[type];
461 return MM_RESOURCE_MANAGER_ERROR_NONE;
465 int _mm_resource_manager_get_res_type_volume(mm_resource_manager_h rm,
466 mm_resource_manager_res_type_e type,
467 mm_resource_manager_res_type_cond_e condition,
468 mm_resource_manager_res_volume *volume)
470 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
472 if (handle->__condition_volumes[type][condition] == MM_RESOURCE_MANAGER_NO_RES) {
473 MM_RM_DEBUG("No pair (resource,condition) for the platform");
474 return MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED;
476 *volume = handle->__condition_volumes[type][condition];
477 return MM_RESOURCE_MANAGER_ERROR_NONE;
481 void __mm_resource_manager_release_callback(mm_resource_manager_s *handle,
482 mm_resource_manager_id id,
483 mm_resource_manager_res_type_e type,
484 mm_resource_manager_res_volume volume)
486 mm_resource_manager_res_s *resource;
487 mm_resource_manager_id handle_id;
488 gboolean release_all = FALSE;
491 MM_RM_DEBUG("Release callback is emitted for %s of volume %d in RM #%"PRIu64,
492 _mm_resource_manager_get_res_str(type), volume, id);
494 handle_id = handle->id;
495 MM_RM_HASH64(handle_id);
496 if (handle_id == id) {
497 __mm_resources_lock(handle);
498 __mm_resource_handles_unlock();
499 for (j = 0; j < handle->resources->len; j++) {
500 resource = (mm_resource_manager_res_s*)handle->resources->pdata[j];
501 if (resource->type == type && resource->volume == volume) {
503 release_all = ((mm_resource_manager_release_cb)
504 handle->release_cb.cb)(
505 handle, resource, handle->release_cb.user_data);
507 __send_release_cb_sync(handle->id);
509 g_ptr_array_remove_index_fast(handle->resources, j);
513 __mm_resources_unlock(handle);
516 if (_mm_resource_manager_mark_all_for_release(handle) == MM_RESOURCE_MANAGER_ERROR_NONE
517 && _mm_resource_manager_commit(handle) == MM_RESOURCE_MANAGER_ERROR_NONE) {
518 MM_RM_DEBUG("All resources are released after release cb");
520 MM_RM_ERROR("Resources cannot be released after release cb");
524 __mm_resource_handles_unlock();
528 void __mm_resource_manager_status_callback(mm_resource_manager_s *handle,
529 mm_resource_manager_status_e status)
531 __mm_resources_lock(handle);
532 __mm_resource_handles_unlock();
533 if (handle->status_cb.cb) {
534 ((mm_resource_manager_status_cb)handle->status_cb.cb)(handle, status,
535 handle->status_cb.user_data);
537 __mm_resources_unlock(handle);
540 static void __mm_resource_handles_lock(void)
542 MM_RM_INFO("handles lock");
543 g_mutex_lock(&handles_lock);
546 static void __mm_resource_handles_unlock(void)
548 g_mutex_unlock(&handles_lock);
549 MM_RM_INFO("handles unlocked");
552 static void __mm_resources_lock(mm_resource_manager_s *h)
554 MM_RM_RETM_IF(!h, "handle is NULL");
555 MM_RM_INFO("[handle %p]resources lock", h);
556 g_mutex_lock(&h->resources_lock);
559 static void __mm_resources_unlock(mm_resource_manager_s *h)
561 MM_RM_RETM_IF(!h, "handle is NULL");
562 g_mutex_unlock(&h->resources_lock);
563 MM_RM_INFO("[handle %p]resources unlocked", h);
566 static int __check_resource(mm_resource_manager_s *rm,
567 mm_resource_manager_res_type_e type,
568 mm_resource_manager_res_volume volume)
570 mm_resource_manager_res_volume remaining_local_volume =
571 rm->__max_resource_volumes[type];
572 mm_resource_manager_res_p i_res;
575 MM_RM_RETVM_IF(remaining_local_volume == MM_RESOURCE_MANAGER_NO_RES,
576 MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED,
577 "No resource for the platform");
580 MM_RM_RETVM_IF(remaining_local_volume < volume,
581 MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
582 "Requested volume %d exceeds max value %d", volume,
583 remaining_local_volume);
584 for (i = 0; i < rm->resources->len; i++) {
585 i_res = (mm_resource_manager_res_p) rm->resources->pdata[i];
586 if (i_res->type == type &&
587 i_res->state != MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE &&
588 (i_res->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL ||
589 (remaining_local_volume -= i_res->volume) < volume)) {
590 MM_RM_ERROR("Requested volume %d exceeds remaining local volume %d",
592 i_res->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL ?
593 0 : remaining_local_volume);
594 return MM_RESOURCE_MANAGER_ERROR_NOT_ENOUGH;
599 return MM_RESOURCE_MANAGER_ERROR_NONE;
602 static int __create_resource(mm_resource_manager_s *rm,
603 mm_resource_manager_res_type_e type,
604 mm_resource_manager_res_volume volume, mm_resource_manager_res_p *res)
608 MM_RM_RETVM_IF(res == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
610 ret = __check_resource(rm, type, volume);
611 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
614 *res = g_new0(mm_resource_manager_res_s, 1);
616 (*res)->volume = volume;
618 return MM_RESOURCE_MANAGER_ERROR_NONE;
621 static void __destroy_resource(void *res)
626 static int __get_resource_index(mm_resource_manager_s *rm,
627 mm_resource_manager_res_p res)
631 for (i = 0; i < rm->resources->len; i++)
632 if (rm->resources->pdata[i] == (gpointer) res)
635 return MM_RESOURCE_MANAGER_RES_NOT_FOUND;
638 static gboolean __mark_resource_for_release(GPtrArray *resources, int index,
639 mm_resource_manager_res_p resource)
641 switch (resource->state) {
642 case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
643 g_ptr_array_remove_index_fast(resources, index);
644 MM_RM_DEBUG("Resource %p is removed implicitly", resource);
646 case MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED:
647 resource->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE;
649 case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
650 MM_RM_DEBUG("Resource %p is already marked", resource);
657 static gboolean __check_rm_handle(mm_resource_manager_s *handle)
661 for (i = 0; i < handles->len; i++)
662 if (g_ptr_array_index(handles, i) == handle)
667 static void __send_release_cb_sync(mm_resource_manager_id id)
671 sync_fd = open(RELEASE_CB_SYNC_PATH, O_WRONLY);
672 MM_RM_RETM_IF(sync_fd == -1, "Sync FIFO cannot be opened");
674 if (write(sync_fd, &id, sizeof(id)) == sizeof(id))
675 MM_RM_DEBUG("Sync message is sent successfully");
677 MM_RM_ERROR("Sync message cannot be sent");
682 static void __init_lib()
684 handles = g_ptr_array_sized_new(
685 MM_RESOURCE_MANAGER_RESERVED_HANDLE_ARRAY_SIZE);
686 MM_RM_RETM_IF(handles == NULL, "API lib cannot be initialized");
688 MM_RM_INFO("API lib is loaded");
691 static void __deinit_lib()
693 if (handles->len > 0) {
694 MM_RM_DEBUG("Handles array [%d] is not empty. It will be cleaned now.", handles->len);
695 while (handles->len > 0)
696 _mm_resource_manager_destroy(handles->pdata[0]);
699 g_ptr_array_free(handles, TRUE);
701 MM_RM_INFO("API lib is unloaded");
704 static int __dbus_init(mm_resource_manager_s *handle)
706 GError *error = NULL;
708 MM_RM_RETVM_IF(handle->dbus_proxy != NULL,
709 MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
710 "Dbus proxy is not NULL");
712 g_main_context_push_thread_default(handle->dispatcher_context);
713 handle->dbus_proxy = mmresource_manager_proxy_new_for_bus_sync(
714 G_BUS_TYPE_SYSTEM, 0, RMD_GDBUS_NAME, RMD_GDBUS_PATH, NULL, &error);
715 g_main_context_pop_thread_default(handle->dispatcher_context);
716 MM_RM_RET_IF_GERR(error, "Dbus proxy cannot be created");
718 if (g_signal_connect(handle->dbus_proxy, "release_callback",
719 (GCallback)__dbus_release_callback, NULL) < 1 ||
720 g_signal_connect(handle->dbus_proxy, "status_callback",
721 (GCallback)__dbus_status_callback, NULL) < 1) {
723 g_object_unref(handle->dbus_proxy);
724 handle->dbus_proxy = NULL;
725 MM_RM_ERROR("Release or status callback signals cannot be connected");
727 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
730 return MM_RESOURCE_MANAGER_ERROR_NONE;
733 static int __dbus_deinit(mm_resource_manager_s *handle)
735 MM_RM_RETVM_IF(handle->dbus_proxy == NULL,
736 MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Dbus proxy is NULL");
737 g_object_unref(handle->dbus_proxy);
738 handle->dbus_proxy = NULL;
739 return MM_RESOURCE_MANAGER_ERROR_NONE;
742 static int __dbus_init_conf(mm_resource_manager_s *handle)
745 GError *error = NULL;
746 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
747 GVariant *max_volume = NULL;
748 GVariant *cond_volume = NULL;
750 GVariantIter volume_iter;
751 GVariantIter cond_volume_iter;
753 mmresource_manager_call_conf_sync(handle->dbus_proxy, &rm_error,
754 &max_volume, &cond_volume, NULL, &error);
755 MM_RM_RET_IF_GERR(error, "DBus conf msg cannot be sent");
757 MM_RM_RETVM_IF(max_volume == NULL || cond_volume == NULL,
758 MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
759 "Variant data are empty");
761 if (g_variant_iter_init(&volume_iter, max_volume) ==
762 MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
763 for (i = 0; g_variant_iter_next(&volume_iter, "i",
764 &handle->__max_resource_volumes[i]); i++);
765 g_variant_unref(max_volume);
767 g_variant_unref(max_volume);
768 g_variant_unref(cond_volume);
769 MM_RM_ERROR("Wrong max volume array size");
770 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
773 if (g_variant_iter_init(&volume_iter, cond_volume) ==
774 MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
775 for (i = 0; (tmp = g_variant_iter_next_value(&volume_iter)) != NULL;
777 if (g_variant_iter_init(&cond_volume_iter, tmp) ==
778 MM_RESOURCE_MANAGER_RES_TYPE_COND_MAX) {
779 for (j = 0; g_variant_iter_next(&cond_volume_iter, "i",
780 &handle->__condition_volumes[i][j]); j++);
781 g_variant_unref(tmp);
783 g_variant_unref(tmp);
784 MM_RM_ERROR("Wrong condition volume array size");
785 rm_error = MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
789 g_variant_unref(cond_volume);
791 g_variant_unref(cond_volume);
792 MM_RM_ERROR("Wrong condition volume array size");
793 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
799 static int __dbus_create(mm_resource_manager_s *handle,
800 mm_resource_manager_app_class_e app_class)
802 GError *error = NULL;
803 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
805 mmresource_manager_call_create_sync(handle->dbus_proxy, app_class, &handle->id,
806 &rm_error, NULL, &error);
807 MM_RM_RET_IF_GERR(error, "DBus create msg cannot be sent");
809 MM_RM_DEBUG("Create returned id - #%"PRIu64", error - %d",
810 _mm_rm_hash64(handle->id), rm_error);
815 static int __dbus_destroy(mm_resource_manager_s *handle)
817 GError *error = NULL;
818 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
820 mmresource_manager_call_destroy_sync(handle->dbus_proxy, handle->id, &rm_error,
822 MM_RM_RET_IF_GERR(error, "DBus destroy msg cannot be sent");
824 MM_RM_DEBUG("Destroy for id - #%"PRIu64" returned error - %d", _mm_rm_hash64(handle->id), rm_error);
826 return MM_RESOURCE_MANAGER_ERROR_NONE;
829 static int __dbus_commit(mm_resource_manager_s *handle)
833 GVariantBuilder *release_builder;
834 GVariantBuilder *acquire_builder;
835 GVariant *flags_variant;
836 GVariantIter flags_iter;
837 mm_resource_manager_res_p resource;
841 GError *error = NULL;
842 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
844 release_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
845 acquire_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
846 for (i = 0; i < handle->resources->len; i++) {
847 resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
849 switch (resource->state) {
850 case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
851 g_variant_builder_add_value(acquire_builder, g_variant_new("(ii)",
852 resource->type, resource->volume));
855 case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
856 g_variant_builder_add_value(release_builder, g_variant_new("(ii)",
857 resource->type, resource->volume));
865 if (release_num + acquire_num == 0) {
866 g_variant_builder_unref(release_builder);
867 g_variant_builder_unref(acquire_builder);
868 MM_RM_DEBUG("There is nothing to commit - dbus request is not sent");
873 * Acquire and release arrays are ended with special element, because
874 * g_variant_builder_end crashes without at least one element
876 g_variant_builder_add_value(acquire_builder, g_variant_new("(ii)",
877 MM_RESOURCE_MANAGER_NO_RES, 0));
878 acquire = g_variant_builder_end(acquire_builder);
879 g_variant_builder_unref(acquire_builder);
881 g_variant_builder_add_value(release_builder, g_variant_new("(ii)",
882 MM_RESOURCE_MANAGER_NO_RES, 0));
883 release = g_variant_builder_end(release_builder);
884 g_variant_builder_unref(release_builder);
886 mmresource_manager_call_commit_sync(handle->dbus_proxy, handle->id, release,
887 acquire, &rm_error, &flags_variant, NULL, &error);
889 MM_RM_RET_IF_GERR(error, "DBus commit msg cannot be sent");
891 MM_RM_DEBUG("Commit for id - #%"PRIu64" returned error - %d",
892 _mm_rm_hash64(handle->id), rm_error);
894 if (rm_error == MM_RESOURCE_MANAGER_ERROR_NONE) {
895 for (i = 0; i < handle->resources->len; i++) {
896 resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
898 switch (resource->state) {
899 case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
900 resource->state = MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED;
901 resource->is_acquire_failed = FALSE;
903 case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
904 g_ptr_array_remove_index_fast(handle->resources, i--);
910 } else if (rm_error == MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY) {
911 g_variant_iter_init(&flags_iter, flags_variant);
913 for (i = 0; i < handle->resources->len; i++) {
914 resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
916 if (resource->state == MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE)
917 g_variant_iter_next(&flags_iter, "b", &resource->is_acquire_failed);
921 g_variant_unref(flags_variant);
926 static void __dbus_release_callback(MMResourceManager *object, guint64 arg_id,
927 gint arg_resource_type, gint arg_volume)
929 mm_resource_manager_s *handle;
930 gboolean unlock = TRUE;
933 __mm_resource_handles_lock();
934 for (i = 0; i < handles->len; i++) {
935 handle = (mm_resource_manager_s*)handles->pdata[i];
936 if (handle->dbus_proxy == object) {
937 __mm_resource_manager_release_callback(handle, arg_id,
938 arg_resource_type, arg_volume);
945 __mm_resource_handles_unlock();
948 static void __dbus_status_callback(MMResourceManager *object, gint arg_status)
950 mm_resource_manager_s *handle;
951 gboolean unlock = TRUE;
954 __mm_resource_handles_lock();
955 for (i = 0; i < handles->len; i++) {
956 handle = (mm_resource_manager_s*)handles->pdata[i];
957 if (handle->dbus_proxy == object) {
958 __mm_resource_manager_status_callback(handle, arg_status);
965 __mm_resource_handles_unlock();
968 static gpointer __dispatcher_thread(gpointer user_data)
970 GMainLoop *ml = (GMainLoop *) user_data;
974 MM_RM_INFO("main loop %p quit", ml);
980 static void __destroy_dispatcher(mm_resource_manager_s *handle)
982 if (__dbus_deinit(handle) != MM_RESOURCE_MANAGER_ERROR_NONE)
983 MM_RM_ERROR("Error while dbus deinitializing");
985 if (handle->dispatcher_loop) {
986 if (g_main_loop_is_running(handle->dispatcher_loop)) {
987 MM_RM_INFO("mainloop %p is running", handle->dispatcher_loop);
988 g_main_loop_quit(handle->dispatcher_loop);
990 g_main_loop_unref(handle->dispatcher_loop);
991 handle->dispatcher_loop = NULL;
994 if (handle->dispatcher_thread) {
995 g_thread_join(handle->dispatcher_thread);
996 MM_RM_INFO("dispatcher thread join %p", handle->dispatcher_thread);
997 handle->dispatcher_thread = NULL;
1000 if (handle->dispatcher_context) {
1001 g_main_context_unref(handle->dispatcher_context);
1002 handle->dispatcher_context = NULL;