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