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.
26 #include "daemon/mm_resource_manager_daemon_priv.h"
27 #include "daemon/mm_resource_manager_daemon_conf.h"
28 #include "daemon/mm_resource_manager_daemon_dbus.h"
29 #include "daemon/backend/mm_resource_manager_backend.h"
30 #include "common/mm_resource_manager_utils.h"
32 #define MM_RESOURCE_MANAGER_RESERVED_RM_ARRAY_SIZE 64 /* preallocated size */
33 #define MM_RESOURCE_MANAGER_RESERVED_PART_ARRAY_SIZE 4 /* preallocated size */
34 #define MM_RESOURCE_MANAGER_RESERVED_CALLBACK_ARRAY_SIZE 32 /* preallocated size */
35 #define MM_RESOURCE_MANGER_NOT_FOUND -1
36 #define RELEASE_CB_SYNC_TIMEOUT 300 /* milliseconds */
39 MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE,
40 MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED,
41 MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE
42 } mm_resource_manager_res_state_e;
45 mm_resource_manager_res_state_e state;
47 /* NULL means, the resource is acquired fully or is not acquired at all */
50 } mm_resource_manager_dmn_res_s;
51 typedef mm_resource_manager_dmn_res_s *mm_resource_manager_dmn_res_p;
54 mm_resource_manager_id id;
55 mm_resource_manager_app_class_e app_class;
56 mm_resource_manager_res_type_e type;
58 /* if an element is NULL, there is no such a resource for the current platform. */
59 mm_resource_manager_dmn_res_p resources[MM_RESOURCE_MANAGER_RES_TYPE_MAX];
61 } mm_resource_manager_dmn_s;
62 typedef mm_resource_manager_dmn_s *mm_resource_manager_dmn_p;
65 mm_resource_manager_dmn_p manager;
66 mm_resource_manager_res_type_e type;
67 mm_resource_manager_res_volume volume;
68 } mm_resource_manager_dmn_release_cb_request_s;
70 static const char *res_state_str[] = {
76 static GPtrArray *managers;
77 static int res_count[MM_RESOURCE_MANAGER_RES_TYPE_MAX];
79 static void __destroy_resource(mm_resource_manager_dmn_res_p res);
80 static void __destroy_manager(void *m);
81 static int __search_manager_index(mm_resource_manager_id id);
82 static inline mm_resource_manager_dmn_p __search_manager(mm_resource_manager_id id);
83 static mm_resource_manager_error_e __check_release_requests(mm_resource_manager_dmn_p manager,
84 mm_resource_manager_dmn_res_request_s *releases);
85 static mm_resource_manager_dmn_res_request_s *__create_dmn_res_requests(
86 mm_resource_manager_dmn_res_request_s *releases, mm_resource_manager_dmn_res_request_s *acquires);
87 static mm_resource_manager_error_e __check_requests_conflict(mm_resource_manager_dmn_p manager,
88 mm_resource_manager_dmn_res_request_s *requests);
89 static void __sync_increase_acquire_requests(mm_resource_manager_dmn_res_request_s *increases,
90 mm_resource_manager_dmn_res_request_s *acquires);
91 static void __handle_release_requests(mm_resource_manager_dmn_p manager, mm_resource_manager_dmn_res_request_s *requests);
92 static GArray* __handle_acquire_requests(mm_resource_manager_dmn_p manager, mm_resource_manager_dmn_res_request_s *requests);
93 static void __handle_release_callbacks(GArray *requests);
94 static inline void __add_cb_request(GArray *cb_requests, mm_resource_manager_dmn_p mgr,
95 mm_resource_manager_res_type_e type, mm_resource_manager_res_volume volume);
96 static void __destroy_all_resources(mm_resource_manager_dmn_p manager);
97 static gboolean __poll(struct pollfd sync, mm_resource_manager_id id);
98 static gboolean __wait_for_release_cb_sync(mm_resource_manager_id id);
103 gboolean _mmrm_dmn_init(void)
105 MM_RM_RETVMS_IF(access(RELEASE_CB_SYNC_PATH, F_OK) != 0, FALSE,
106 "systemd-tmpfiles-setup.service can't create %s", RELEASE_CB_SYNC_PATH);
108 MM_RM_RETVM_IF(mm_resource_manager_backend_init() != MM_RESOURCE_MANAGER_ERROR_NONE, FALSE, "Back-end cannot be initialized");
110 if (_mmrm_dmn_dbus_init() != MM_RESOURCE_MANAGER_ERROR_NONE) {
111 mm_resource_manager_backend_deinit();
112 MM_RM_ERROR("D-bus server cannot be created");
116 managers = g_ptr_array_new_full(MM_RESOURCE_MANAGER_RESERVED_RM_ARRAY_SIZE, __destroy_manager);
117 MM_RM_RETVM_IF(managers == NULL, FALSE, "Daemon cannot be initialized");
122 gboolean _mmrm_dmn_deinit(void)
126 if (mm_resource_manager_backend_deinit() != MM_RESOURCE_MANAGER_ERROR_NONE)
127 MM_RM_ERROR("Error during back-end deinitialization");
129 if (_mmrm_dmn_dbus_deinit() != MM_RESOURCE_MANAGER_ERROR_NONE)
130 MM_RM_ERROR("Error during d-bus server shutdown");
133 for (i = 0; i < managers->len; i++)
134 __destroy_all_resources((mm_resource_manager_dmn_p)managers->pdata[i]);
136 mm_resource_manager_backend_commit_all();
137 g_ptr_array_free(managers, TRUE);
139 MM_RM_ERROR("Trying to deinit uninitialized daemon");
142 if (unlink(RELEASE_CB_SYNC_PATH) == -1)
143 MM_RM_ERROR("Release callback sync cannot be removed");
148 mm_resource_manager_error_e _mmrm_dmn_create(
149 mm_resource_manager_app_class_e app_class, mm_resource_manager_id *id)
151 mm_resource_manager_dmn_p mgr;
152 mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
155 MM_RM_RETVM_IF(app_class < 0 || app_class >= MM_RESOURCE_MANAGER_APP_CLASS_MAX,
156 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "Wrong app class");
158 MM_RM_RETVM_IF(conf->priority[app_class] == MM_RESOURCE_MANAGER_NO_APP_CLASS,
159 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "App class is not supported for the platform");
161 mgr = g_new0(mm_resource_manager_dmn_s, 1);
162 MM_RM_RAND64(mgr->id);
163 mgr->app_class = app_class;
164 for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++) {
165 mgr->resources[i] = conf->max_volume[i] == MM_RESOURCE_MANAGER_NO_RES ?
166 NULL : g_malloc0(sizeof(mm_resource_manager_dmn_s));
169 g_ptr_array_add(managers, mgr);
171 MM_RM_INFO("managers length %d", managers->len);
175 return MM_RESOURCE_MANAGER_ERROR_NONE;
178 mm_resource_manager_error_e _mmrm_dmn_destroy(mm_resource_manager_id id)
180 int idx = __search_manager_index(id);
181 mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
182 mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
183 mm_resource_manager_dmn_p i_mgr = __search_manager(id);
185 MM_RM_RETVM_IF(idx == MM_RESOURCE_MANGER_NOT_FOUND, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
186 "Resource manager #%"PRIu64" doesn't exist", _mm_rm_hash64(id));
187 MM_RM_RETVM_IF(conf == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "conf is null");
191 __destroy_all_resources(i_mgr);
192 mm_resource_manager_backend_commit_all();
194 g_ptr_array_remove_index_fast(managers, idx);
196 MM_RM_INFO("remaining managers #%d type %s available volume %d",
197 managers->len, _mm_resource_manager_get_res_str(type), conf->max_volume[type]);
203 return MM_RESOURCE_MANAGER_ERROR_NONE;
206 mm_resource_manager_error_e _mmrm_dmn_commit(mm_resource_manager_id id,
207 mm_resource_manager_dmn_res_request_s *releases, mm_resource_manager_dmn_res_request_s *acquires)
209 mm_resource_manager_dmn_p mgr = __search_manager(id);
210 mm_resource_manager_error_e ret = MM_RESOURCE_MANAGER_ERROR_NONE;
211 mm_resource_manager_dmn_res_request_s *increases = NULL;
214 MM_RM_RETVM_IF(mgr == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
215 "Resource manager #%"PRIu64" doesn't exist", _mm_rm_hash64(id));
216 MM_RM_RETVM_IF((releases == NULL || releases[0].type == MM_RESOURCE_MANAGER_NO_RES) &&
217 (acquires == NULL || acquires[0].type == MM_RESOURCE_MANAGER_NO_RES),
218 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "Commit request is empty");
220 MM_RM_INFO("RM #%"PRIu64" mgr [%p] release type (%s) acquires type (%s)", _mm_rm_hash64(mgr->id), mgr,
221 releases[0].type == MM_RESOURCE_MANAGER_NO_RES ? "nil" : _mm_resource_manager_get_res_str(releases[0].type),
222 acquires[0].type == MM_RESOURCE_MANAGER_NO_RES ? "nil" : _mm_resource_manager_get_res_str(acquires[0].type));
224 ret = __check_release_requests(mgr, releases);
225 MM_RM_RETVM_IF(ret != MM_RESOURCE_MANAGER_ERROR_NONE, ret, "check_release_requests is failed [0x%x]", ret);
227 increases = __create_dmn_res_requests(releases, acquires);
228 MM_RM_RETVM_IF(increases == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "create_increase_requests is failed");
230 ret = __check_requests_conflict(mgr, increases);
231 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
232 __sync_increase_acquire_requests(increases, acquires);
238 __handle_release_requests(mgr, releases);
239 cb_requests = __handle_acquire_requests(mgr, acquires);
240 MM_RM_RETVM_IF(cb_requests == NULL, MM_RESOURCE_MANAGER_ERROR_NOT_ENOUGH, "not enough free resource volume");
241 __handle_release_callbacks(cb_requests);
242 if (!mm_resource_manager_backend_commit_all()) {
244 * The commit_all function can fail only if resource management back-end is not solely used by mm-resource-manager or
245 * if the back-end cannot acquire/release a resource because of some internal error.
247 * Initiate status disconnected and reload the back-end and the RM daemon.
249 kill(getpid(), SIGHUP);
250 ret = MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
252 g_array_free(cb_requests, TRUE);
257 void _mmrm_dmn_status_callback(mm_resource_manager_status_e status)
259 _mmrm_dmn_dbus_status_callback(status);
262 static void __destroy_resource(mm_resource_manager_dmn_res_p res)
268 g_array_free(res->parts, TRUE);
273 static void __destroy_manager(void *m)
275 mm_resource_manager_dmn_p mgr = (mm_resource_manager_dmn_p) m;
278 MM_RM_RETM_IF(mgr == NULL, "NULL pointer");
280 for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++)
281 __destroy_resource(mgr->resources[i]);
286 static int __search_manager_index(mm_resource_manager_id id)
290 for (i = managers->len - 1; i >= 0; i--) {
291 if (((mm_resource_manager_dmn_p)managers->pdata[i])->id == id)
295 return MM_RESOURCE_MANGER_NOT_FOUND;
298 static inline mm_resource_manager_dmn_p __search_manager(mm_resource_manager_id id)
300 int i = __search_manager_index(id);
301 return i == MM_RESOURCE_MANGER_NOT_FOUND ? NULL : managers->pdata[i];
304 static mm_resource_manager_error_e __check_release_requests(mm_resource_manager_dmn_p manager,
305 mm_resource_manager_dmn_res_request_s *releases)
308 mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
309 mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
310 const char *res_name = NULL;
312 MM_RM_RETVM_IF(conf == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "conf is null");
313 MM_RM_RETVM_IF(releases == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "requests is null");
315 for (; releases->type != MM_RESOURCE_MANAGER_NO_RES; releases++) {
317 type = releases->type;
318 res_name = _mm_resource_manager_get_res_str(type);
320 MM_RM_RETVM_IF(manager->resources[type] == NULL,
321 MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED, "There is no resource %s for the platform", res_name);
323 if (manager->resources[type]->state == MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED) {
324 if (manager->resources[type]->parts == NULL) {
325 if (releases->volume != MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
326 MM_RM_ERROR("Resource %s is acquired fully, but a resource part is tried to be released", res_name);
327 return MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER;
330 for (i = 0; i < manager->resources[type]->parts->len &&
331 ((mm_resource_manager_res_volume*)manager->resources[type]->parts->data)[i] != releases->volume; i++);
332 if (i == manager->resources[type]->parts->len) {
333 MM_RM_ERROR("Part of %s of volume %d is not acquired", res_name, releases->volume);
334 return MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER;
338 MM_RM_ERROR("Resource %s is not acquired", res_name);
339 return MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER;
341 MM_RM_DEBUG("Release requests are OK type %s available volume %d", res_name, conf->max_volume[type]);
344 return MM_RESOURCE_MANAGER_ERROR_NONE;
347 static mm_resource_manager_dmn_res_request_s *__create_dmn_res_requests(
348 mm_resource_manager_dmn_res_request_s *releases, mm_resource_manager_dmn_res_request_s *acquires)
352 mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
353 mm_resource_manager_dmn_res_request_s *result = NULL;
354 mm_resource_manager_dmn_res_request_s *result_iter = NULL;
355 mm_resource_manager_res_volume resources[MM_RESOURCE_MANAGER_RES_TYPE_MAX] = { 0 };
357 MM_RM_RETVM_IF(conf == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "conf is null");
359 for (; acquires->type != MM_RESOURCE_MANAGER_NO_RES; acquires++) {
361 if ((resources[acquires->type] > 0 || resources[acquires->type] == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) &&
362 acquires->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
363 MM_RM_ERROR("The client tries to acquire %s by part and fully at once", _mm_resource_manager_get_res_str(acquires->type));
367 if (acquires->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
368 resources[acquires->type] = MM_RESOURCE_MANAGER_RES_VOLUME_FULL;
370 if (conf->max_volume[acquires->type] > 1)
371 resources[acquires->type] += acquires->volume;
373 resources[acquires->type]++;
376 MM_RM_DEBUG("(type, vol) = (%d, %d)", acquires->type, resources[acquires->type]);
379 for (; releases->type != MM_RESOURCE_MANAGER_NO_RES; releases++) {
380 if (resources[releases->type] > 1) {
381 resources[releases->type] += releases->volume;
382 MM_RM_INFO("type %s available volume %d", _mm_resource_manager_get_res_str(releases->type), resources[releases->type]);
386 for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++)
387 if (resources[i] > 0 || resources[i] == MM_RESOURCE_MANAGER_RES_VOLUME_FULL)
390 result_iter = result = g_new0(mm_resource_manager_dmn_res_request_s, result_len);
391 for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++) {
392 if (resources[i] > 0 || resources[i] == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
393 result_iter->type = i;
394 result_iter->volume = resources[i];
398 result_iter->type = MM_RESOURCE_MANAGER_NO_RES;
403 static mm_resource_manager_error_e __check_requests_conflict(mm_resource_manager_dmn_p manager,
404 mm_resource_manager_dmn_res_request_s *requests)
406 mm_resource_manager_res_volume remaining_volume;
407 mm_resource_manager_dmn_p i_mgr;
408 mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
410 mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
411 const char *res_name = NULL;
413 MM_RM_RETVM_IF(conf == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "conf is null");
414 MM_RM_RETVM_IF(manager == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "manager is null");
415 MM_RM_RETVM_IF(requests == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "requests is null");
419 for (; requests->type != MM_RESOURCE_MANAGER_NO_RES; requests++) {
420 type = requests->type;
421 res_name = _mm_resource_manager_get_res_str(type);
423 MM_RM_RETVM_IF(type < MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER || type >= MM_RESOURCE_MANAGER_RES_TYPE_MAX,
424 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "wrong type %s", res_name);
425 MM_RM_RETVM_IF(manager->resources[type] == NULL, MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED,
426 "There is no resource %s for the platform", res_name);
428 remaining_volume = conf->max_volume[type];
430 for (i = 0; i < len; i++) {
431 i_mgr = (mm_resource_manager_dmn_p)managers->pdata[i];
433 if (i_mgr != manager && conf->priority[i_mgr->app_class] > conf->priority[manager->app_class] &&
434 i_mgr->resources[type]->state == MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED) {
435 if (i_mgr->resources[type]->parts) {
436 if (requests->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
437 requests->priority_error = TRUE;
438 MM_RM_DEBUG("Resource conflict. Full volume is requested, but only part is available");
439 return MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY;
441 for (j = 0; j < i_mgr->resources[type]->parts->len; j++)
442 remaining_volume -= g_array_index(i_mgr->resources[type]->parts, mm_resource_manager_res_volume, j);
444 if (remaining_volume < requests->volume) {
445 requests->priority_error = TRUE;
446 MM_RM_DEBUG("Resource conflict. %d of %s are available, but %d required",
447 remaining_volume, res_name, requests->volume);
448 return MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY;
452 requests->priority_error = TRUE;
453 MM_RM_DEBUG("Resource conflict. %s is already acquired fully", res_name);
454 return MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY;
460 return MM_RESOURCE_MANAGER_ERROR_NONE;
463 static void __sync_increase_acquire_requests(mm_resource_manager_dmn_res_request_s *increases,
464 mm_resource_manager_dmn_res_request_s *acquires)
466 mm_resource_manager_dmn_res_request_s *increase_iter;
467 mm_resource_manager_dmn_res_request_s *acquire_iter;
469 for (increase_iter = increases; increase_iter->type != MM_RESOURCE_MANAGER_NO_RES; increase_iter++) {
470 for (acquire_iter = acquires; acquire_iter->type != MM_RESOURCE_MANAGER_NO_RES; acquire_iter++) {
471 if (acquire_iter->type == increase_iter->type)
472 acquire_iter->priority_error = increase_iter->priority_error;
477 static inline void __add_cb_request(GArray *cb_requests,mm_resource_manager_dmn_p mgr,
478 mm_resource_manager_res_type_e type, mm_resource_manager_res_volume volume)
480 mm_resource_manager_dmn_release_cb_request_s *cb_request;
482 g_array_set_size(cb_requests, cb_requests->len + 1);
483 cb_request = &g_array_index(cb_requests, mm_resource_manager_dmn_release_cb_request_s, cb_requests->len - 1);
485 cb_request->manager = mgr;
486 cb_request->type = type;
487 cb_request->volume = volume;
490 static GArray *__handle_acquire_requests(mm_resource_manager_dmn_p manager,
491 mm_resource_manager_dmn_res_request_s *requests)
493 mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
494 mm_resource_manager_res_volume acquired_volume = 0;
495 mm_resource_manager_dmn_p i_mgr = NULL, j_mgr = NULL;
496 const char *res_name = NULL;
497 GArray *cb_requests = NULL;
500 mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
501 mm_resource_manager_res_volume volume = MM_RESOURCE_MANAGER_RES_VOLUME_FULL;
503 MM_RM_RETVM_IF(conf == NULL, NULL, "conf is NULL");
504 MM_RM_RETVM_IF(requests == NULL, NULL, "requests is NULL");
506 cb_requests = g_array_sized_new(FALSE, FALSE, sizeof(mm_resource_manager_dmn_release_cb_request_s),
507 MM_RESOURCE_MANAGER_RESERVED_CALLBACK_ARRAY_SIZE);
509 for (; requests->type != MM_RESOURCE_MANAGER_NO_RES; requests++) {
510 type = requests->type;
511 res_name = _mm_resource_manager_get_res_str(type);
512 volume = requests->volume;
514 if (volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
515 MM_RM_DEBUG("Resource of %s is requested (mgr %p)", res_name, manager);
517 for (i = 0; i < managers->len; i++) {
518 i_mgr = (mm_resource_manager_dmn_p)managers->pdata[i];
520 if (manager->id == i_mgr->id || conf->priority[i_mgr->app_class] >conf->priority[manager->app_class]) {
521 i_mgr->resources[type]->state = MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED;
523 i_mgr->volume = volume;
524 MM_RM_DEBUG("Reset the value of acquire in RM #%"PRIu64" (type %s mgr %p)", _mm_rm_hash64(i_mgr->id), res_name, i_mgr);
525 if (conf->max_instance[type] > 0)
530 if ((res = i_mgr->resources[type]->parts)) { /* always null, which is no conflict case now */
531 for (j = 0; j < res->len; j++) {
532 __add_cb_request(cb_requests, i_mgr, type, g_array_index(res, mm_resource_manager_res_volume, j));
533 mm_resource_manager_backend_release(type);
535 g_array_free(res, TRUE);
536 i_mgr->resources[type]->parts = NULL;
538 MM_RM_WARNING("Resource of %s is conflicted in RM #%"PRIu64, res_name, _mm_rm_hash64(i_mgr->id));
540 __add_cb_request(cb_requests, i_mgr, type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL);
542 mm_resource_manager_backend_release(type);
544 if (i_mgr->resources[type]->state == MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE)
545 MM_RM_DEBUG("Resource %s will be released (%s state) in RM #%"PRIu64" available volume %d", res_name,
546 res_state_str[i_mgr->resources[type]->state], _mm_rm_hash64(i_mgr->id), conf->max_volume[type]);
548 MM_RM_DEBUG("Resource %s will be released (%s state) in RM #%"PRIu64" available volume %d", res_name,
549 res_state_str[i_mgr->resources[type]->state], _mm_rm_hash64(i_mgr->id), conf->max_volume[type]);
553 MM_RM_INFO("[managers len #%d] [%s #%d (max inst #%d)] [%d (max vol %d)] are requested",
554 managers->len, res_name, res_count[type] + 1, conf->max_instance[type], volume, conf->max_volume[type]);
556 if (conf->max_instance[type] > 0 && conf->max_instance[type] == res_count[type]) {
557 for (i= 0; i < managers->len; i++) {
558 i_mgr = (mm_resource_manager_dmn_p)managers->pdata[j];
559 res = i_mgr->resources[type]->parts;
561 if (res && i_mgr->resources[type]->state == MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED) {
562 MM_RM_INFO("[#%d] [#%d / #%d] will be released %s in RM #%"PRIu64,
563 managers->len, i + 1, res->len, res_name, _mm_rm_hash64(i_mgr->id));
565 __add_cb_request(cb_requests, i_mgr, type, g_array_index(res, mm_resource_manager_res_volume, 0));
567 mm_resource_manager_backend_release(type);
572 for (i = 0; i < managers->len; i++) {
573 i_mgr = (mm_resource_manager_dmn_p)managers->pdata[i];
574 res = i_mgr->resources[type]->parts;
576 if (manager->id == i_mgr->id || conf->priority[i_mgr->app_class] > conf->priority[manager->app_class]) {
578 if (conf->volume_would_be_checked[type]) {
579 if (i_mgr->resources[type]->state != MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED && conf->max_volume[type] >= 0) {
580 i_mgr->resources[type]->state = MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED;
582 i_mgr->volume = volume;
583 conf->max_volume[type] -= volume;
584 MM_RM_INFO("[type %s] - %d = %d", res_name, volume, conf->max_volume[type]);
587 if (conf->volume_would_be_checked[type] && conf->max_volume[type] < 0
588 && acquired_volume < volume) {
589 for (j = 0; j < managers->len; j++) {
590 j_mgr = (mm_resource_manager_dmn_p)managers->pdata[j];
591 res = j_mgr->resources[type]->parts;
593 if (j_mgr->resources[type]->state != MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED)
596 acquired_volume += g_array_index(res, mm_resource_manager_res_volume, 0);
597 MM_RM_INFO("[#%d] [#%d / #%d] There are %d units of %s in RM #%"PRIu64,
598 managers->len, j + 1, res->len, acquired_volume, res_name, _mm_rm_hash64(j_mgr->id));
600 __add_cb_request(cb_requests, j_mgr, type, g_array_index(res, mm_resource_manager_res_volume, 0));
602 mm_resource_manager_backend_release(type);
604 if (acquired_volume >= volume)
610 if (i_mgr->resources[type]->state == MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED)
613 i_mgr->resources[type]->state = MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED;
617 res = manager->resources[requests->type]->parts;
619 res = g_array_sized_new(FALSE, FALSE, sizeof(mm_resource_manager_res_volume),
620 MM_RESOURCE_MANAGER_RESERVED_PART_ARRAY_SIZE);
621 manager->resources[requests->type]->parts = res;
623 g_array_append_val(res, requests->volume);
626 manager->resources[type]->state = MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED;
627 mm_resource_manager_backend_acquire(type);
629 MM_RM_DEBUG("RM #%"PRIu64" (type %s mgr %p) is acquired", _mm_rm_hash64(i_mgr->id), res_name, i_mgr);
635 static void __handle_release_callbacks(GArray *requests)
638 mm_resource_manager_id id;
639 mm_resource_manager_dmn_release_cb_request_s *request;
640 mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
641 mm_resource_manager_res_volume volume = MM_RESOURCE_MANAGER_RES_VOLUME_FULL;
642 mm_resource_manager_dmn_p mgr = NULL;
643 const char *res_name = NULL;
644 mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
646 MM_RM_RETM_IF(requests == NULL, "requests is NULL");
647 MM_RM_RETM_IF(conf == NULL, "conf is NULL");
649 for (i = 0; i < requests->len; i++) {
650 request = &g_array_index(requests, mm_resource_manager_dmn_release_cb_request_s, i);
651 mgr = request->manager;
652 type = request->type;
653 res_name = _mm_resource_manager_get_res_str(type);
654 volume = request->volume;
656 if (mgr->resources[type]->state != MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED)
662 if (mgr->type == type && mgr->volume == volume && mgr->resources[type]->state == MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE) {
663 MM_RM_WARNING("Resource (mgr %p) release callback is already invoked RM #%"PRIu64" for %s of volume %d",
664 mgr, id, res_name, volume);
668 MM_RM_INFO("Sending release callback to [mgr %p] RM #%"PRIu64" for %s of volume %d", mgr, id, res_name, volume);
670 _mmrm_dmn_dbus_release_callback(id, type, volume);
672 if (__wait_for_release_cb_sync(id)) {
673 MM_RM_INFO("[SYNC] Release callback success RM #%"PRIu64, id);
674 if (conf->volume_would_be_checked[type] && volume != MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
675 conf->max_volume[type] += volume;
676 MM_RM_DEBUG("type %s available volume + %d = %d", res_name, volume, conf->max_volume[type]);
679 if (conf->max_instance[type] > 0 && res_count[type] > 0) {
681 MM_RM_DEBUG("The number of type %s #%d", res_name, res_count[type]);
684 mgr->resources[type]->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE;
685 MM_RM_DEBUG("RM #%"PRIu64" (type %s mgr %p) set acquired value as state (%s)",
686 id, res_name, mgr, res_state_str[mgr->resources[type]->state]);
688 MM_RM_ERROR("Wait for release callback sync failed RM #%"PRIu64" (type %s)", id, res_name);
693 static void __handle_release_requests(mm_resource_manager_dmn_p manager,
694 mm_resource_manager_dmn_res_request_s *requests)
698 mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
699 mm_resource_manager_res_volume volume = MM_RESOURCE_MANAGER_RES_VOLUME_FULL;
700 const char *res_name = NULL;
701 mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
703 MM_RM_RETM_IF(conf == NULL, "conf is NULL");
704 MM_RM_RETM_IF(requests == NULL, "requests is NULL");
706 for (; requests->type != MM_RESOURCE_MANAGER_NO_RES; requests++) {
708 type = requests->type;
709 res_name = _mm_resource_manager_get_res_str(type);
710 volume = requests->volume;
712 if (volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
713 manager->resources[type]->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE;
715 parts = manager->resources[type]->parts;
716 for (i = 0; i < parts->len && ((mm_resource_manager_res_volume*)parts->data)[i] != volume; i++);
718 g_array_remove_index_fast(parts, i);
720 if (parts->len == 0) {
721 g_array_free(parts, TRUE);
722 manager->resources[type]->parts = NULL;
723 manager->resources[type]->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE;
727 if (conf->volume_would_be_checked[type]) {
728 conf->max_volume[type] += volume;
729 MM_RM_INFO("[type %s] + %d = %d", res_name, volume, conf->max_volume[type]);
732 if (conf->max_instance[type] > 0 && res_count[type] > 0) {
734 MM_RM_INFO("The number of type %s #%d", res_name, res_count[type]);
737 mm_resource_manager_backend_release(type);
741 static void __destroy_all_resources(mm_resource_manager_dmn_p manager)
745 for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++) {
746 if (manager->resources[i] && manager->resources[i]->state == MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED) {
747 if (manager->resources[i]->parts) {
748 for (j = 0; j < manager->resources[i]->parts->len; j++)
749 mm_resource_manager_backend_release(i);
751 mm_resource_manager_backend_release(i);
753 manager->resources[i]->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE;
758 static gboolean __poll(struct pollfd sync, mm_resource_manager_id id)
764 while (try_cnt++ < 3) {
765 sync.events = POLLIN;
768 ret = poll(&sync, 1, RELEASE_CB_SYNC_TIMEOUT);
772 MM_RM_ERROR("[%d ms] Polling is failed [fd %d errno %d] RM #%"PRIu64" revents : 0x%x",
773 RELEASE_CB_SYNC_TIMEOUT, sync.fd, errsv, id, sync.revents);
777 } else if (ret == 0) {
778 MM_RM_WARNING("Wait timeout [%d ms] is elapsed [fd %d] RM #%"PRIu64" revents : 0x%x",
779 RELEASE_CB_SYNC_TIMEOUT, sync.fd, id, sync.revents);
783 MM_RM_DEBUG("[fd %d] RM #%"PRIu64" revents : 0x%x", sync.fd, id, sync.revents);
790 static gboolean __wait_for_release_cb_sync(mm_resource_manager_id id)
792 gboolean ret = FALSE;
793 struct pollfd sync = {0};
794 mm_resource_manager_id recv_id;
797 sync.fd = open(RELEASE_CB_SYNC_PATH, O_RDONLY | O_NONBLOCK);
798 MM_RM_RETVM_IF(sync.fd == -1, FALSE, "Sync FIFO cannot be opened");
800 if (!__poll(sync, id))
803 read_size = read(sync.fd, &recv_id, sizeof(recv_id));
804 if (read_size != sizeof(recv_id)) {
805 MM_RM_ERROR("Read is failed (revents=%hd, read_size=%zd)", sync.revents, read_size);
809 if (id != _mm_rm_hash64(recv_id))
810 MM_RM_WARNING("Sync is received from wrong client #%"PRIu64, id);
812 ret = __poll(sync, id);