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