Revise the coding rule and dlog of resource handle
[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
23 #include "daemon/mm_resource_manager_daemon_priv.h"
24 #include "daemon/mm_resource_manager_daemon_conf.h"
25 #include "daemon/mm_resource_manager_daemon_dbus.h"
26 #include "daemon/backend/mm_resource_manager_backend.h"
27 #include "common/mm_resource_manager_utils.h"
28
29
30
31 #define MM_RESOURCE_MANAGER_RESERVED_RM_ARRAY_SIZE 64 /* preallocated size */
32 #define MM_RESOURCE_MANAGER_RESERVED_PART_ARRAY_SIZE 4 /* preallocated size */
33 #define MM_RESOURCE_MANAGER_RESERVED_CALLBACK_ARRAY_SIZE 32 /* preallocated size */
34 #define MM_RESOURCE_MANGER_NOT_FOUND -1
35 #define RELEASE_CB_SYNC_TIMEOUT 5 /* seconds */
36
37
38
39 typedef struct {
40         gboolean is_acquired;
41
42         /* NULL means, the resource is acquired fully or is not acquired at all */
43         GArray *parts;
44
45 } mm_resource_manager_dmn_res_s;
46 typedef mm_resource_manager_dmn_res_s *mm_resource_manager_dmn_res_p;
47
48 typedef struct {
49         mm_resource_manager_id id;
50         mm_resource_manager_app_class_e app_class;
51         mm_resource_manager_res_type_e type;
52         int volume;
53         gboolean is_released;
54         /* if an element is NULL, there is no such a resource for the current platform. */
55         mm_resource_manager_dmn_res_p resources[MM_RESOURCE_MANAGER_RES_TYPE_MAX];
56
57 } mm_resource_manager_dmn_s;
58 typedef mm_resource_manager_dmn_s *mm_resource_manager_dmn_p;
59
60 typedef struct {
61         mm_resource_manager_dmn_p manager;
62         mm_resource_manager_res_type_e type;
63         mm_resource_manager_res_volume volume;
64 } mm_resource_manager_dmn_release_cb_request_s;
65
66
67
68 static GPtrArray *managers;
69 static int res_count[MM_RESOURCE_MANAGER_RES_TYPE_MAX];
70
71
72 static void __destroy_resource(mm_resource_manager_dmn_res_p res);
73 static void __destroy_manager(void *m);
74 static int __search_manager_index(mm_resource_manager_id id);
75 static inline mm_resource_manager_dmn_p __search_manager(mm_resource_manager_id id);
76 static mm_resource_manager_error_e __check_release_requests(
77                 mm_resource_manager_dmn_p manager,
78                 mm_resource_manager_dmn_res_request_s *requests);
79 static mm_resource_manager_dmn_res_request_s *__create_increase_requests(
80                 mm_resource_manager_dmn_res_request_s *releases,
81                 mm_resource_manager_dmn_res_request_s *acquires);
82 static mm_resource_manager_error_e __check_increase_requests(
83                 mm_resource_manager_dmn_p manager,
84                 mm_resource_manager_dmn_res_request_s *requests);
85 static void __sync_increase_acquire_requests(
86                 mm_resource_manager_dmn_res_request_s *increases,
87                 mm_resource_manager_dmn_res_request_s *acquires);
88 static void __handle_release_requests(mm_resource_manager_dmn_p manager,
89                 mm_resource_manager_dmn_res_request_s *requests);
90 static GArray* __handle_acquire_requests(mm_resource_manager_dmn_p manager,
91                 mm_resource_manager_dmn_res_request_s *requests);
92 static void __handle_release_callbacks(GArray *requests);
93 static inline void __add_cb_request(GArray *cb_requests, mm_resource_manager_dmn_p man,
94                 mm_resource_manager_res_type_e type, mm_resource_manager_res_volume volume);
95 static void __release_all_resources(mm_resource_manager_dmn_s *manager);
96 static gboolean __wait_for_release_cb_sync(mm_resource_manager_id id);
97
98
99
100
101 gboolean _mmrm_dmn_init(void)
102 {
103         unlink(RELEASE_CB_SYNC_PATH);
104         MM_RM_RETVM_IF(mkfifo(RELEASE_CB_SYNC_PATH,
105                         S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IWOTH) == -1, FALSE,
106                         "Release callback sync cannot be created");
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()
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 man;
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         man = g_new0(mm_resource_manager_dmn_s, 1);
168         MM_RM_RAND64(man->id);
169         man->app_class = app_class;
170         for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++) {
171                 man->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, man);
176
177         MM_RM_INFO("managers length %d", managers->len);
178
179         *id = man->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_man = __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_man = (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_man->type;
203
204         MM_RM_INFO("managers length #%d type %d available volume %d", managers->len, type, conf->max_volume[type]);
205
206         return MM_RESOURCE_MANAGER_ERROR_NONE;
207 }
208
209 mm_resource_manager_error_e _mmrm_dmn_commit(mm_resource_manager_id id,
210                 mm_resource_manager_dmn_res_request_s *releases,
211                 mm_resource_manager_dmn_res_request_s *acquires)
212 {
213         mm_resource_manager_dmn_p manager = __search_manager(id);
214         mm_resource_manager_error_e ret = MM_RESOURCE_MANAGER_ERROR_NONE;
215         mm_resource_manager_dmn_res_request_s *increases = NULL;
216         GArray *cb_requests;
217
218         MM_RM_RETVM_IF(manager == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
219                         "Resource manager #%"PRIu64" doesn't exist", _mm_rm_hash64(id));
220         MM_RM_RETVM_IF(
221                         (releases == NULL || releases[0].type == MM_RESOURCE_MANAGER_NO_RES) &&
222                         (acquires == NULL || acquires[0].type == MM_RESOURCE_MANAGER_NO_RES),
223                         MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
224                         "Commit request is empty");
225
226         ret = __check_release_requests(manager, releases);
227         MM_RM_RETVM_IF(ret != MM_RESOURCE_MANAGER_ERROR_NONE, ret,
228                 "check_release_requests is failed [0x%x]", ret);
229
230         increases = __create_increase_requests(releases, acquires);
231         MM_RM_RETVM_IF(increases == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
232                 "create_increase_requests is failed");
233
234         ret = __check_increase_requests(manager, increases);
235         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
236                 __sync_increase_acquire_requests(increases, acquires);
237                 g_free(increases);
238                 return ret;
239         }
240         g_free(increases);
241
242         __handle_release_requests(manager, releases);
243         cb_requests = __handle_acquire_requests(manager, acquires);
244         MM_RM_RETVM_IF(cb_requests == NULL, MM_RESOURCE_MANAGER_ERROR_NOT_ENOUGH,
245                         "not enough free resource volume");
246         __handle_release_callbacks(cb_requests);
247         if (!mm_resource_manager_backend_commit_all()) {
248                 /*
249                  * The commit_all
250                  * function can fail only if resource management back-end is not solely
251                  * used by mm-resource-manager or if the back-end cannot acquire/release
252                  * a resource because of some internal error.
253                  *
254                  * Initiate status disconnected and reload the back-end and the RM
255                  * daemon.
256                  */
257                 kill(getpid(), SIGHUP);
258                 ret = MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
259         }
260         g_array_free(cb_requests, TRUE);
261
262         return ret;
263 }
264
265 void _mmrm_dmn_status_callback(mm_resource_manager_status_e status)
266 {
267         _mmrm_dmn_dbus_status_callback(status);
268 }
269
270 static void __destroy_resource(mm_resource_manager_dmn_res_p res)
271 {
272         if (res == NULL)
273                 return;
274
275         if (res->parts)
276                 g_array_free(res->parts, TRUE);
277
278         g_free(res);
279 }
280
281 static void __destroy_manager(void *m)
282 {
283         mm_resource_manager_dmn_p man = (mm_resource_manager_dmn_p) m;
284         int i;
285
286         MM_RM_RETM_IF(man == NULL, "NULL pointer");
287
288         for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++)
289                 __destroy_resource(man->resources[i]);
290
291         g_free(man);
292 }
293
294 static int __search_manager_index(mm_resource_manager_id id)
295 {
296         int i;
297
298         for (i = managers->len - 1; i >= 0; i--) {
299                 if (((mm_resource_manager_dmn_p)managers->pdata[i])->id == id)
300                         return i;
301         }
302
303         return MM_RESOURCE_MANGER_NOT_FOUND;
304 }
305
306 static inline mm_resource_manager_dmn_p __search_manager(mm_resource_manager_id id)
307 {
308         int i = __search_manager_index(id);
309         return i == MM_RESOURCE_MANGER_NOT_FOUND ? NULL : managers->pdata[i];
310 }
311
312 static mm_resource_manager_error_e __check_release_requests(mm_resource_manager_dmn_p manager,
313                         mm_resource_manager_dmn_res_request_s *requests)
314 {
315         int i;
316         mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
317         mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
318
319         MM_RM_RETVM_IF(conf == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "conf is null");
320         MM_RM_RETVM_IF(requests == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "requests is null");
321
322         for (; requests->type != MM_RESOURCE_MANAGER_NO_RES; requests++) {
323
324                 type = requests->type;
325                 const char *type_s = _mm_resource_manager_get_res_str(type);
326
327                 MM_RM_RETVM_IF(manager->resources[type] == NULL,
328                         MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED, "There is no resource %s for the platform", type_s);
329
330                 if (manager->resources[type]->is_acquired) {
331                         if (manager->resources[type]->parts == NULL) {
332                                 if (requests->volume != MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
333                                         MM_RM_ERROR("Resource %s is acquired fully, but a resource part is tried to be released", type_s);
334                                         return MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER;
335                                 }
336                         } else {
337                                 for (i = 0; i < manager->resources[type]->parts->len &&
338                                         ((mm_resource_manager_res_volume*)manager->resources[type]->parts->data)[i]
339                                                 != requests->volume; i++);
340                                 if (i == manager->resources[type]->parts->len) {
341                                         MM_RM_ERROR("Part of %s of volume %d is not acquired", type_s, requests->volume);
342                                         return MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER;
343                                 }
344                         }
345                 } else {
346                         MM_RM_ERROR("Resource %s is not acquired", type_s);
347                         return MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER;
348                 }
349                 MM_RM_DEBUG("Release requests are OK type %d available volume %d", type, conf->max_volume[type]);
350         }
351
352         return MM_RESOURCE_MANAGER_ERROR_NONE;
353 }
354
355 static mm_resource_manager_dmn_res_request_s *__create_increase_requests(
356                 mm_resource_manager_dmn_res_request_s *releases, mm_resource_manager_dmn_res_request_s *acquires)
357 {
358         int i;
359         int result_len = 1;
360         mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
361         mm_resource_manager_dmn_res_request_s *result = NULL;
362         mm_resource_manager_dmn_res_request_s *result_iter = NULL;
363         mm_resource_manager_res_volume resources[MM_RESOURCE_MANAGER_RES_TYPE_MAX] = { 0 };
364
365         MM_RM_RETVM_IF(conf == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "conf is null");
366
367         for (; acquires->type != MM_RESOURCE_MANAGER_NO_RES; acquires++) {
368
369                 if ((resources[acquires->type] > 0 || resources[acquires->type] == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) &&
370                         acquires->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
371                         MM_RM_ERROR("The client tries to acquire %s by part and fully at once",
372                                         _mm_resource_manager_get_res_str(acquires->type));
373                         return NULL;
374                 }
375
376                 if (acquires->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
377                         resources[acquires->type] = MM_RESOURCE_MANAGER_RES_VOLUME_FULL;
378                 } else {
379                         if (conf->max_volume[acquires->type] > 1)
380                                 resources[acquires->type] += acquires->volume;
381                         else
382                                 resources[acquires->type]++;
383                 }
384
385                 MM_RM_DEBUG("(type, vol) = (%d, %d)", acquires->type, resources[acquires->type]);
386         }
387
388         for (; releases->type != MM_RESOURCE_MANAGER_NO_RES; releases++) {
389                 if (resources[releases->type] > 1) {
390                         resources[releases->type] += releases->volume;
391                         MM_RM_INFO("type %d available volume %d", releases->type, resources[releases->type]);
392                 }
393         }
394
395         for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++)
396                 if (resources[i] > 0 || resources[i] == MM_RESOURCE_MANAGER_RES_VOLUME_FULL)
397                         result_len++;
398
399         result_iter = result = g_new0(mm_resource_manager_dmn_res_request_s, result_len);
400         for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++) {
401                 if (resources[i] > 0 || resources[i] == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
402                         result_iter->type = i;
403                         result_iter->volume = resources[i];
404                         result_iter++;
405                 }
406         }
407         result_iter->type = MM_RESOURCE_MANAGER_NO_RES;
408
409         return result;
410 }
411
412 static mm_resource_manager_error_e __check_increase_requests(mm_resource_manager_dmn_p manager,
413                         mm_resource_manager_dmn_res_request_s *requests)
414 {
415         mm_resource_manager_res_volume remaining_volume;
416         mm_resource_manager_dmn_p i_man;
417         mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
418         int i, j, len;
419         mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
420
421         MM_RM_RETVM_IF(conf == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "conf is null");
422         MM_RM_RETVM_IF(manager == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "manager is null");
423         MM_RM_RETVM_IF(requests == NULL, MM_RESOURCE_MANAGER_ERROR_NONE, "requests is null");
424
425         len = managers->len;
426
427         for (; requests->type != MM_RESOURCE_MANAGER_NO_RES; requests++) {
428                 type = requests->type;
429                 const char *type_s = _mm_resource_manager_get_res_str(type);
430
431                 MM_RM_RETVM_IF(type < MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER ||
432                                 type >= MM_RESOURCE_MANAGER_RES_TYPE_MAX,
433                                 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
434                                 "wrong type %d", type);
435                 MM_RM_RETVM_IF(manager->resources[type] == NULL,
436                                 MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED,
437                                 "There is no resource %s for the platform", type_s);
438
439                 remaining_volume = conf->max_volume[type];
440
441                 for (i = 0; i < len; i++) {
442                         i_man = (mm_resource_manager_dmn_p)managers->pdata[i];
443
444                         if (i_man != manager && conf->priority[i_man->app_class] > conf->priority[manager->app_class] &&
445                                 i_man->resources[type]->is_acquired) {
446                                 if (i_man->resources[type]->parts) {
447                                         if (requests->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
448                                                 requests->priority_error = TRUE;
449                                                 MM_RM_DEBUG("Resource conflict. Full volume is requested, but only part is available");
450                                                 return MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY;
451                                         } else {
452                                                 for (j = 0; j < i_man->resources[type]->parts->len; j++)
453                                                         remaining_volume -= g_array_index(i_man->resources[type]->parts,
454                                                                                                 mm_resource_manager_res_volume, j);
455
456                                                 if (remaining_volume < requests->volume) {
457                                                         requests->priority_error = TRUE;
458                                                         MM_RM_DEBUG("Resource conflict. %d of %s are available, but %d required",
459                                                                         remaining_volume, type_s, requests->volume);
460                                                         return MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY;
461                                                 }
462                                         }
463                                 } else {
464                                         requests->priority_error = TRUE;
465                                         MM_RM_DEBUG("Resource conflict. %s is already acquired fully", type_s);
466                                         return MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY;
467                                 }
468                         }
469                 }
470         }
471
472         return MM_RESOURCE_MANAGER_ERROR_NONE;
473 }
474
475 static void __sync_increase_acquire_requests(mm_resource_manager_dmn_res_request_s *increases,
476                         mm_resource_manager_dmn_res_request_s *acquires)
477 {
478         mm_resource_manager_dmn_res_request_s *increase_iter;
479         mm_resource_manager_dmn_res_request_s *acquire_iter;
480
481         for (increase_iter = increases; increase_iter->type != MM_RESOURCE_MANAGER_NO_RES; increase_iter++) {
482                 for (acquire_iter = acquires; acquire_iter->type != MM_RESOURCE_MANAGER_NO_RES; acquire_iter++) {
483                         if (acquire_iter->type == increase_iter->type)
484                                 acquire_iter->priority_error = increase_iter->priority_error;
485                 }
486         }
487 }
488
489 static inline void __add_cb_request(GArray *cb_requests,mm_resource_manager_dmn_p man,
490                         mm_resource_manager_res_type_e type, mm_resource_manager_res_volume volume)
491 {
492         mm_resource_manager_dmn_release_cb_request_s *cb_request;
493
494         g_array_set_size(cb_requests, cb_requests->len + 1);
495         cb_request = &g_array_index(cb_requests, mm_resource_manager_dmn_release_cb_request_s, cb_requests->len - 1);
496
497         cb_request->manager = man;
498         cb_request->type = type;
499         cb_request->volume = volume;
500 }
501
502 static GArray *__handle_acquire_requests(mm_resource_manager_dmn_p manager,
503                 mm_resource_manager_dmn_res_request_s *requests)
504 {
505         mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
506         mm_resource_manager_res_volume acquired_volume = 0;
507         mm_resource_manager_dmn_p i_man = NULL, j_man = NULL;
508         const char *res_name = NULL;
509         GArray *cb_requests = NULL;
510         GArray *res = NULL;
511         int i =0, j = 0;
512         gboolean is_released_called_once = FALSE;
513         mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
514         mm_resource_manager_res_volume volume = MM_RESOURCE_MANAGER_RES_VOLUME_FULL;
515
516         MM_RM_RETVM_IF(conf == NULL, NULL, "conf is NULL");
517         MM_RM_RETVM_IF(requests == NULL, NULL, "requests is NULL");
518
519         cb_requests = g_array_sized_new(FALSE, FALSE, sizeof(mm_resource_manager_dmn_release_cb_request_s),
520                         MM_RESOURCE_MANAGER_RESERVED_CALLBACK_ARRAY_SIZE);
521
522         for (; requests->type != MM_RESOURCE_MANAGER_NO_RES; requests++) {
523                 type = requests->type;
524                 res_name = _mm_resource_manager_get_res_str(type);
525                 volume = requests->volume;
526
527                 if (volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
528                         MM_RM_DEBUG("Full volume of %s is requested", res_name);
529
530                         for (i = 0; i < managers->len; i++) {
531                                 i_man = (mm_resource_manager_dmn_p)managers->pdata[i];
532
533                                 if (!i_man->resources[type]->is_acquired ||
534                                         conf->priority[i_man->app_class] >conf->priority[manager->app_class]) {
535                                         i_man->resources[type]->is_acquired = TRUE;
536                                         if (conf->max_instance[type] > 0)
537                                                 res_count[type]++;
538                                         continue;
539                                 }
540
541                                 res = i_man->resources[type]->parts;
542                                 if (res) {
543
544                                         for (j = 0; j < res->len; j++) {
545                                                 __add_cb_request(cb_requests, i_man, type,
546                                                                 g_array_index(res, mm_resource_manager_res_volume, j));
547
548                                                 mm_resource_manager_backend_release(type);
549                                         }
550
551                                         g_array_free(res, TRUE);
552                                         i_man->resources[type]->parts = NULL;
553                                         i_man->resources[type]->is_acquired = FALSE;
554
555                                         MM_RM_DEBUG("All parts of %s are released in RM %"PRIu64,
556                                                         res_name, _mm_rm_hash64(i_man->id));
557                                 } else {
558                                         __add_cb_request(cb_requests, i_man, type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL);
559
560                                         mm_resource_manager_backend_release(type);
561
562                                         i_man->resources[type]->is_acquired = FALSE;
563
564                                         MM_RM_DEBUG("Full resource %s is released in RM %"PRIu64" available volume %d",
565                                                 res_name, _mm_rm_hash64(i_man->id), conf->max_volume[type]);
566                                         break;
567                                 }
568                         }
569                 } else {
570                         MM_RM_INFO("[managers len #%d] [%d type #%d (max inst #%d)] [%d (max vol %d) units of %s] are requested",
571                                 managers->len, type, res_count[type] + 1,
572                                 conf->max_instance[type], volume, conf->max_volume[type], res_name);
573
574                         for (i = 0; i < managers->len; i++) {
575                                 i_man = (mm_resource_manager_dmn_p)managers->pdata[i];
576                                 res = i_man->resources[type]->parts;
577
578                                 if (!i_man->resources[type]->is_acquired || res ||
579                                         conf->priority[i_man->app_class] > conf->priority[manager->app_class]) {
580
581                                         if (conf->volume_would_be_checked[type] && conf->max_volume[type] >= 0 && !res) {
582                                                 conf->max_volume[type] -= volume;
583                                                 MM_RM_INFO("[type %d] - %d = %d", type, volume, conf->max_volume[type]);
584                                         }
585
586                                         if (conf->max_instance[type] > 0 && conf->max_instance[type] == res_count[type]
587                                                 && !is_released_called_once) {
588                                                 for (j = 0; j < managers->len; j++) {
589                                                         j_man = (mm_resource_manager_dmn_p)managers->pdata[j];
590                                                         res = j_man->resources[type]->parts;
591
592                                                         if (res && !j_man->is_released) {
593                                                                 MM_RM_INFO("[#%d] [#%d / #%d] would be released %s in RM %"PRIu64,
594                                                                 managers->len, j + 1, res->len, res_name, _mm_rm_hash64(j_man->id));
595
596                                                                 j_man->is_released = TRUE;
597                                                                 __add_cb_request(cb_requests, j_man, type,
598                                                                                 g_array_index(res, mm_resource_manager_res_volume, 0));
599
600                                                                 mm_resource_manager_backend_release(type);
601                                                                 is_released_called_once = TRUE;
602                                                                 break;
603                                                         }
604                                                 }
605                                         }
606
607                                         if (conf->max_instance[type] > 0 && !res)
608                                                 res_count[type]++;
609
610                                         i_man->resources[type]->is_acquired = TRUE;
611
612                                         if (conf->max_instance[type] < res_count[type])
613                                                 break;
614
615                                         if (conf->volume_would_be_checked[type] && conf->max_volume[type] < 0
616                                                 && acquired_volume < volume) {
617                                                 for (j = 0; j < managers->len; j++) {
618                                                         j_man = (mm_resource_manager_dmn_p)managers->pdata[j];
619                                                         res = j_man->resources[type]->parts;
620
621                                                         if (j_man->is_released)
622                                                                 continue;
623
624                                                         acquired_volume += g_array_index(res, mm_resource_manager_res_volume, 0);
625                                                         MM_RM_INFO("[#%d] [#%d / #%d] There are %d units of %s in RM %"PRIu64,
626                                                                 managers->len, j + 1, res->len, acquired_volume, res_name,
627                                                                 _mm_rm_hash64(j_man->id));
628
629                                                         j_man->is_released = TRUE;
630                                                         __add_cb_request(cb_requests, j_man, type,
631                                                                 g_array_index(res, mm_resource_manager_res_volume, 0));
632
633                                                         mm_resource_manager_backend_release(type);
634
635                                                         if (acquired_volume >= volume)
636                                                                 break;
637                                                 }
638                                         }
639
640                                         continue;
641                                 }
642                         }
643
644                         res = manager->resources[requests->type]->parts;
645                         if (res == NULL) {
646                                 res = g_array_sized_new(FALSE, FALSE, sizeof(mm_resource_manager_res_volume),
647                                         MM_RESOURCE_MANAGER_RESERVED_PART_ARRAY_SIZE);
648                                 manager->resources[requests->type]->parts = res;
649                         }
650                         g_array_append_val(res, requests->volume);
651                 }
652
653                 manager->resources[type]->is_acquired = TRUE;
654                 mm_resource_manager_backend_acquire(type);
655         }
656
657         return cb_requests;
658 }
659
660 static void __handle_release_callbacks(GArray *requests)
661 {
662         int i;
663         mm_resource_manager_id id;
664         mm_resource_manager_dmn_release_cb_request_s *request;
665         mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
666         mm_resource_manager_res_volume volume = MM_RESOURCE_MANAGER_RES_VOLUME_FULL;
667         mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
668
669         MM_RM_RETM_IF(requests == NULL, "requests is NULL");
670         MM_RM_RETM_IF(conf == NULL, "conf is NULL");
671
672         for (i = 0; i < requests->len; i++) {
673                 request = &g_array_index(requests, mm_resource_manager_dmn_release_cb_request_s, i);
674                 id = request->manager->id;
675                 MM_RM_HASH64(id);
676                 type = request->type;
677                 volume = request->volume;
678                 MM_RM_INFO("Sending release callback to [man %p] RM #%"PRIu64" for %s of volume %d",
679                                 request->manager, 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 }
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 __wait_for_release_cb_sync(mm_resource_manager_id id)
763 {
764         gboolean ret = TRUE;
765         struct pollfd sync = {0};
766         mm_resource_manager_id recv_id;
767         ssize_t read_size;
768
769         sync.fd = open(RELEASE_CB_SYNC_PATH, O_RDONLY | O_NONBLOCK);
770         MM_RM_RETVM_IF(sync.fd == -1, FALSE, "Sync FIFO cannot be opened");
771
772         sync.events = POLLIN;
773         switch (poll(&sync, 1, RELEASE_CB_SYNC_TIMEOUT * 1000)) {
774         case -1:
775                 MM_RM_ERROR("Polling is failed");
776                 ret = FALSE;
777                 break;
778         case 0:
779                 MM_RM_DEBUG("Wait timeout is elapsed");
780                 ret = FALSE;
781                 break;
782         default:
783                 read_size = read(sync.fd, &recv_id, sizeof(recv_id));
784                 if (read_size == sizeof(recv_id)) {
785                         ret = id == _mm_rm_hash64(recv_id);
786                         if (ret == FALSE)
787                                 MM_RM_ERROR("Sync is received from wrong client #%"PRIu64, id);
788                         /*
789                          * Wait POLLHUP to avoid situation when client sent last sync
790                          * through the pipe, but not already closed the pipe handle and
791                          * the daemon is already opened the pipe again and waiting for
792                          * the next sync.
793                          */
794                         sync.revents = 0;
795                         if (poll(&sync, 1, RELEASE_CB_SYNC_TIMEOUT * 1000) == 0 || (sync.revents & (POLLHUP | POLLERR)) == 0)
796                                 MM_RM_ERROR("The client didn't close the FIFO");
797                 } else {
798                         MM_RM_ERROR("Read is failed (revents=%hd,read_size=%zd)", sync.revents, read_size);
799                         ret = FALSE;
800                 }
801         }
802
803         close(sync.fd);
804
805         return ret;
806 }