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 5000 /* 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;
57 mm_resource_manager_res_volume volume;
59 /* if an element is NULL, there is no such a resource for the current platform. */
60 mm_resource_manager_dmn_res_p resources[MM_RESOURCE_MANAGER_RES_TYPE_MAX];
62 } mm_resource_manager_dmn_s;
63 typedef mm_resource_manager_dmn_s *mm_resource_manager_dmn_p;
66 mm_resource_manager_dmn_p manager;
67 mm_resource_manager_res_type_e type;
68 mm_resource_manager_res_volume volume;
70 } mm_resource_manager_dmn_release_cb_request_s;
72 static const char *res_state_str[] = {
78 static GPtrArray *managers;
79 static int res_count[MM_RESOURCE_MANAGER_RES_TYPE_MAX];
81 static void __destroy_resource(mm_resource_manager_dmn_res_p res);
82 static void __destroy_manager(void *m);
83 static int __search_manager_index(mm_resource_manager_id id);
84 static inline mm_resource_manager_dmn_p __search_manager(mm_resource_manager_id id);
85 static mm_resource_manager_error_e __check_release_requests(mm_resource_manager_dmn_p manager,
86 mm_resource_manager_dmn_res_request_s *releases);
87 static mm_resource_manager_dmn_res_request_s *__create_dmn_res_requests(
88 mm_resource_manager_dmn_res_request_s *releases, mm_resource_manager_dmn_res_request_s *acquires);
89 static mm_resource_manager_error_e __check_requests_conflict(mm_resource_manager_dmn_p manager,
90 mm_resource_manager_dmn_res_request_s *requests);
91 static void __sync_increase_acquire_requests(mm_resource_manager_dmn_res_request_s *increases,
92 mm_resource_manager_dmn_res_request_s *acquires);
93 static void __handle_release_requests(mm_resource_manager_dmn_p manager, mm_resource_manager_dmn_res_request_s *requests);
94 static GArray* __handle_acquire_requests(mm_resource_manager_dmn_p manager, mm_resource_manager_dmn_res_request_s *requests);
95 static void __handle_release_callbacks(GArray *requests);
96 static int __open_release_cb_sync_fd(void);
97 static void __close_release_cb_sync_fd(int fd);
98 static gboolean __is_process_alive(int pid);
99 static inline void __add_cb_request(GArray *cb_requests, mm_resource_manager_dmn_p mgr,
100 mm_resource_manager_res_type_e type, mm_resource_manager_res_volume volume);
101 static void __destroy_all_resources(mm_resource_manager_dmn_p manager);
102 static gboolean __poll(struct pollfd sync, mm_resource_manager_id id);
103 static gboolean __wait_for_release_cb_sync(mm_resource_manager_id id, int sync_fd);
108 gboolean _mmrm_dmn_init(void)
110 MM_RM_RETVMS_IF(access(RELEASE_CB_SYNC_PATH, F_OK) != 0, FALSE,
111 "access(%s) is failed errno[%d]", RELEASE_CB_SYNC_PATH, errno);
113 MM_RM_RETVM_IF(mm_resource_manager_backend_init() != MM_RESOURCE_MANAGER_ERROR_NONE,
114 FALSE, "Back-end cannot be initialized");
116 if (_mmrm_dmn_dbus_init() != MM_RESOURCE_MANAGER_ERROR_NONE) {
117 mm_resource_manager_backend_deinit();
118 MM_RM_ERROR("D-bus server cannot be created");
122 managers = g_ptr_array_new_full(MM_RESOURCE_MANAGER_RESERVED_RM_ARRAY_SIZE, __destroy_manager);
123 MM_RM_RETVM_IF(managers == NULL, FALSE, "Daemon cannot be initialized");
128 gboolean _mmrm_dmn_deinit(void)
132 if (mm_resource_manager_backend_deinit() != MM_RESOURCE_MANAGER_ERROR_NONE)
133 MM_RM_ERROR("Error during back-end deinitialization");
135 if (_mmrm_dmn_dbus_deinit() != MM_RESOURCE_MANAGER_ERROR_NONE)
136 MM_RM_ERROR("Error during d-bus server shutdown");
139 for (i = 0; i < managers->len; i++)
140 __destroy_all_resources((mm_resource_manager_dmn_p)managers->pdata[i]);
142 mm_resource_manager_backend_commit_all();
143 g_ptr_array_free(managers, TRUE);
145 MM_RM_ERROR("Trying to deinit uninitialized daemon");
148 if (unlink(RELEASE_CB_SYNC_PATH) == -1)
149 MM_RM_ERROR("Release callback sync cannot be removed");
154 mm_resource_manager_error_e _mmrm_dmn_create(
155 mm_resource_manager_app_class_e app_class, mm_resource_manager_id *id)
157 mm_resource_manager_dmn_p mgr;
158 mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
161 MM_RM_RETVM_IF(app_class < 0 || app_class >= MM_RESOURCE_MANAGER_APP_CLASS_MAX,
162 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "Wrong app class");
164 MM_RM_RETVM_IF(conf->priority[app_class] == MM_RESOURCE_MANAGER_NO_APP_CLASS,
165 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "App class is not supported for the platform");
167 mgr = g_new0(mm_resource_manager_dmn_s, 1);
168 MM_RM_RAND64(mgr->id);
169 mgr->app_class = app_class;
170 for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++) {
171 mgr->resources[i] = conf->max_volume[i] == MM_RESOURCE_MANAGER_NO_RES ?
172 NULL : g_malloc0(sizeof(mm_resource_manager_dmn_s));
175 g_ptr_array_add(managers, mgr);
177 MM_RM_INFO("managers length %d", managers->len);
181 return MM_RESOURCE_MANAGER_ERROR_NONE;
184 mm_resource_manager_error_e _mmrm_dmn_destroy(mm_resource_manager_id id)
186 int idx = __search_manager_index(id);
187 mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
188 mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
189 mm_resource_manager_dmn_p i_mgr = __search_manager(id);
191 MM_RM_RETVM_IF(idx == MM_RESOURCE_MANGER_NOT_FOUND, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
192 "Resource manager #%"PRIu64" doesn't exist", _mm_rm_hash64(id));
193 MM_RM_RETVM_IF(conf == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "conf is null");
197 __destroy_all_resources(i_mgr);
198 mm_resource_manager_backend_commit_all();
200 g_ptr_array_remove_index_fast(managers, idx);
202 MM_RM_INFO("remaining managers #%d type %s available volume %d",
203 managers->len, _mm_resource_manager_get_res_str(type), conf->max_volume[type]);
209 return MM_RESOURCE_MANAGER_ERROR_NONE;
212 mm_resource_manager_error_e _mmrm_dmn_commit(mm_resource_manager_id id,
213 mm_resource_manager_dmn_res_request_s *releases, mm_resource_manager_dmn_res_request_s *acquires)
215 mm_resource_manager_dmn_p mgr = __search_manager(id);
216 mm_resource_manager_error_e ret = MM_RESOURCE_MANAGER_ERROR_NONE;
217 mm_resource_manager_dmn_res_request_s *increases = NULL;
220 MM_RM_RETVM_IF(mgr == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
221 "Resource manager #%"PRIu64" doesn't exist", _mm_rm_hash64(id));
222 MM_RM_RETVM_IF((releases == NULL || releases[0].type == MM_RESOURCE_MANAGER_NO_RES) &&
223 (acquires == NULL || acquires[0].type == MM_RESOURCE_MANAGER_NO_RES),
224 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "Commit request is empty");
226 MM_RM_INFO("RM #%"PRIu64" mgr [%p] release type (%s) acquires type (%s)", _mm_rm_hash64(mgr->id), mgr,
227 releases[0].type == MM_RESOURCE_MANAGER_NO_RES ? "nil" : _mm_resource_manager_get_res_str(releases[0].type),
228 acquires[0].type == MM_RESOURCE_MANAGER_NO_RES ? "nil" : _mm_resource_manager_get_res_str(acquires[0].type));
230 ret = __check_release_requests(mgr, releases);
231 MM_RM_RETVM_IF(ret != MM_RESOURCE_MANAGER_ERROR_NONE, ret, "check_release_requests is failed [0x%x]", ret);
233 increases = __create_dmn_res_requests(releases, acquires);
234 MM_RM_RETVM_IF(increases == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "create_increase_requests is failed");
236 ret = __check_requests_conflict(mgr, increases);
237 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
238 __sync_increase_acquire_requests(increases, acquires);
244 __handle_release_requests(mgr, releases);
245 cb_requests = __handle_acquire_requests(mgr, acquires);
246 MM_RM_RETVM_IF(cb_requests == NULL, MM_RESOURCE_MANAGER_ERROR_NOT_ENOUGH, "not enough free resource volume");
247 __handle_release_callbacks(cb_requests);
248 if (!mm_resource_manager_backend_commit_all()) {
250 * The commit_all function can fail only if resource management back-end is not solely used by mm-resource-manager or
251 * if the back-end cannot acquire/release a resource because of some internal error.
253 * Initiate status disconnected and reload the back-end and the RM daemon.
255 kill(getpid(), SIGHUP);
256 ret = MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
258 g_array_free(cb_requests, TRUE);
263 void _mmrm_dmn_status_callback(mm_resource_manager_status_e status)
265 _mmrm_dmn_dbus_status_callback(status);
268 static void __destroy_resource(mm_resource_manager_dmn_res_p res)
274 g_array_free(res->parts, TRUE);
279 static void __destroy_manager(void *m)
281 mm_resource_manager_dmn_p mgr = (mm_resource_manager_dmn_p) m;
284 MM_RM_RETM_IF(mgr == NULL, "NULL pointer");
286 for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++)
287 __destroy_resource(mgr->resources[i]);
292 static int __search_manager_index(mm_resource_manager_id id)
296 for (i = managers->len - 1; i >= 0; i--) {
297 if (((mm_resource_manager_dmn_p)managers->pdata[i])->id == id)
301 return MM_RESOURCE_MANGER_NOT_FOUND;
304 static inline mm_resource_manager_dmn_p __search_manager(mm_resource_manager_id id)
306 int i = __search_manager_index(id);
307 return i == MM_RESOURCE_MANGER_NOT_FOUND ? NULL : managers->pdata[i];
310 static mm_resource_manager_error_e __check_release_requests(mm_resource_manager_dmn_p manager,
311 mm_resource_manager_dmn_res_request_s *releases)
314 mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
315 mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
316 const char *res_name = NULL;
318 MM_RM_RETVM_IF(conf == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "conf is null");
319 MM_RM_RETVM_IF(releases == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "requests is null");
321 for (; releases->type != MM_RESOURCE_MANAGER_NO_RES; releases++) {
323 type = releases->type;
324 res_name = _mm_resource_manager_get_res_str(type);
326 MM_RM_RETVM_IF(manager->resources[type] == NULL,
327 MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED, "There is no resource %s for the platform", res_name);
329 if (manager->resources[type]->state == MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED) {
330 if (manager->resources[type]->parts == NULL) {
331 if (releases->volume != MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
332 MM_RM_ERROR("Resource %s is acquired fully, but a resource part is tried to be released", res_name);
333 return MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER;
336 for (i = 0; i < manager->resources[type]->parts->len &&
337 ((mm_resource_manager_res_volume*)manager->resources[type]->parts->data)[i] != releases->volume; i++);
338 if (i == manager->resources[type]->parts->len) {
339 MM_RM_ERROR("Part of %s of volume %d is not acquired", res_name, releases->volume);
340 return MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER;
344 MM_RM_ERROR("Resource %s is not acquired", res_name);
345 return MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER;
347 MM_RM_DEBUG("Release requests are OK type %s available volume %d", res_name, conf->max_volume[type]);
350 return MM_RESOURCE_MANAGER_ERROR_NONE;
353 static mm_resource_manager_dmn_res_request_s *__create_dmn_res_requests(
354 mm_resource_manager_dmn_res_request_s *releases, mm_resource_manager_dmn_res_request_s *acquires)
358 mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
359 mm_resource_manager_dmn_res_request_s *result = NULL;
360 mm_resource_manager_dmn_res_request_s *result_iter = NULL;
361 mm_resource_manager_res_volume resources[MM_RESOURCE_MANAGER_RES_TYPE_MAX] = { 0 };
363 MM_RM_RETVM_IF(conf == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "conf is null");
365 for (; acquires->type != MM_RESOURCE_MANAGER_NO_RES; acquires++) {
367 if ((resources[acquires->type] > 0 || resources[acquires->type] == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) &&
368 acquires->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
369 MM_RM_ERROR("The client tries to acquire %s by part and fully at once", _mm_resource_manager_get_res_str(acquires->type));
373 if (acquires->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
374 resources[acquires->type] = MM_RESOURCE_MANAGER_RES_VOLUME_FULL;
376 if (conf->max_volume[acquires->type] > 1)
377 resources[acquires->type] += acquires->volume;
379 resources[acquires->type]++;
382 MM_RM_DEBUG("(type, vol) = (%d, %d)", acquires->type, resources[acquires->type]);
385 for (; releases->type != MM_RESOURCE_MANAGER_NO_RES; releases++) {
386 if (resources[releases->type] > 1) {
387 resources[releases->type] += releases->volume;
388 MM_RM_INFO("type %s available volume %d", _mm_resource_manager_get_res_str(releases->type), resources[releases->type]);
392 for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++)
393 if (resources[i] > 0 || resources[i] == MM_RESOURCE_MANAGER_RES_VOLUME_FULL)
396 result_iter = result = g_new0(mm_resource_manager_dmn_res_request_s, result_len);
397 for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++) {
398 if (resources[i] > 0 || resources[i] == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
399 result_iter->type = i;
400 result_iter->volume = resources[i];
404 result_iter->type = MM_RESOURCE_MANAGER_NO_RES;
409 static mm_resource_manager_error_e __check_requests_conflict(mm_resource_manager_dmn_p manager,
410 mm_resource_manager_dmn_res_request_s *requests)
412 mm_resource_manager_res_volume remaining_volume;
413 mm_resource_manager_dmn_p i_mgr;
414 mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
416 mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
417 const char *res_name = NULL;
419 MM_RM_RETVM_IF(conf == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "conf is null");
420 MM_RM_RETVM_IF(manager == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "manager is null");
421 MM_RM_RETVM_IF(requests == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "requests is null");
425 for (; requests->type != MM_RESOURCE_MANAGER_NO_RES; requests++) {
426 type = requests->type;
427 res_name = _mm_resource_manager_get_res_str(type);
429 MM_RM_RETVM_IF(type < MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER || type >= MM_RESOURCE_MANAGER_RES_TYPE_MAX,
430 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "wrong type %s", res_name);
431 MM_RM_RETVM_IF(manager->resources[type] == NULL, MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED,
432 "There is no resource %s for the platform", res_name);
434 remaining_volume = conf->max_volume[type];
436 for (i = 0; i < len; i++) {
437 i_mgr = (mm_resource_manager_dmn_p)managers->pdata[i];
439 if (i_mgr != manager && conf->priority[i_mgr->app_class] > conf->priority[manager->app_class] &&
440 i_mgr->resources[type]->state == MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED) {
441 if (i_mgr->resources[type]->parts) {
442 if (requests->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
443 requests->priority_error = TRUE;
444 MM_RM_DEBUG("Resource conflict. Full volume is requested, but only part is available");
445 return MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY;
447 for (j = 0; j < i_mgr->resources[type]->parts->len; j++)
448 remaining_volume -= g_array_index(i_mgr->resources[type]->parts, mm_resource_manager_res_volume, j);
450 if (remaining_volume < requests->volume) {
451 requests->priority_error = TRUE;
452 MM_RM_DEBUG("Resource conflict. %d of %s are available, but %d required",
453 remaining_volume, res_name, requests->volume);
454 return MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY;
458 requests->priority_error = TRUE;
459 MM_RM_DEBUG("Resource conflict. %s is already acquired fully", res_name);
460 return MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY;
466 return MM_RESOURCE_MANAGER_ERROR_NONE;
469 static void __sync_increase_acquire_requests(mm_resource_manager_dmn_res_request_s *increases,
470 mm_resource_manager_dmn_res_request_s *acquires)
472 mm_resource_manager_dmn_res_request_s *increase_iter;
473 mm_resource_manager_dmn_res_request_s *acquire_iter;
475 for (increase_iter = increases; increase_iter->type != MM_RESOURCE_MANAGER_NO_RES; increase_iter++) {
476 for (acquire_iter = acquires; acquire_iter->type != MM_RESOURCE_MANAGER_NO_RES; acquire_iter++) {
477 if (acquire_iter->type == increase_iter->type)
478 acquire_iter->priority_error = increase_iter->priority_error;
483 static inline void __add_cb_request(GArray *cb_requests,mm_resource_manager_dmn_p mgr,
484 mm_resource_manager_res_type_e type, mm_resource_manager_res_volume volume)
486 mm_resource_manager_dmn_release_cb_request_s *cb_request;
488 g_array_set_size(cb_requests, cb_requests->len + 1);
489 cb_request = &g_array_index(cb_requests, mm_resource_manager_dmn_release_cb_request_s, cb_requests->len - 1);
491 cb_request->manager = mgr;
492 cb_request->type = type;
493 cb_request->volume = volume;
496 static GArray *__handle_acquire_requests(mm_resource_manager_dmn_p manager,
497 mm_resource_manager_dmn_res_request_s *requests)
499 mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
500 mm_resource_manager_res_volume acquired_volume = 0;
501 mm_resource_manager_dmn_p i_mgr = NULL, j_mgr = NULL;
502 const char *res_name = NULL;
503 GArray *cb_requests = NULL;
507 mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
508 mm_resource_manager_res_volume volume = MM_RESOURCE_MANAGER_RES_VOLUME_FULL;
510 MM_RM_RETVM_IF(conf == NULL, NULL, "conf is NULL");
511 MM_RM_RETVM_IF(requests == NULL, NULL, "requests is NULL");
513 cb_requests = g_array_sized_new(FALSE, FALSE, sizeof(mm_resource_manager_dmn_release_cb_request_s),
514 MM_RESOURCE_MANAGER_RESERVED_CALLBACK_ARRAY_SIZE);
516 for (; requests->type != MM_RESOURCE_MANAGER_NO_RES; requests++) {
517 type = requests->type;
518 res_name = _mm_resource_manager_get_res_str(type);
519 volume = requests->volume;
522 if (volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
523 MM_RM_DEBUG("Resource of %s is requested (mgr %p)", res_name, manager);
525 for (i = 0; i < managers->len; i++) {
526 i_mgr = (mm_resource_manager_dmn_p)managers->pdata[i];
528 if (manager->id == i_mgr->id || conf->priority[i_mgr->app_class] >conf->priority[manager->app_class]) {
529 i_mgr->resources[type]->state = MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED;
531 i_mgr->volume = volume;
533 MM_RM_DEBUG("[PID %d] Reset the value of acquire in RM #%"PRIu64" (type %s mgr %p)",
534 i_mgr->pid, _mm_rm_hash64(i_mgr->id), res_name, i_mgr);
535 if (conf->max_instance[type] > 0)
540 if ((res = i_mgr->resources[type]->parts)) { /* always null, which is no conflict case now */
541 for (j = 0; j < res->len; j++) {
542 __add_cb_request(cb_requests, i_mgr, type, g_array_index(res, mm_resource_manager_res_volume, j));
543 mm_resource_manager_backend_release(type);
545 g_array_free(res, TRUE);
546 i_mgr->resources[type]->parts = NULL;
548 MM_RM_WARNING("[PID %d] Resource of %s is conflicted in RM #%"PRIu64, i_mgr->pid, res_name, _mm_rm_hash64(i_mgr->id));
550 __add_cb_request(cb_requests, i_mgr, type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL);
552 mm_resource_manager_backend_release(type);
554 MM_RM_DEBUG("[PID %d] Resource %s will be released (%s state) in RM #%"PRIu64" available volume %d", i_mgr->pid, res_name,
555 res_state_str[i_mgr->resources[type]->state], _mm_rm_hash64(i_mgr->id), conf->max_volume[type]);
559 MM_RM_INFO("[managers len #%d] [%s #%d (max inst #%d)] [%d (max vol %d)] are requested",
560 managers->len, res_name, res_count[type] + 1, conf->max_instance[type], volume, conf->max_volume[type]);
562 if (conf->max_instance[type] > 0 && conf->max_instance[type] == res_count[type]) {
563 for (i= 0; i < managers->len; i++) {
564 i_mgr = (mm_resource_manager_dmn_p)managers->pdata[j];
565 res = i_mgr->resources[type]->parts;
567 if (res && i_mgr->resources[type]->state == MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED) {
568 MM_RM_INFO("[#%d] [#%d / #%d] will be released %s in RM #%"PRIu64,
569 managers->len, i + 1, res->len, res_name, _mm_rm_hash64(i_mgr->id));
571 __add_cb_request(cb_requests, i_mgr, type, g_array_index(res, mm_resource_manager_res_volume, 0));
573 mm_resource_manager_backend_release(type);
578 for (i = 0; i < managers->len; i++) {
579 i_mgr = (mm_resource_manager_dmn_p)managers->pdata[i];
580 res = i_mgr->resources[type]->parts;
582 if (manager->id == i_mgr->id || conf->priority[i_mgr->app_class] > conf->priority[manager->app_class]) {
584 if (conf->volume_would_be_checked[type]) {
585 if (i_mgr->resources[type]->state != MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED && conf->max_volume[type] >= 0) {
586 i_mgr->resources[type]->state = MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED;
588 i_mgr->volume = volume;
590 conf->max_volume[type] -= volume;
591 MM_RM_INFO("[type %s] - %d = %d", res_name, volume, conf->max_volume[type]);
594 if (conf->volume_would_be_checked[type] && conf->max_volume[type] < 0
595 && acquired_volume < volume) {
596 for (j = 0; j < managers->len; j++) {
597 j_mgr = (mm_resource_manager_dmn_p)managers->pdata[j];
598 res = j_mgr->resources[type]->parts;
600 if (j_mgr->resources[type]->state != MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED)
603 acquired_volume += g_array_index(res, mm_resource_manager_res_volume, 0);
604 MM_RM_INFO("[#%d] [#%d / #%d] There are %d units of %s in RM #%"PRIu64,
605 managers->len, j + 1, res->len, acquired_volume, res_name, _mm_rm_hash64(j_mgr->id));
607 __add_cb_request(cb_requests, j_mgr, type, g_array_index(res, mm_resource_manager_res_volume, 0));
609 mm_resource_manager_backend_release(type);
611 if (acquired_volume >= volume)
617 if (i_mgr->resources[type]->state == MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED)
620 i_mgr->resources[type]->state = MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED;
624 res = manager->resources[requests->type]->parts;
626 res = g_array_sized_new(FALSE, FALSE, sizeof(mm_resource_manager_res_volume),
627 MM_RESOURCE_MANAGER_RESERVED_PART_ARRAY_SIZE);
628 manager->resources[requests->type]->parts = res;
630 g_array_append_val(res, requests->volume);
633 manager->resources[type]->state = MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED;
634 mm_resource_manager_backend_acquire(type);
636 MM_RM_DEBUG("[PID %d] RM #%"PRIu64" (type %s mgr %p) is acquired", i_mgr->pid, _mm_rm_hash64(i_mgr->id), res_name, i_mgr);
642 static int __open_release_cb_sync_fd(void)
644 int fd = open(RELEASE_CB_SYNC_PATH, O_RDONLY | O_NONBLOCK);
645 MM_RM_RETVM_IF(fd == -1, fd, "[%s] open failed (%d)", RELEASE_CB_SYNC_PATH, errno);
647 MM_RM_DEBUG("[%d] opened %s", fd, RELEASE_CB_SYNC_PATH);
652 static void __close_release_cb_sync_fd(int fd)
654 MM_RM_RETM_IF(fd == -1, "[fd %d] invalid parameter", fd);
655 MM_RM_RETM_IF(close(fd) == -1, "[%s] close failed (%d)", RELEASE_CB_SYNC_PATH, errno);
657 MM_RM_DEBUG("[%d] closed %s", fd, RELEASE_CB_SYNC_PATH);
660 static gboolean __is_process_alive(int pid)
662 char path[PID_MSG_LEN];
664 snprintf(path, sizeof(path), "/proc/%d", pid);
666 return access(path, F_OK) == 0;
669 static void __handle_release_callbacks(GArray *requests)
674 mm_resource_manager_id id;
675 mm_resource_manager_dmn_release_cb_request_s *request;
676 mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
677 mm_resource_manager_res_volume volume = MM_RESOURCE_MANAGER_RES_VOLUME_FULL;
678 mm_resource_manager_dmn_p mgr = NULL;
679 const char *res_name = NULL;
680 mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
682 MM_RM_RETM_IF(requests == NULL, "requests is NULL");
683 MM_RM_RETM_IF(conf == NULL, "conf is NULL");
685 for (i = 0; i < requests->len; i++) {
686 request = &g_array_index(requests, mm_resource_manager_dmn_release_cb_request_s, i);
687 mgr = request->manager;
688 type = request->type;
689 res_name = _mm_resource_manager_get_res_str(type);
690 volume = request->volume;
692 if (mgr->resources[type]->state != MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED)
698 if (!__is_process_alive(pid)) {
699 MM_RM_ERROR("[PID %d] is already terminated", pid);
700 _mmrm_dmn_destroy(id);
706 if (mgr->type == type && mgr->volume == volume && mgr->resources[type]->state == MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE) {
707 MM_RM_WARNING("Resource (mgr %p) release callback is already invoked RM #%"PRIu64" for %s of volume %d",
708 mgr, id, res_name, volume);
712 /* Avoid to emit release callback of resource manager's other resource, which can be changed by release policy*/
713 if (conf->is_release_all && mgr->resources[type]->state == MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE) {
714 MM_RM_WARNING("Already sending release callback to [mgr %p] RM #%"PRIu64" for %s of volume %d", mgr, id, res_name, volume);
718 MM_RM_INFO("Sending release callback to [mgr %p] RM #%"PRIu64" for %s of volume %d", mgr, id, res_name, volume);
720 sync_fd = __open_release_cb_sync_fd();
721 MM_RM_RETM_IF(sync_fd == -1, "[%s] open failed", RELEASE_CB_SYNC_PATH);
723 _mmrm_dmn_dbus_release_callback(id, type, volume);
725 if (__wait_for_release_cb_sync(id, sync_fd)) {
726 MM_RM_INFO("[SYNC] Release callback success RM #%"PRIu64, id);
727 if (conf->volume_would_be_checked[type] && volume != MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
728 conf->max_volume[type] += volume;
729 MM_RM_DEBUG("type %s available volume + %d = %d", res_name, volume, conf->max_volume[type]);
732 if (conf->max_instance[type] > 0 && res_count[type] > 0) {
734 MM_RM_DEBUG("The number of type %s #%d", res_name, res_count[type]);
737 mgr->resources[type]->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE;
739 MM_RM_DEBUG("RM #%"PRIu64" (type %s mgr %p) set acquired value as state (%s)",
740 id, res_name, mgr, res_state_str[mgr->resources[type]->state]);
742 MM_RM_ERROR("Wait for release callback sync failed RM #%"PRIu64" (type %s)", id, res_name);
745 __close_release_cb_sync_fd(sync_fd);
749 static void __handle_release_requests(mm_resource_manager_dmn_p manager,
750 mm_resource_manager_dmn_res_request_s *requests)
754 mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
755 mm_resource_manager_res_volume volume = MM_RESOURCE_MANAGER_RES_VOLUME_FULL;
756 const char *res_name = NULL;
757 mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
759 MM_RM_RETM_IF(conf == NULL, "conf is NULL");
760 MM_RM_RETM_IF(requests == NULL, "requests is NULL");
762 for (; requests->type != MM_RESOURCE_MANAGER_NO_RES; requests++) {
764 type = requests->type;
765 res_name = _mm_resource_manager_get_res_str(type);
766 volume = requests->volume;
768 if (volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
769 manager->resources[type]->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE;
771 parts = manager->resources[type]->parts;
772 for (i = 0; i < parts->len && ((mm_resource_manager_res_volume*)parts->data)[i] != volume; i++);
774 g_array_remove_index_fast(parts, i);
776 if (parts->len == 0) {
777 g_array_free(parts, TRUE);
778 manager->resources[type]->parts = NULL;
779 manager->resources[type]->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE;
783 if (conf->volume_would_be_checked[type]) {
784 conf->max_volume[type] += volume;
785 MM_RM_INFO("[type %s] + %d = %d", res_name, volume, conf->max_volume[type]);
788 if (conf->max_instance[type] > 0 && res_count[type] > 0) {
790 MM_RM_INFO("The number of type %s #%d", res_name, res_count[type]);
793 mm_resource_manager_backend_release(type);
797 static void __destroy_all_resources(mm_resource_manager_dmn_p manager)
801 for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++) {
802 if (manager->resources[i] && manager->resources[i]->state == MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED) {
803 if (manager->resources[i]->parts) {
804 for (j = 0; j < manager->resources[i]->parts->len; j++)
805 mm_resource_manager_backend_release(i);
807 mm_resource_manager_backend_release(i);
809 manager->resources[i]->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE;
814 static gboolean __poll(struct pollfd sync, mm_resource_manager_id id)
820 while (try_cnt++ < 3) {
821 sync.events = POLLIN;
824 ret = poll(&sync, 1, RELEASE_CB_SYNC_TIMEOUT);
828 MM_RM_ERROR("[%d ms] Polling is failed [fd %d errno %d] RM #%"PRIu64" revents : 0x%x",
829 RELEASE_CB_SYNC_TIMEOUT, sync.fd, errsv, id, sync.revents);
833 } else if (ret == 0) {
834 MM_RM_WARNING("Wait timeout [%d ms] is elapsed [fd %d] RM #%"PRIu64" revents : 0x%x",
835 RELEASE_CB_SYNC_TIMEOUT, sync.fd, id, sync.revents);
839 MM_RM_DEBUG("[fd %d] RM #%"PRIu64" revents : 0x%x", sync.fd, id, sync.revents);
846 static gboolean __wait_for_release_cb_sync(mm_resource_manager_id id, int sync_fd)
848 gboolean ret = FALSE;
849 struct pollfd sync = {0};
850 mm_resource_manager_id recv_id;
853 MM_RM_DEBUG("Enter %d", sync_fd);
855 MM_RM_RETVM_IF(sync_fd == -1, FALSE, "[sync_fd %d] invalid parameter", sync_fd);
859 if (!__poll(sync, id))
862 read_size = read(sync.fd, &recv_id, sizeof(recv_id));
863 if (read_size != sizeof(recv_id)) {
864 MM_RM_ERROR("Read is failed (revents=%hd, read_size=%zd)", sync.revents, read_size);
868 if (id != _mm_rm_hash64(recv_id))
869 MM_RM_WARNING("Sync is received from wrong client #%"PRIu64, id);
871 ret = __poll(sync, id);