04b1b0767a5c67efc1a3f30da6e93949b9852f1b
[platform/core/multimedia/mm-resource-manager.git] / src / daemon / mm_resource_manager_daemon_priv.c
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <glib.h>
18 #include <unistd.h>
19 #include <sys/stat.h>
20 #include <poll.h>
21 #include <inttypes.h>
22 #ifdef RM_GCOV_TEST
23 #include <gcov.h>
24 #endif
25
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"
31
32
33
34 #define MM_RESOURCE_MANAGER_RESERVED_RM_ARRAY_SIZE 64 /* preallocated size */
35 #define MM_RESOURCE_MANAGER_RESERVED_PART_ARRAY_SIZE 4 /* preallocated size */
36 #define MM_RESOURCE_MANAGER_RESERVED_CALLBACK_ARRAY_SIZE 32 /* preallocated size */
37 #define MM_RESOURCE_MANGER_NOT_FOUND -1
38 #define RELEASE_CB_SYNC_TIMEOUT 5 /* seconds */
39
40
41
42 typedef struct {
43         gboolean is_acquired;
44
45         /* NULL means, the resource is acquired fully or is not acquired at all */
46         GArray *parts;
47
48 } mm_resource_manager_dmn_res_s;
49 typedef mm_resource_manager_dmn_res_s *mm_resource_manager_dmn_res_p;
50
51 typedef struct {
52         mm_resource_manager_id id;
53         mm_resource_manager_app_class_e app_class;
54         mm_resource_manager_res_type_e type;
55         int volume;
56         /* if an element is NULL, there is no such a resource for the current platform. */
57         mm_resource_manager_dmn_res_p resources[MM_RESOURCE_MANAGER_RES_TYPE_MAX];
58
59 } mm_resource_manager_dmn_s;
60 typedef mm_resource_manager_dmn_s *mm_resource_manager_dmn_p;
61
62 typedef struct {
63         mm_resource_manager_dmn_p manager;
64         mm_resource_manager_res_type_e type;
65         mm_resource_manager_res_volume volume;
66 } mm_resource_manager_dmn_release_cb_request_s;
67
68
69
70 static GPtrArray *managers;
71 static int res_count[MM_RESOURCE_MANAGER_RES_TYPE_MAX];
72
73 static void __destroy_resource(mm_resource_manager_dmn_res_p res);
74 static void __destroy_manager(void *m);
75 static int __search_manager_index(mm_resource_manager_id id);
76 static inline mm_resource_manager_dmn_p __search_manager(mm_resource_manager_id id);
77 static mm_resource_manager_error_e __check_release_requests(
78                 mm_resource_manager_dmn_p manager,
79                 mm_resource_manager_dmn_res_request_s *releases);
80 static mm_resource_manager_dmn_res_request_s *__create_dmn_res_requests(
81                 mm_resource_manager_dmn_res_request_s *releases,
82                 mm_resource_manager_dmn_res_request_s *acquires);
83 static mm_resource_manager_error_e __check_requests_conflict(
84                 mm_resource_manager_dmn_p manager,
85                 mm_resource_manager_dmn_res_request_s *requests);
86 static void __sync_increase_acquire_requests(
87                 mm_resource_manager_dmn_res_request_s *increases,
88                 mm_resource_manager_dmn_res_request_s *acquires);
89 static void __handle_release_requests(mm_resource_manager_dmn_p manager,
90                 mm_resource_manager_dmn_res_request_s *requests);
91 static GArray* __handle_acquire_requests(mm_resource_manager_dmn_p manager,
92                 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 __release_all_resources(mm_resource_manager_dmn_s *manager);
97 static gboolean __poll(struct pollfd sync);
98 static gboolean __wait_for_release_cb_sync(mm_resource_manager_id id);
99
100
101
102
103 gboolean _mmrm_dmn_init(void)
104 {
105         unlink(RELEASE_CB_SYNC_PATH);
106         MM_RM_RETVM_IF(mkfifo(RELEASE_CB_SYNC_PATH,
107                         S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IWOTH) == -1, FALSE,
108                         "Release callback sync cannot be created");
109
110         MM_RM_RETVM_IF(mm_resource_manager_backend_init() !=
111                         MM_RESOURCE_MANAGER_ERROR_NONE, FALSE,
112                         "Back-end cannot be initialized");
113
114         if (_mmrm_dmn_dbus_init() != MM_RESOURCE_MANAGER_ERROR_NONE) {
115                 mm_resource_manager_backend_deinit();
116                 MM_RM_ERROR("D-bus server cannot be created");
117                 return FALSE;
118         }
119
120         managers = g_ptr_array_new_full(MM_RESOURCE_MANAGER_RESERVED_RM_ARRAY_SIZE,
121                         __destroy_manager);
122         MM_RM_RETVM_IF(managers == NULL, FALSE, "Daemon cannot be initialized");
123
124         return TRUE;
125 }
126
127 gboolean _mmrm_dmn_deinit()
128 {
129         int i;
130
131         if (mm_resource_manager_backend_deinit() != MM_RESOURCE_MANAGER_ERROR_NONE)
132                 MM_RM_ERROR("Error during back-end deinitialization");
133
134         if (_mmrm_dmn_dbus_deinit() != MM_RESOURCE_MANAGER_ERROR_NONE)
135                 MM_RM_ERROR("Error during d-bus server shutdown");
136
137         if (managers) {
138                 for (i = 0; i < managers->len; i++)
139                         __release_all_resources((mm_resource_manager_dmn_p)managers->pdata[i]);
140
141                 mm_resource_manager_backend_commit_all();
142                 g_ptr_array_free(managers, TRUE);
143         } else {
144                 MM_RM_ERROR("Trying to deinit uninitialized daemon");
145         }
146
147         if (unlink(RELEASE_CB_SYNC_PATH) == -1)
148                 MM_RM_ERROR("Release callback sync cannot be removed");
149
150         return TRUE;
151 }
152
153 mm_resource_manager_error_e _mmrm_dmn_create(
154                 mm_resource_manager_app_class_e app_class, mm_resource_manager_id *id)
155 {
156         mm_resource_manager_dmn_p mgr;
157         mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
158         int i;
159
160         MM_RM_RETVM_IF(app_class < 0 ||
161                         app_class >= MM_RESOURCE_MANAGER_APP_CLASS_MAX,
162                         MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "Wrong app class");
163
164         MM_RM_RETVM_IF(conf->priority[app_class] ==
165                         MM_RESOURCE_MANAGER_NO_APP_CLASS,
166                         MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
167                         "App class is not supported for the platform");
168
169         mgr = g_new0(mm_resource_manager_dmn_s, 1);
170         MM_RM_RAND64(mgr->id);
171         mgr->app_class = app_class;
172         for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++) {
173                 mgr->resources[i] = conf->max_volume[i] == MM_RESOURCE_MANAGER_NO_RES ?
174                                 NULL : g_malloc0(sizeof(mm_resource_manager_dmn_s));
175         }
176
177         g_ptr_array_add(managers, mgr);
178
179         MM_RM_INFO("managers length %d", managers->len);
180
181         *id = mgr->id;
182
183         return MM_RESOURCE_MANAGER_ERROR_NONE;
184 }
185
186 mm_resource_manager_error_e _mmrm_dmn_destroy(mm_resource_manager_id id)
187 {
188         int idx = __search_manager_index(id);
189         mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
190         mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
191         mm_resource_manager_dmn_p i_mgr = __search_manager(id);
192
193         MM_RM_RETVM_IF(idx == MM_RESOURCE_MANGER_NOT_FOUND, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
194                         "Resource manager #%"PRIu64" doesn't exist", _mm_rm_hash64(id));
195         MM_RM_RETVM_IF(conf == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "conf is null");
196
197         i_mgr = (mm_resource_manager_dmn_p)managers->pdata[idx];
198
199         __release_all_resources((mm_resource_manager_dmn_s *)managers->pdata[idx]);
200         mm_resource_manager_backend_commit_all();
201
202         g_ptr_array_remove_index_fast(managers, idx);
203
204         type = i_mgr->type;
205
206         MM_RM_INFO("managers length #%d type %d available volume %d", managers->len, type, conf->max_volume[type]);
207
208 #ifdef RM_GCOV_TEST
209         __gcov_flush();
210 #endif
211
212         return MM_RESOURCE_MANAGER_ERROR_NONE;
213 }
214
215 mm_resource_manager_error_e _mmrm_dmn_commit(mm_resource_manager_id id,
216                 mm_resource_manager_dmn_res_request_s *releases,
217                 mm_resource_manager_dmn_res_request_s *acquires)
218 {
219         mm_resource_manager_dmn_p manager = __search_manager(id);
220         mm_resource_manager_error_e ret = MM_RESOURCE_MANAGER_ERROR_NONE;
221         mm_resource_manager_dmn_res_request_s *increases = NULL;
222         GArray *cb_requests;
223
224         MM_RM_RETVM_IF(manager == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
225                         "Resource manager #%"PRIu64" doesn't exist", _mm_rm_hash64(id));
226         MM_RM_RETVM_IF(
227                         (releases == NULL || releases[0].type == MM_RESOURCE_MANAGER_NO_RES) &&
228                         (acquires == NULL || acquires[0].type == MM_RESOURCE_MANAGER_NO_RES),
229                         MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "Commit request is empty");
230
231         ret = __check_release_requests(manager, releases);
232         MM_RM_RETVM_IF(ret != MM_RESOURCE_MANAGER_ERROR_NONE, ret,
233                 "check_release_requests is failed [0x%x]", ret);
234
235         increases = __create_dmn_res_requests(releases, acquires);
236         MM_RM_RETVM_IF(increases == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
237                 "create_increase_requests is failed");
238
239         ret = __check_requests_conflict(manager, increases);
240         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
241                 __sync_increase_acquire_requests(increases, acquires);
242                 g_free(increases);
243                 return ret;
244         }
245         g_free(increases);
246
247         __handle_release_requests(manager, releases);
248         cb_requests = __handle_acquire_requests(manager, acquires);
249         MM_RM_RETVM_IF(cb_requests == NULL, MM_RESOURCE_MANAGER_ERROR_NOT_ENOUGH,
250                         "not enough free resource volume");
251         __handle_release_callbacks(cb_requests);
252         if (!mm_resource_manager_backend_commit_all()) {
253                 /*
254                  * The commit_all
255                  * function can fail only if resource management back-end is not solely
256                  * used by mm-resource-manager or if the back-end cannot acquire/release
257                  * a resource because of some internal error.
258                  *
259                  * Initiate status disconnected and reload the back-end and the RM
260                  * daemon.
261                  */
262                 kill(getpid(), SIGHUP);
263                 ret = MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
264         }
265         g_array_free(cb_requests, TRUE);
266
267         return ret;
268 }
269
270 void _mmrm_dmn_status_callback(mm_resource_manager_status_e status)
271 {
272         _mmrm_dmn_dbus_status_callback(status);
273 }
274
275 static void __destroy_resource(mm_resource_manager_dmn_res_p res)
276 {
277         if (res == NULL)
278                 return;
279
280         if (res->parts)
281                 g_array_free(res->parts, TRUE);
282
283         g_free(res);
284 }
285
286 static void __destroy_manager(void *m)
287 {
288         mm_resource_manager_dmn_p mgr = (mm_resource_manager_dmn_p) m;
289         int i;
290
291         MM_RM_RETM_IF(mgr == NULL, "NULL pointer");
292
293         for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++)
294                 __destroy_resource(mgr->resources[i]);
295
296         g_free(mgr);
297 }
298
299 static int __search_manager_index(mm_resource_manager_id id)
300 {
301         int i;
302
303         for (i = managers->len - 1; i >= 0; i--) {
304                 if (((mm_resource_manager_dmn_p)managers->pdata[i])->id == id)
305                         return i;
306         }
307
308         return MM_RESOURCE_MANGER_NOT_FOUND;
309 }
310
311 static inline mm_resource_manager_dmn_p __search_manager(mm_resource_manager_id id)
312 {
313         int i = __search_manager_index(id);
314         return i == MM_RESOURCE_MANGER_NOT_FOUND ? NULL : managers->pdata[i];
315 }
316
317 static mm_resource_manager_error_e __check_release_requests(mm_resource_manager_dmn_p manager,
318                         mm_resource_manager_dmn_res_request_s *releases)
319 {
320         int i;
321         mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
322         mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
323
324         MM_RM_RETVM_IF(conf == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "conf is null");
325         MM_RM_RETVM_IF(releases == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "requests is null");
326
327         for (; releases->type != MM_RESOURCE_MANAGER_NO_RES; releases++) {
328
329                 type = releases->type;
330                 const char *type_s = _mm_resource_manager_get_res_str(type);
331
332                 MM_RM_RETVM_IF(manager->resources[type] == NULL,
333                         MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED, "There is no resource %s for the platform", type_s);
334
335                 if (manager->resources[type]->is_acquired) {
336                         if (manager->resources[type]->parts == NULL) {
337                                 if (releases->volume != MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
338                                         MM_RM_ERROR("Resource %s is acquired fully, but a resource part is tried to be released", type_s);
339                                         return MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER;
340                                 }
341                         } else {
342                                 for (i = 0; i < manager->resources[type]->parts->len &&
343                                         ((mm_resource_manager_res_volume*)manager->resources[type]->parts->data)[i] != releases->volume; i++);
344                                 if (i == manager->resources[type]->parts->len) {
345                                         MM_RM_ERROR("Part of %s of volume %d is not acquired", type_s, releases->volume);
346                                         return MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER;
347                                 }
348                         }
349                 } else {
350                         MM_RM_ERROR("Resource %s is not acquired", type_s);
351                         return MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER;
352                 }
353                 MM_RM_DEBUG("Release requests are OK type %d available volume %d", type, conf->max_volume[type]);
354         }
355
356         return MM_RESOURCE_MANAGER_ERROR_NONE;
357 }
358
359 static mm_resource_manager_dmn_res_request_s *__create_dmn_res_requests(
360                 mm_resource_manager_dmn_res_request_s *releases, mm_resource_manager_dmn_res_request_s *acquires)
361 {
362         int i;
363         int result_len = 1;
364         mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
365         mm_resource_manager_dmn_res_request_s *result = NULL;
366         mm_resource_manager_dmn_res_request_s *result_iter = NULL;
367         mm_resource_manager_res_volume resources[MM_RESOURCE_MANAGER_RES_TYPE_MAX] = { 0 };
368
369         MM_RM_RETVM_IF(conf == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "conf is null");
370
371         for (; acquires->type != MM_RESOURCE_MANAGER_NO_RES; acquires++) {
372
373                 if ((resources[acquires->type] > 0 || resources[acquires->type] == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) &&
374                         acquires->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
375                         MM_RM_ERROR("The client tries to acquire %s by part and fully at once",
376                                         _mm_resource_manager_get_res_str(acquires->type));
377                         return NULL;
378                 }
379
380                 if (acquires->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
381                         resources[acquires->type] = MM_RESOURCE_MANAGER_RES_VOLUME_FULL;
382                 } else {
383                         if (conf->max_volume[acquires->type] > 1)
384                                 resources[acquires->type] += acquires->volume;
385                         else
386                                 resources[acquires->type]++;
387                 }
388
389                 MM_RM_DEBUG("(type, vol) = (%d, %d)", acquires->type, resources[acquires->type]);
390         }
391
392         for (; releases->type != MM_RESOURCE_MANAGER_NO_RES; releases++) {
393                 if (resources[releases->type] > 1) {
394                         resources[releases->type] += releases->volume;
395                         MM_RM_INFO("type %d available volume %d", releases->type, resources[releases->type]);
396                 }
397         }
398
399         for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++)
400                 if (resources[i] > 0 || resources[i] == MM_RESOURCE_MANAGER_RES_VOLUME_FULL)
401                         result_len++;
402
403         result_iter = result = g_new0(mm_resource_manager_dmn_res_request_s, result_len);
404         for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++) {
405                 if (resources[i] > 0 || resources[i] == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
406                         result_iter->type = i;
407                         result_iter->volume = resources[i];
408                         result_iter++;
409                 }
410         }
411         result_iter->type = MM_RESOURCE_MANAGER_NO_RES;
412
413         return result;
414 }
415
416 static mm_resource_manager_error_e __check_requests_conflict(mm_resource_manager_dmn_p manager,
417                         mm_resource_manager_dmn_res_request_s *requests)
418 {
419         mm_resource_manager_res_volume remaining_volume;
420         mm_resource_manager_dmn_p i_mgr;
421         mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
422         int i, j, len;
423         mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
424
425         MM_RM_RETVM_IF(conf == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "conf is null");
426         MM_RM_RETVM_IF(manager == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "manager is null");
427         MM_RM_RETVM_IF(requests == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "requests is null");
428
429         len = managers->len;
430
431         for (; requests->type != MM_RESOURCE_MANAGER_NO_RES; requests++) {
432                 type = requests->type;
433                 const char *type_s = _mm_resource_manager_get_res_str(type);
434
435                 MM_RM_RETVM_IF(type < MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER ||
436                                 type >= MM_RESOURCE_MANAGER_RES_TYPE_MAX,
437                                 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
438                                 "wrong type %d", type);
439                 MM_RM_RETVM_IF(manager->resources[type] == NULL,
440                                 MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED,
441                                 "There is no resource %s for the platform", type_s);
442
443                 remaining_volume = conf->max_volume[type];
444
445                 for (i = 0; i < len; i++) {
446                         i_mgr = (mm_resource_manager_dmn_p)managers->pdata[i];
447
448                         if (i_mgr != manager && conf->priority[i_mgr->app_class] > conf->priority[manager->app_class] &&
449                                 i_mgr->resources[type]->is_acquired) {
450                                 if (i_mgr->resources[type]->parts) {
451                                         if (requests->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
452                                                 requests->priority_error = TRUE;
453                                                 MM_RM_DEBUG("Resource conflict. Full volume is requested, but only part is available");
454                                                 return MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY;
455                                         } else {
456                                                 for (j = 0; j < i_mgr->resources[type]->parts->len; j++)
457                                                         remaining_volume -= g_array_index(i_mgr->resources[type]->parts,
458                                                                                                 mm_resource_manager_res_volume, j);
459
460                                                 if (remaining_volume < requests->volume) {
461                                                         requests->priority_error = TRUE;
462                                                         MM_RM_DEBUG("Resource conflict. %d of %s are available, but %d required",
463                                                                         remaining_volume, type_s, requests->volume);
464                                                         return MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY;
465                                                 }
466                                         }
467                                 } else {
468                                         requests->priority_error = TRUE;
469                                         MM_RM_DEBUG("Resource conflict. %s is already acquired fully", type_s);
470                                         return MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY;
471                                 }
472                         }
473                 }
474         }
475
476         return MM_RESOURCE_MANAGER_ERROR_NONE;
477 }
478
479 static void __sync_increase_acquire_requests(mm_resource_manager_dmn_res_request_s *increases,
480                         mm_resource_manager_dmn_res_request_s *acquires)
481 {
482         mm_resource_manager_dmn_res_request_s *increase_iter;
483         mm_resource_manager_dmn_res_request_s *acquire_iter;
484
485         for (increase_iter = increases; increase_iter->type != MM_RESOURCE_MANAGER_NO_RES; increase_iter++) {
486                 for (acquire_iter = acquires; acquire_iter->type != MM_RESOURCE_MANAGER_NO_RES; acquire_iter++) {
487                         if (acquire_iter->type == increase_iter->type)
488                                 acquire_iter->priority_error = increase_iter->priority_error;
489                 }
490         }
491 }
492
493 static inline void __add_cb_request(GArray *cb_requests,mm_resource_manager_dmn_p mgr,
494                         mm_resource_manager_res_type_e type, mm_resource_manager_res_volume volume)
495 {
496         mm_resource_manager_dmn_release_cb_request_s *cb_request;
497
498         g_array_set_size(cb_requests, cb_requests->len + 1);
499         cb_request = &g_array_index(cb_requests, mm_resource_manager_dmn_release_cb_request_s, cb_requests->len - 1);
500
501         cb_request->manager = mgr;
502         cb_request->type = type;
503         cb_request->volume = volume;
504 }
505
506 static GArray *__handle_acquire_requests(mm_resource_manager_dmn_p manager,
507                 mm_resource_manager_dmn_res_request_s *requests)
508 {
509         mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
510         mm_resource_manager_res_volume acquired_volume = 0;
511         mm_resource_manager_dmn_p i_mgr = NULL, j_mgr = NULL;
512         const char *res_name = NULL;
513         GArray *cb_requests = NULL;
514         GArray *res = NULL;
515         int i = 0, j = 0;
516         mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
517         mm_resource_manager_res_volume volume = MM_RESOURCE_MANAGER_RES_VOLUME_FULL;
518
519         MM_RM_RETVM_IF(conf == NULL, NULL, "conf is NULL");
520         MM_RM_RETVM_IF(requests == NULL, NULL, "requests is NULL");
521
522         cb_requests = g_array_sized_new(FALSE, FALSE, sizeof(mm_resource_manager_dmn_release_cb_request_s),
523                         MM_RESOURCE_MANAGER_RESERVED_CALLBACK_ARRAY_SIZE);
524
525         for (; requests->type != MM_RESOURCE_MANAGER_NO_RES; requests++) {
526                 type = requests->type;
527                 res_name = _mm_resource_manager_get_res_str(type);
528                 volume = requests->volume;
529
530                 if (volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
531                         MM_RM_DEBUG("Resource of %s is requested (mgr %p)", res_name, manager);
532
533                         for (i = 0; i < managers->len; i++) {
534                                 i_mgr = (mm_resource_manager_dmn_p)managers->pdata[i];
535
536                                 if (manager->id == i_mgr->id || conf->priority[i_mgr->app_class] >conf->priority[manager->app_class]) {
537                                         i_mgr->resources[type]->is_acquired = TRUE;
538                                         i_mgr->type = type;
539                                         i_mgr->volume = volume;
540                                         MM_RM_INFO("Reset the value of release in RM %"PRIu64" (mgr %p)", _mm_rm_hash64(i_mgr->id), i_mgr);
541                                         if (conf->max_instance[type] > 0)
542                                                 res_count[type]++;
543                                         continue;
544                                 }
545
546                                 if ((res = i_mgr->resources[type]->parts)) { /* always null, which is no conflict case now */
547                                         for (j = 0; j < res->len; j++) {
548                                                 __add_cb_request(cb_requests, i_mgr, type, g_array_index(res, mm_resource_manager_res_volume, j));
549                                                 mm_resource_manager_backend_release(type);
550                                         }
551                                         g_array_free(res, TRUE);
552                                         i_mgr->resources[type]->parts = NULL;
553
554                                         MM_RM_WARNING("Resource of %s is conflicted in RM %"PRIu64, res_name, _mm_rm_hash64(i_mgr->id));
555                                 } else {
556                                         __add_cb_request(cb_requests, i_mgr, type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL);
557
558                                         mm_resource_manager_backend_release(type);
559
560                                         MM_RM_INFO("Resource %s is released (%d) in RM %"PRIu64" available volume %d", res_name,
561                                                 i_mgr->resources[type]->is_acquired, _mm_rm_hash64(i_mgr->id), conf->max_volume[type]);
562                                 }
563                         }
564                 } else {
565                         MM_RM_INFO("[managers len #%d] [%s #%d (max inst #%d)] [%d (max vol %d) units of %s] are requested",
566                                 managers->len, _mm_resource_manager_get_res_str(type), res_count[type] + 1,
567                                 conf->max_instance[type], volume, conf->max_volume[type], res_name);
568
569                         if (conf->max_instance[type] > 0 && conf->max_instance[type] == res_count[type]) {
570                                 for (i= 0; i < managers->len; i++) {
571                                         i_mgr = (mm_resource_manager_dmn_p)managers->pdata[j];
572                                         res = i_mgr->resources[type]->parts;
573
574                                         if (res && i_mgr->resources[type]->is_acquired) {
575                                                 MM_RM_INFO("[#%d] [#%d / #%d] would be released %s in RM %"PRIu64,
576                                                 managers->len, i + 1, res->len, res_name, _mm_rm_hash64(i_mgr->id));
577
578                                                 __add_cb_request(cb_requests, i_mgr, type, g_array_index(res, mm_resource_manager_res_volume, 0));
579
580                                                 mm_resource_manager_backend_release(type);
581                                                 break;
582                                         }
583                                 }
584                         } else {
585                                 for (i = 0; i < managers->len; i++) {
586                                         i_mgr = (mm_resource_manager_dmn_p)managers->pdata[i];
587                                         res = i_mgr->resources[type]->parts;
588
589                                         if (manager->id == i_mgr->id || conf->priority[i_mgr->app_class] > conf->priority[manager->app_class]) {
590
591                                                 if (conf->volume_would_be_checked[type]) {
592                                                         if (!i_mgr->resources[type]->is_acquired && conf->max_volume[type] >= 0) {
593                                                                 i_mgr->resources[type]->is_acquired = TRUE;
594                                                                 i_mgr->type = type;
595                                                                 i_mgr->volume = volume;
596                                                                 conf->max_volume[type] -= volume;
597                                                                 MM_RM_INFO("[type %d] - %d = %d", type, volume, conf->max_volume[type]);
598                                                         }
599
600                                                         if (conf->volume_would_be_checked[type] && conf->max_volume[type] < 0
601                                                                 && acquired_volume < volume) {
602                                                                 for (j = 0; j < managers->len; j++) {
603                                                                         j_mgr = (mm_resource_manager_dmn_p)managers->pdata[j];
604                                                                         res = j_mgr->resources[type]->parts;
605
606                                                                         if (!j_mgr->resources[type]->is_acquired)
607                                                                                 continue;
608
609                                                                         acquired_volume += g_array_index(res, mm_resource_manager_res_volume, 0);
610                                                                         MM_RM_INFO("[#%d] [#%d / #%d] There are %d units of %s in RM %"PRIu64,
611                                                                                 managers->len, j + 1, res->len, acquired_volume, res_name, _mm_rm_hash64(j_mgr->id));
612
613                                                                         __add_cb_request(cb_requests, j_mgr, type, g_array_index(res, mm_resource_manager_res_volume, 0));
614
615                                                                         mm_resource_manager_backend_release(type);
616
617                                                                         if (acquired_volume >= volume)
618                                                                                 break;
619                                                                 }
620                                                         }
621                                                 }
622
623                                                 if (i_mgr->resources[type]->is_acquired)
624                                                         res_count[type]++;
625
626                                                 i_mgr->resources[type]->is_acquired = TRUE;
627                                         }
628                                 }
629
630                                 res = manager->resources[requests->type]->parts;
631                                 if (!res) {
632                                         res = g_array_sized_new(FALSE, FALSE, sizeof(mm_resource_manager_res_volume),
633                                                 MM_RESOURCE_MANAGER_RESERVED_PART_ARRAY_SIZE);
634                                         manager->resources[requests->type]->parts = res;
635                                 }
636                                 g_array_append_val(res, requests->volume);
637                         }
638                 }
639
640                 manager->resources[type]->is_acquired = TRUE;
641                 mm_resource_manager_backend_acquire(type);
642         }
643
644         return cb_requests;
645 }
646
647 static void __handle_release_callbacks(GArray *requests)
648 {
649         int i;
650         mm_resource_manager_id id;
651         mm_resource_manager_dmn_release_cb_request_s *request;
652         mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
653         mm_resource_manager_res_volume volume = MM_RESOURCE_MANAGER_RES_VOLUME_FULL;
654         mm_resource_manager_dmn_p mgr = NULL;
655         mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
656
657         MM_RM_RETM_IF(requests == NULL, "requests is NULL");
658         MM_RM_RETM_IF(conf == NULL, "conf is NULL");
659
660         for (i = 0; i < requests->len; i++) {
661                 request = &g_array_index(requests, mm_resource_manager_dmn_release_cb_request_s, i);
662                 mgr = request->manager;
663                 type = request->type;
664                 volume = request->volume;
665
666                 if (!mgr->resources[type]->is_acquired)
667                         continue;
668
669                 id = mgr->id;
670                 MM_RM_HASH64(id);
671
672                 if (mgr->type == type && mgr->volume == volume && !mgr->resources[type]->is_acquired) {
673                         MM_RM_WARNING("Resource (mgr %p) release callback is already completed RM #%"PRIu64" for %s of volume %d",
674                                 mgr, id, _mm_resource_manager_get_res_str(type), volume);
675                         continue;
676                 }
677
678                 MM_RM_INFO("Sending release callback to [mgr %p] RM #%"PRIu64" for %s of volume %d",
679                                 mgr, id, _mm_resource_manager_get_res_str(type), volume);
680
681                 _mmrm_dmn_dbus_release_callback(id, type, volume);
682                 if (__wait_for_release_cb_sync(id))
683                         MM_RM_DEBUG("Release callback sync success");
684                 else
685                         MM_RM_ERROR("Wait for release callback sync failed");
686
687                 if (conf->volume_would_be_checked[type] && volume != MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
688                         conf->max_volume[type] += volume;
689                         MM_RM_INFO("type %d available volume + %d = %d", type, volume, conf->max_volume[type]);
690                 }
691
692                 if (conf->max_instance[type] > 0 && res_count[type] > 0) {
693                         res_count[type]--;
694                         MM_RM_INFO("The number of type %d #%d", type, res_count[type]);
695                 }
696
697                 mgr->resources[type]->is_acquired = FALSE;
698         }
699 }
700
701 static void __handle_release_requests(mm_resource_manager_dmn_p manager,
702                 mm_resource_manager_dmn_res_request_s *requests)
703 {
704         GArray *parts;
705         int i;
706         mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
707         mm_resource_manager_res_volume volume = MM_RESOURCE_MANAGER_RES_VOLUME_FULL;
708         mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
709
710         MM_RM_RETM_IF(conf == NULL, "conf is NULL");
711         MM_RM_RETM_IF(requests == NULL, "requests is NULL");
712
713         for (; requests->type != MM_RESOURCE_MANAGER_NO_RES; requests++) {
714
715                 type = requests->type;
716                 volume = requests->volume;
717
718                 if (volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
719                         manager->resources[type]->is_acquired = FALSE;
720                 } else {
721                         parts = manager->resources[type]->parts;
722                         for (i = 0; i < parts->len && ((mm_resource_manager_res_volume*)parts->data)[i] != volume; i++);
723
724                         g_array_remove_index_fast(parts, i);
725
726                         if (parts->len == 0) {
727                                 g_array_free(parts, TRUE);
728                                 manager->resources[type]->parts = NULL;
729                                 manager->resources[type]->is_acquired = FALSE;
730                         }
731                 }
732
733                 if (conf->volume_would_be_checked[type]) {
734                         conf->max_volume[type] += volume;
735                         MM_RM_INFO("[type %d] + %d = %d", type, volume, conf->max_volume[type]);
736                 }
737
738                 if (conf->max_instance[type] > 0) {
739                         res_count[type]--;
740                         MM_RM_INFO("The number of type %d #%d", type, res_count[type]);
741                 }
742
743                 mm_resource_manager_backend_release(type);
744         }
745 }
746
747 static void __release_all_resources(mm_resource_manager_dmn_s *manager)
748 {
749         int i, j;
750
751         for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++) {
752                 if (manager->resources[i] && manager->resources[i]->is_acquired) {
753                         if (manager->resources[i]->parts) {
754                                 for (j = 0; j < manager->resources[i]->parts->len; j++)
755                                         mm_resource_manager_backend_release(i);
756                         } else {
757                                 mm_resource_manager_backend_release(i);
758                         }
759                         manager->resources[i]->is_acquired = FALSE;
760                 }
761         }
762 }
763
764 static gboolean __poll(struct pollfd sync)
765 {
766         int errsv = 0;
767         int try_cnt = 0;
768         int ret = 0;
769
770         while (try_cnt++ < 3) {
771                 sync.events = POLLIN;
772                 sync.revents = 0;
773
774                 ret = poll(&sync, 1, RELEASE_CB_SYNC_TIMEOUT * 1000);
775
776                 if (ret == -1) {
777                         errsv = errno;
778                         MM_RM_ERROR("Polling is failed [fd %d errno %d]", sync.fd, errsv);
779                         if (errsv == EAGAIN)
780                                 continue;
781                         break;
782                 } else if (ret == 0) {
783                         MM_RM_WARNING("Wait timeout is elapsed [fd %d]", sync.fd);
784                         break;
785                 }
786
787                 return TRUE;
788         }
789
790         return FALSE;
791 }
792
793 static gboolean __wait_for_release_cb_sync(mm_resource_manager_id id)
794 {
795         gboolean ret = FALSE;
796         struct pollfd sync = {0};
797         mm_resource_manager_id recv_id;
798         ssize_t read_size;
799
800         sync.fd = open(RELEASE_CB_SYNC_PATH, O_RDONLY | O_NONBLOCK);
801         MM_RM_RETVM_IF(sync.fd == -1, FALSE, "Sync FIFO cannot be opened");
802
803         if (!__poll(sync))
804                 goto out;
805
806         read_size = read(sync.fd, &recv_id, sizeof(recv_id));
807         if (read_size != sizeof(recv_id)) {
808                 MM_RM_ERROR("Read is failed (revents=%hd, read_size=%zd)", sync.revents, read_size);
809                 goto out;
810         }
811
812         if (id != _mm_rm_hash64(recv_id)) {
813                 MM_RM_ERROR("Sync is received from wrong client #%"PRIu64, id);
814                 goto out;
815         }
816
817         ret = __poll(sync);
818
819 out:
820         close(sync.fd);
821
822         return ret;
823 }