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.
24 #include "common/mm_resource_manager_utils.h"
25 #include "lib/mm_resource_manager_priv.h"
26 #include "common/mm_resource_manager_dbus.h"
28 static GMutex handles_lock;
29 static GPtrArray *handles;
31 #define MM_RESOURCE_MANAGER(x) ((mm_resource_manager_s *) (x))
32 #define MM_RESOURCE_MANAGER_CHECK(x) \
33 MM_RM_UNLOCK_RETVM_IF(!__check_rm_handle(x), handles_lock, \
34 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, \
35 "Invalid resource manager handle %p", x)
36 #define MM_RESOURCE_MANAGER_RESERVED_RES_ARRAY_SIZE 16 /* preallocated size */
37 #define MM_RESOURCE_MANAGER_RESERVED_HANDLE_ARRAY_SIZE 8 /* preallocated size */
38 #define MM_RESOURCE_MANAGER_RES_NOT_FOUND -1
43 MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE, /* uncommitted */
44 MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED, /* committed */
45 MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE /* uncommitted */
46 } mm_resource_manager_res_state_e;
51 } mm_resource_manager_cb_s;
54 mm_resource_manager_res_type_e type;
55 mm_resource_manager_res_volume volume;
56 mm_resource_manager_res_state_e state;
57 gboolean is_acquire_failed;
58 } mm_resource_manager_res_s;
59 typedef mm_resource_manager_res_s *mm_resource_manager_res_p;
62 mm_resource_manager_id id;
66 mm_resource_manager_cb_s release_cb;
67 mm_resource_manager_cb_s status_cb;
69 GMutex resources_lock;
71 mm_resource_manager_res_volume __max_resource_volumes
72 [MM_RESOURCE_MANAGER_RES_TYPE_MAX];
73 mm_resource_manager_res_volume __condition_volumes
74 [MM_RESOURCE_MANAGER_RES_TYPE_MAX]
75 [MM_RESOURCE_MANAGER_RES_TYPE_COND_MAX];
77 MMResourceManager *dbus_proxy;
79 GMainContext *dispatcher_context;
80 GMainLoop *dispatcher_loop;
81 GThread *dispatcher_thread;
82 } mm_resource_manager_s;
84 static void __init_lib() __attribute__((constructor));
85 static void __deinit_lib() __attribute__((destructor));
86 static int __check_resource(mm_resource_manager_s *rm,
87 mm_resource_manager_res_type_e type,
88 mm_resource_manager_res_volume volume);
89 static int __create_resource(mm_resource_manager_s *rm,
90 mm_resource_manager_res_type_e type,
91 mm_resource_manager_res_volume volume, mm_resource_manager_res_p *res);
92 static void __destroy_resource(void *res);
93 static int __get_resource_index(mm_resource_manager_s *rm,
94 mm_resource_manager_res_p res);
95 static gboolean __mark_resource_for_release(GPtrArray *resources, int index,
96 mm_resource_manager_res_p resource); /* FALSE if resource is destroyed */
97 static void __send_release_cb_sync(mm_resource_manager_id id);
98 static void __mm_resource_manager_release_callback(mm_resource_manager_s *handle,
99 mm_resource_manager_id id,
100 mm_resource_manager_res_type_e type,
101 mm_resource_manager_res_volume volume);
102 static void __mm_resource_manager_status_callback(mm_resource_manager_s *handle,
103 mm_resource_manager_status_e status);
104 static void __mm_resource_handles_lock(void);
105 static void __mm_resource_handles_unlock(void);
106 static void __mm_resources_lock(mm_resource_manager_s *h);
107 static void __mm_resources_unlock(mm_resource_manager_s *h);
110 static int __dbus_init(mm_resource_manager_s *handle);
111 static int __dbus_deinit(mm_resource_manager_s *handle);
112 static int __dbus_init_conf(mm_resource_manager_s *handle);
113 static gboolean __check_rm_handle(mm_resource_manager_s *handle);
114 static int __dbus_create(mm_resource_manager_s *handle,
115 mm_resource_manager_app_class_e app_class);
116 static int __dbus_destroy(mm_resource_manager_s *handle);
117 static int __dbus_commit(mm_resource_manager_s *handle);
118 static void __dbus_release_callback(MMResourceManager *object, guint64 arg_id,
119 gint arg_resource_type, gint arg_volume);
120 static void __dbus_status_callback(MMResourceManager *object, gint arg_status);
121 static gpointer __dispatcher_thread(gpointer user_data);
122 static void __destroy_dispatcher(mm_resource_manager_s *handle);
125 int _mm_resource_manager_create(mm_resource_manager_app_class_e app_class,
126 mm_resource_manager_release_cb cb, void *cb_data,
127 mm_resource_manager_h *rm)
129 mm_resource_manager_s *handle = *rm = NULL;
131 GError *error = NULL;
133 handle = (mm_resource_manager_s *) calloc(1, sizeof(mm_resource_manager_s));
134 MM_RM_RETVM_IF(NULL == handle, MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
135 "Error allocating memory for Handle");
137 handle->dispatcher_context = g_main_context_new();
138 if (!handle->dispatcher_context) {
140 MM_RM_ERROR("g_main_context_new failed");
141 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
143 MM_RM_INFO("new main context %p", handle->dispatcher_context);
145 handle->dispatcher_loop = g_main_loop_new(handle->dispatcher_context, FALSE);
146 if (!handle->dispatcher_loop) {
147 g_main_context_unref(handle->dispatcher_context);
149 MM_RM_ERROR("g_main_loop_new failed");
150 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
152 MM_RM_INFO("new main loop %p", handle->dispatcher_loop);
154 ret = __dbus_init(handle);
155 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
156 __destroy_dispatcher(handle);
158 MM_RM_ERROR("Error initializing dbus client");
162 handle->dispatcher_thread = g_thread_try_new("dispatcher_thread", __dispatcher_thread, handle->dispatcher_loop, &error);
163 if (!handle->dispatcher_thread) {
165 MM_RM_ERROR("dispatcher_thread creation failed : %s", error->message);
168 __destroy_dispatcher(handle);
170 return MM_RESOURCE_MANAGER_ERROR_NOT_ENOUGH;
172 MM_RM_INFO("new dispatcher thread %p", handle->dispatcher_thread);
174 ret = __dbus_init_conf(handle);
175 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
176 __destroy_dispatcher(handle);
178 MM_RM_ERROR("Configuration cannot be requested");
182 ret = __dbus_create(handle, app_class);
183 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
184 __destroy_dispatcher(handle);
186 MM_RM_ERROR("Dbus create request failed");
190 handle->release_cb.cb = cb;
191 handle->release_cb.user_data = cb_data;
193 handle->resources = g_ptr_array_new_full(
194 MM_RESOURCE_MANAGER_RESERVED_RES_ARRAY_SIZE, __destroy_resource);
196 g_mutex_init(&handle->resources_lock);
198 *rm = (mm_resource_manager_h *) handle;
199 __mm_resource_handles_lock();
200 g_ptr_array_add(handles, handle);
202 MM_RM_INFO("Resource manager #%"PRIu64" is created", _mm_rm_hash64(handle->id));
203 __mm_resource_handles_unlock();
205 return MM_RESOURCE_MANAGER_ERROR_NONE;
208 int _mm_resource_manager_destroy(mm_resource_manager_h rm)
210 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
211 mm_resource_manager_id id;
212 int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
214 __mm_resource_handles_lock();
215 MM_RESOURCE_MANAGER_CHECK(handle);
216 g_ptr_array_remove_fast(handles, handle);
217 __mm_resource_handles_unlock();
221 MM_RM_INFO("Resource manager #%"PRIu64" would be destroyed", _mm_rm_hash64(id));
223 __mm_resources_lock(handle);
224 ret = __dbus_destroy(handle);
225 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
226 MM_RM_ERROR("Dbus destroy request failed 0x%x", ret);
228 __destroy_dispatcher(handle);
230 g_ptr_array_free(handle->resources, TRUE);
231 __mm_resources_unlock(handle);
233 g_mutex_clear(&handle->resources_lock);
236 if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
237 MM_RM_INFO("Resource manager #%"PRIu64" is destroyed", _mm_rm_hash64(id));
242 int _mm_resource_manager_mark_for_acquire(
243 mm_resource_manager_h rm, mm_resource_manager_res_type_e type,
244 mm_resource_manager_res_volume volume,
245 mm_resource_manager_res_h *resource_h)
247 int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
248 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
249 mm_resource_manager_res_p resource;
251 __mm_resource_handles_lock();
252 MM_RESOURCE_MANAGER_CHECK(handle);
253 __mm_resources_lock(handle);
254 __mm_resource_handles_unlock();
256 ret = __create_resource(handle, type, volume, &resource);
257 MM_RM_UNLOCK_RETVM_IF(ret != MM_RESOURCE_MANAGER_ERROR_NONE,
258 handle->resources_lock, ret, "Resource cannot be created");
259 g_ptr_array_add(handle->resources, resource);
261 *resource_h = resource;
263 MM_RM_INFO("Resource %p of type %d with volume %d is marked for acquire in "
264 "resource manager #%"PRIu64, *resource_h, type, volume,
265 _mm_rm_hash64(handle->id));
266 __mm_resources_unlock(handle);
271 int _mm_resource_manager_resize_marked(mm_resource_manager_h rm,
272 mm_resource_manager_res_h resource_h,
273 mm_resource_manager_res_volume new_volume)
275 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
276 mm_resource_manager_res_p resource = (mm_resource_manager_res_p) resource_h;
277 mm_resource_manager_res_p tmp_resource;
278 mm_resource_manager_res_volume add_volume;
280 int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
282 __mm_resource_handles_lock();
283 MM_RESOURCE_MANAGER_CHECK(handle);
284 __mm_resources_lock(handle);
285 __mm_resource_handles_unlock();
287 i = __get_resource_index(handle, resource);
288 MM_RM_UNLOCK_RETVM_IF(i == MM_RESOURCE_MANAGER_RES_NOT_FOUND,
289 handle->resources_lock,
290 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
291 "Invalid resource handle");
292 if (new_volume == resource->volume) {
293 __mm_resources_unlock(handle);
294 MM_RM_DEBUG("New volume equals the old. Resize is not needed.");
298 add_volume = resource->volume != MM_RESOURCE_MANAGER_RES_VOLUME_FULL &&
299 new_volume != MM_RESOURCE_MANAGER_RES_VOLUME_FULL &&
300 resource->volume < new_volume ? (new_volume - resource->volume) : 0;
302 switch (resource->state) {
303 case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
304 if (add_volume > 0) {
305 ret = __check_resource(handle, resource->type, add_volume);
306 MM_RM_UNLOCK_RETVM_IF(ret != MM_RESOURCE_MANAGER_ERROR_NONE,
307 handle->resources_lock, ret, "Resource check failed");
309 resource->volume = new_volume;
312 case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
313 case MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED:
314 ret = __create_resource(handle, resource->type, add_volume, &tmp_resource);
315 MM_RM_UNLOCK_RETVM_IF(ret != MM_RESOURCE_MANAGER_ERROR_NONE,
316 handle->resources_lock, ret, "Resource cannot be created");
318 tmp_resource->volume = resource->volume;
319 tmp_resource->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE;
321 g_ptr_array_add(handle->resources, resource);
322 resource->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE;
323 resource->volume = new_volume;
325 handle->resources->pdata[i] = tmp_resource;
329 MM_RM_INFO("Resource %p is resized for acquire in resource manager #%"PRIu64,
330 resource_h, _mm_rm_hash64(handle->id));
331 __mm_resources_unlock(handle);
336 int _mm_resource_manager_mark_for_release(mm_resource_manager_h rm,
337 mm_resource_manager_res_h resource_h)
339 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
340 mm_resource_manager_res_p resource = (mm_resource_manager_res_p) resource_h;
343 __mm_resource_handles_lock();
344 MM_RESOURCE_MANAGER_CHECK(handle);
345 __mm_resources_lock(handle);
346 __mm_resource_handles_unlock();
348 i = __get_resource_index(handle, resource);
349 MM_RM_UNLOCK_RETVM_IF(i == MM_RESOURCE_MANAGER_RES_NOT_FOUND,
350 handle->resources_lock,
351 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
352 "Invalid resource handle");
354 __mark_resource_for_release(handle->resources, i, resource);
356 MM_RM_INFO("Resource %p is marked for release in resource manager #%"PRIu64,
357 resource_h, _mm_rm_hash64(handle->id));
358 __mm_resources_unlock(handle);
360 return MM_RESOURCE_MANAGER_ERROR_NONE;
363 int _mm_resource_manager_mark_all_for_release(mm_resource_manager_h rm)
365 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
368 __mm_resource_handles_lock();
369 MM_RESOURCE_MANAGER_CHECK(handle);
370 __mm_resources_lock(handle);
371 __mm_resource_handles_unlock();
373 for (i = 0; i < handle->resources->len; i++) {
374 if (!__mark_resource_for_release(handle->resources, i,
375 (mm_resource_manager_res_p) handle->resources->pdata[i]))
379 MM_RM_INFO("All resources are marked for release in resource manager #%"PRIu64,
380 _mm_rm_hash64(handle->id));
381 __mm_resources_unlock(handle);
383 return MM_RESOURCE_MANAGER_ERROR_NONE;
386 int _mm_resource_manager_get_resource_info(mm_resource_manager_h rm,
387 mm_resource_manager_res_h resource_h,
388 mm_resource_manager_res_info_s *info)
390 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
391 mm_resource_manager_res_p resource = (mm_resource_manager_res_p) resource_h;
394 __mm_resource_handles_lock();
395 MM_RESOURCE_MANAGER_CHECK(handle);
396 __mm_resources_lock(handle);
397 __mm_resource_handles_unlock();
399 i = __get_resource_index(handle, resource);
400 MM_RM_UNLOCK_RETVM_IF(i == MM_RESOURCE_MANAGER_RES_NOT_FOUND,
401 handle->resources_lock,
402 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
403 "Invalid resource handle");
405 info->type = resource->type;
406 info->volume = resource->volume;
407 info->is_acquire_failed = resource->is_acquire_failed;
409 MM_RM_INFO("Info structure of resource %p in resource manager #%"PRIu64" is filled",
410 resource_h, _mm_rm_hash64(handle->id));
411 __mm_resources_unlock(handle);
413 return MM_RESOURCE_MANAGER_ERROR_NONE;
416 int _mm_resource_manager_commit(mm_resource_manager_h rm)
418 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
421 __mm_resource_handles_lock();
422 MM_RESOURCE_MANAGER_CHECK(handle);
423 __mm_resources_lock(handle);
424 __mm_resource_handles_unlock();
426 ret = __dbus_commit(handle);
427 if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
428 MM_RM_INFO("Changes in resource manager #%"PRIu64" have been committed successfully",
429 _mm_rm_hash64(handle->id));
431 MM_RM_ERROR("Dbus commit request failed");
432 __mm_resources_unlock(handle);
437 int _mm_resource_manager_set_status_cb(mm_resource_manager_h rm,
438 mm_resource_manager_status_cb cb, void *user_data)
440 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
442 __mm_resource_handles_lock();
443 MM_RESOURCE_MANAGER_CHECK(handle);
444 __mm_resources_lock(handle);
445 __mm_resource_handles_unlock();
447 handle->status_cb.cb = cb;
448 handle->status_cb.user_data = user_data;
449 __mm_resources_unlock(handle);
451 MM_RM_INFO("Status callback %p in resource manager #%"PRIu64" is set", cb,
452 _mm_rm_hash64(handle->id));
454 return MM_RESOURCE_MANAGER_ERROR_NONE;
457 int _mm_resource_manager_get_res_type_max_volume(mm_resource_manager_h rm,
458 mm_resource_manager_res_type_e type,
459 mm_resource_manager_res_volume *max_volume)
461 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
463 if (handle->__max_resource_volumes[type] == MM_RESOURCE_MANAGER_NO_RES) {
464 MM_RM_DEBUG("No resource for the platform");
465 return MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED;
467 *max_volume = handle->__max_resource_volumes[type];
468 return MM_RESOURCE_MANAGER_ERROR_NONE;
472 int _mm_resource_manager_get_res_type_volume(mm_resource_manager_h rm,
473 mm_resource_manager_res_type_e type,
474 mm_resource_manager_res_type_cond_e condition,
475 mm_resource_manager_res_volume *volume)
477 mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
479 if (handle->__condition_volumes[type][condition] == MM_RESOURCE_MANAGER_NO_RES) {
480 MM_RM_DEBUG("No pair (resource,condition) for the platform");
481 return MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED;
483 *volume = handle->__condition_volumes[type][condition];
484 return MM_RESOURCE_MANAGER_ERROR_NONE;
488 void __mm_resource_manager_release_callback(mm_resource_manager_s *handle,
489 mm_resource_manager_id id,
490 mm_resource_manager_res_type_e type,
491 mm_resource_manager_res_volume volume)
493 mm_resource_manager_res_s *resource;
494 mm_resource_manager_id handle_id;
495 gboolean release_all = FALSE;
498 MM_RM_DEBUG("Release callback is emitted for %s of volume %d in RM #%"PRIu64,
499 _mm_resource_manager_get_res_str(type), volume, id);
501 handle_id = handle->id;
502 MM_RM_HASH64(handle_id);
503 if (handle_id == id) {
504 __mm_resources_lock(handle);
505 __mm_resource_handles_unlock();
506 for (j = 0; j < handle->resources->len; j++) {
507 resource = (mm_resource_manager_res_s*)handle->resources->pdata[j];
508 if (resource->type == type && resource->volume == volume) {
510 release_all = ((mm_resource_manager_release_cb)
511 handle->release_cb.cb)(
512 handle, resource, handle->release_cb.user_data);
514 __send_release_cb_sync(handle->id);
516 g_ptr_array_remove_index_fast(handle->resources, j);
520 __mm_resources_unlock(handle);
523 if (_mm_resource_manager_mark_all_for_release(handle) == MM_RESOURCE_MANAGER_ERROR_NONE
524 && _mm_resource_manager_commit(handle) == MM_RESOURCE_MANAGER_ERROR_NONE) {
525 MM_RM_DEBUG("All resources are released after release cb");
527 MM_RM_ERROR("Resources cannot be released after release cb");
531 __mm_resource_handles_unlock();
535 void __mm_resource_manager_status_callback(mm_resource_manager_s *handle,
536 mm_resource_manager_status_e status)
538 __mm_resources_lock(handle);
539 __mm_resource_handles_unlock();
540 if (handle->status_cb.cb) {
541 ((mm_resource_manager_status_cb)handle->status_cb.cb)(handle, status,
542 handle->status_cb.user_data);
544 __mm_resources_unlock(handle);
547 static void __mm_resource_handles_lock(void)
549 MM_RM_INFO("handles lock");
550 g_mutex_lock(&handles_lock);
553 static void __mm_resource_handles_unlock(void)
555 g_mutex_unlock(&handles_lock);
556 MM_RM_INFO("handles unlocked");
559 static void __mm_resources_lock(mm_resource_manager_s *h)
561 MM_RM_RETM_IF(!h, "handle is NULL");
562 MM_RM_INFO("[handle %p]resources lock", h);
563 g_mutex_lock(&h->resources_lock);
566 static void __mm_resources_unlock(mm_resource_manager_s *h)
568 MM_RM_RETM_IF(!h, "handle is NULL");
569 g_mutex_unlock(&h->resources_lock);
570 MM_RM_INFO("[handle %p]resources unlocked", h);
573 static int __check_resource(mm_resource_manager_s *rm,
574 mm_resource_manager_res_type_e type,
575 mm_resource_manager_res_volume volume)
577 mm_resource_manager_res_volume remaining_local_volume =
578 rm->__max_resource_volumes[type];
579 mm_resource_manager_res_p i_res;
582 MM_RM_RETVM_IF(remaining_local_volume == MM_RESOURCE_MANAGER_NO_RES,
583 MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED,
584 "No resource for the platform");
587 MM_RM_RETVM_IF(remaining_local_volume < volume,
588 MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
589 "Requested volume %d exceeds max value %d", volume,
590 remaining_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 &&
594 i_res->state != MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE &&
595 (i_res->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL ||
596 (remaining_local_volume -= i_res->volume) < volume)) {
597 MM_RM_ERROR("Requested volume %d exceeds remaining local volume %d",
599 i_res->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL ?
600 0 : remaining_local_volume);
601 return MM_RESOURCE_MANAGER_ERROR_NOT_ENOUGH;
606 return MM_RESOURCE_MANAGER_ERROR_NONE;
609 static int __create_resource(mm_resource_manager_s *rm,
610 mm_resource_manager_res_type_e type,
611 mm_resource_manager_res_volume volume, mm_resource_manager_res_p *res)
615 MM_RM_RETVM_IF(res == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
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,
634 mm_resource_manager_res_p res)
638 for (i = 0; i < rm->resources->len; i++)
639 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)
674 static void __send_release_cb_sync(mm_resource_manager_id id)
678 sync_fd = open(RELEASE_CB_SYNC_PATH, O_WRONLY);
679 MM_RM_RETM_IF(sync_fd == -1, "Sync FIFO cannot be opened");
681 if (write(sync_fd, &id, sizeof(id)) == sizeof(id))
682 MM_RM_DEBUG("Sync message is sent successfully");
684 MM_RM_ERROR("Sync message cannot be sent");
689 static void __init_lib()
691 handles = g_ptr_array_sized_new(
692 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;
757 GVariantIter volume_iter;
758 GVariantIter cond_volume_iter;
760 mmresource_manager_call_conf_sync(handle->dbus_proxy, &rm_error,
761 &max_volume, &cond_volume, NULL, &error);
762 MM_RM_RET_IF_GERR(error, "DBus conf msg cannot be sent");
764 MM_RM_RETVM_IF(max_volume == NULL || cond_volume == NULL,
765 MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
766 "Variant data are empty");
768 if (g_variant_iter_init(&volume_iter, max_volume) ==
769 MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
770 for (i = 0; g_variant_iter_next(&volume_iter, "i",
771 &handle->__max_resource_volumes[i]); i++);
772 g_variant_unref(max_volume);
774 g_variant_unref(max_volume);
775 g_variant_unref(cond_volume);
776 MM_RM_ERROR("Wrong max volume array size");
777 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
780 if (g_variant_iter_init(&volume_iter, cond_volume) ==
781 MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
782 for (i = 0; (tmp = g_variant_iter_next_value(&volume_iter)) != NULL;
784 if (g_variant_iter_init(&cond_volume_iter, tmp) ==
785 MM_RESOURCE_MANAGER_RES_TYPE_COND_MAX) {
786 for (j = 0; g_variant_iter_next(&cond_volume_iter, "i",
787 &handle->__condition_volumes[i][j]); j++);
788 g_variant_unref(tmp);
790 g_variant_unref(tmp);
791 MM_RM_ERROR("Wrong condition volume array size");
792 rm_error = MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
796 g_variant_unref(cond_volume);
798 g_variant_unref(cond_volume);
799 MM_RM_ERROR("Wrong condition volume array size");
800 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
806 static int __dbus_create(mm_resource_manager_s *handle,
807 mm_resource_manager_app_class_e app_class)
809 GError *error = NULL;
810 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
812 mmresource_manager_call_create_sync(handle->dbus_proxy, app_class, &handle->id,
813 &rm_error, NULL, &error);
814 MM_RM_RET_IF_GERR(error, "DBus create msg cannot be sent");
816 MM_RM_DEBUG("Create returned id - #%"PRIu64", error - %d",
817 _mm_rm_hash64(handle->id), rm_error);
822 static int __dbus_destroy(mm_resource_manager_s *handle)
824 GError *error = NULL;
825 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
827 mmresource_manager_call_destroy_sync(handle->dbus_proxy, handle->id, &rm_error,
829 MM_RM_RET_IF_GERR(error, "DBus destroy msg cannot be sent");
831 MM_RM_DEBUG("Destroy for id - #%"PRIu64" returned error - %d", _mm_rm_hash64(handle->id), rm_error);
833 return MM_RESOURCE_MANAGER_ERROR_NONE;
836 static int __dbus_commit(mm_resource_manager_s *handle)
840 GVariantBuilder *release_builder;
841 GVariantBuilder *acquire_builder;
842 GVariant *flags_variant;
843 GVariantIter flags_iter;
844 mm_resource_manager_res_p resource;
848 GError *error = NULL;
849 int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
851 release_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
852 acquire_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
853 for (i = 0; i < handle->resources->len; i++) {
854 resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
856 switch (resource->state) {
857 case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
858 g_variant_builder_add_value(acquire_builder, g_variant_new("(ii)",
859 resource->type, resource->volume));
862 case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
863 g_variant_builder_add_value(release_builder, g_variant_new("(ii)",
864 resource->type, resource->volume));
872 if (release_num + acquire_num == 0) {
873 g_variant_builder_unref(release_builder);
874 g_variant_builder_unref(acquire_builder);
875 MM_RM_DEBUG("There is nothing to commit - dbus request is not sent");
880 * Acquire and release arrays are ended with special element, because
881 * g_variant_builder_end crashes without at least one element
883 g_variant_builder_add_value(acquire_builder, g_variant_new("(ii)",
884 MM_RESOURCE_MANAGER_NO_RES, 0));
885 acquire = g_variant_builder_end(acquire_builder);
886 g_variant_builder_unref(acquire_builder);
888 g_variant_builder_add_value(release_builder, g_variant_new("(ii)",
889 MM_RESOURCE_MANAGER_NO_RES, 0));
890 release = g_variant_builder_end(release_builder);
891 g_variant_builder_unref(release_builder);
893 mmresource_manager_call_commit_sync(handle->dbus_proxy, handle->id, release,
894 acquire, &rm_error, &flags_variant, NULL, &error);
896 MM_RM_RET_IF_GERR(error, "DBus commit msg cannot be sent");
898 MM_RM_DEBUG("Commit for id - #%"PRIu64" returned error - %d",
899 _mm_rm_hash64(handle->id), rm_error);
901 if (rm_error == MM_RESOURCE_MANAGER_ERROR_NONE) {
902 for (i = 0; i < handle->resources->len; i++) {
903 resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
905 switch (resource->state) {
906 case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
907 resource->state = MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED;
908 resource->is_acquire_failed = FALSE;
910 case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
911 g_ptr_array_remove_index_fast(handle->resources, i--);
917 } else if (rm_error == MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY) {
918 g_variant_iter_init(&flags_iter, flags_variant);
920 for (i = 0; i < handle->resources->len; i++) {
921 resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
923 if (resource->state == MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE)
924 g_variant_iter_next(&flags_iter, "b", &resource->is_acquire_failed);
928 g_variant_unref(flags_variant);
933 static void __dbus_release_callback(MMResourceManager *object, guint64 arg_id,
934 gint arg_resource_type, gint arg_volume)
936 mm_resource_manager_s *handle;
937 gboolean unlock = TRUE;
940 __mm_resource_handles_lock();
941 for (i = 0; i < handles->len; i++) {
942 handle = (mm_resource_manager_s*)handles->pdata[i];
943 if (handle->dbus_proxy == object) {
944 __mm_resource_manager_release_callback(handle, arg_id,
945 arg_resource_type, arg_volume);
952 __mm_resource_handles_unlock();
955 static void __dbus_status_callback(MMResourceManager *object, gint arg_status)
957 mm_resource_manager_s *handle;
958 gboolean unlock = TRUE;
961 __mm_resource_handles_lock();
962 for (i = 0; i < handles->len; i++) {
963 handle = (mm_resource_manager_s*)handles->pdata[i];
964 if (handle->dbus_proxy == object) {
965 __mm_resource_manager_status_callback(handle, arg_status);
972 __mm_resource_handles_unlock();
975 static gpointer __dispatcher_thread(gpointer user_data)
977 GMainLoop *ml = (GMainLoop *) user_data;
981 MM_RM_INFO("main loop %p quit", ml);
987 static void __destroy_dispatcher(mm_resource_manager_s *handle)
989 if (__dbus_deinit(handle) != MM_RESOURCE_MANAGER_ERROR_NONE)
990 MM_RM_ERROR("Error while dbus deinitializing");
992 if (handle->dispatcher_loop) {
993 if (g_main_loop_is_running(handle->dispatcher_loop)) {
994 MM_RM_INFO("mainloop %p is running", handle->dispatcher_loop);
995 g_main_loop_quit(handle->dispatcher_loop);
997 g_main_loop_unref(handle->dispatcher_loop);
998 handle->dispatcher_loop = NULL;
1001 if (handle->dispatcher_thread) {
1002 g_thread_join(handle->dispatcher_thread);
1003 MM_RM_INFO("dispatcher thread join %p", handle->dispatcher_thread);
1004 handle->dispatcher_thread = NULL;
1007 if (handle->dispatcher_context) {
1008 g_main_context_unref(handle->dispatcher_context);
1009 handle->dispatcher_context = NULL;