Resolve the memory leak issue
[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 be_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 mgr,
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 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         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 mgr = (mm_resource_manager_dmn_p) m;
284         int i;
285
286         MM_RM_RETM_IF(mgr == NULL, "NULL pointer");
287
288         for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++)
289                 __destroy_resource(mgr->resources[i]);
290
291         g_free(mgr);
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_mgr;
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_mgr = (mm_resource_manager_dmn_p)managers->pdata[i];
443
444                         if (i_mgr != manager && conf->priority[i_mgr->app_class] > conf->priority[manager->app_class] &&
445                                 i_mgr->resources[type]->is_acquired) {
446                                 if (i_mgr->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_mgr->resources[type]->parts->len; j++)
453                                                         remaining_volume -= g_array_index(i_mgr->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 mgr,
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 = mgr;
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_mgr = NULL, j_mgr = 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("Resource of %s is requested [mgr %p]", res_name, manager);
529
530                         for (i = 0; i < managers->len; i++) {
531                                 i_mgr = (mm_resource_manager_dmn_p)managers->pdata[i];
532
533                                 if (manager->id == i_mgr->id ||
534                                         conf->priority[i_mgr->app_class] >conf->priority[manager->app_class]) {
535                                         i_mgr->resources[type]->is_acquired = TRUE;
536                                         if (conf->max_instance[type] > 0)
537                                                 res_count[type]++;
538                                         continue;
539                                 }
540
541                                 if ((res = i_mgr->resources[type]->parts)) { /* always null, which is no conflict case now */
542                                         for (j = 0; j < res->len; j++) {
543                                                 __add_cb_request(cb_requests, i_mgr, type, g_array_index(res, mm_resource_manager_res_volume, j));
544                                                 mm_resource_manager_backend_release(type);
545                                         }
546                                         g_array_free(res, TRUE);
547                                         i_mgr->resources[type]->parts = NULL;
548
549                                         MM_RM_WARNING("Resource of %s is conflicted in RM %"PRIu64, res_name, _mm_rm_hash64(i_mgr->id));
550                                 } else {
551                                         __add_cb_request(cb_requests, i_mgr, type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL);
552
553                                         mm_resource_manager_backend_release(type);
554
555                                         MM_RM_INFO("Resource %s is released in RM %"PRIu64" available volume %d",
556                                                 res_name, _mm_rm_hash64(i_mgr->id), conf->max_volume[type]);
557                                 }
558                         }
559                 } else {
560                         MM_RM_INFO("[managers len #%d] [%s #%d (max inst #%d)] [%d (max vol %d) units of %s] are requested",
561                                 managers->len, _mm_resource_manager_get_res_str(type), res_count[type] + 1,
562                                 conf->max_instance[type], volume, conf->max_volume[type], res_name);
563
564                         for (i = 0; i < managers->len; i++) {
565                                 i_mgr = (mm_resource_manager_dmn_p)managers->pdata[i];
566                                 res = i_mgr->resources[type]->parts;
567
568                                 if (!i_mgr->resources[type]->is_acquired || res ||
569                                         conf->priority[i_mgr->app_class] > conf->priority[manager->app_class]) {
570
571                                         if (conf->volume_would_be_checked[type] && conf->max_volume[type] >= 0 && !res) {
572                                                 conf->max_volume[type] -= volume;
573                                                 MM_RM_INFO("[type %d] - %d = %d", type, volume, conf->max_volume[type]);
574                                         }
575
576                                         if (conf->max_instance[type] > 0 && conf->max_instance[type] == res_count[type]
577                                                 && !is_released_called_once) {
578                                                 for (j = 0; j < managers->len; j++) {
579                                                         j_mgr = (mm_resource_manager_dmn_p)managers->pdata[j];
580                                                         res = j_mgr->resources[type]->parts;
581
582                                                         if (res && !j_mgr->be_released) {
583                                                                 MM_RM_INFO("[#%d] [#%d / #%d] would be released %s in RM %"PRIu64,
584                                                                 managers->len, j + 1, res->len, res_name, _mm_rm_hash64(j_mgr->id));
585
586                                                                 j_mgr->be_released = TRUE;
587                                                                 __add_cb_request(cb_requests, j_mgr, type,
588                                                                                 g_array_index(res, mm_resource_manager_res_volume, 0));
589
590                                                                 mm_resource_manager_backend_release(type);
591                                                                 is_released_called_once = TRUE;
592                                                                 break;
593                                                         }
594                                                 }
595                                         }
596
597                                         if (conf->max_instance[type] > 0 && !res)
598                                                 res_count[type]++;
599
600                                         i_mgr->resources[type]->is_acquired = TRUE;
601
602                                         if (conf->max_instance[type] < res_count[type])
603                                                 break;
604
605                                         if (conf->volume_would_be_checked[type] && conf->max_volume[type] < 0
606                                                 && acquired_volume < volume) {
607                                                 for (j = 0; j < managers->len; j++) {
608                                                         j_mgr = (mm_resource_manager_dmn_p)managers->pdata[j];
609                                                         res = j_mgr->resources[type]->parts;
610
611                                                         if (j_mgr->be_released)
612                                                                 continue;
613
614                                                         acquired_volume += g_array_index(res, mm_resource_manager_res_volume, 0);
615                                                         MM_RM_INFO("[#%d] [#%d / #%d] There are %d units of %s in RM %"PRIu64,
616                                                                 managers->len, j + 1, res->len, acquired_volume, res_name,
617                                                                 _mm_rm_hash64(j_mgr->id));
618
619                                                         j_mgr->be_released = TRUE;
620                                                         __add_cb_request(cb_requests, j_mgr, type,
621                                                                 g_array_index(res, mm_resource_manager_res_volume, 0));
622
623                                                         mm_resource_manager_backend_release(type);
624
625                                                         if (acquired_volume >= volume)
626                                                                 break;
627                                                 }
628                                         }
629
630                                         continue;
631                                 }
632                         }
633
634                         res = manager->resources[requests->type]->parts;
635                         if (res == NULL) {
636                                 res = g_array_sized_new(FALSE, FALSE, sizeof(mm_resource_manager_res_volume),
637                                         MM_RESOURCE_MANAGER_RESERVED_PART_ARRAY_SIZE);
638                                 manager->resources[requests->type]->parts = res;
639                         }
640                         g_array_append_val(res, requests->volume);
641                 }
642
643                 manager->resources[type]->is_acquired = TRUE;
644                 mm_resource_manager_backend_acquire(type);
645         }
646
647         return cb_requests;
648 }
649
650 static void __handle_release_callbacks(GArray *requests)
651 {
652         int i;
653         mm_resource_manager_id id;
654         mm_resource_manager_dmn_release_cb_request_s *request;
655         mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
656         mm_resource_manager_res_volume volume = MM_RESOURCE_MANAGER_RES_VOLUME_FULL;
657         mm_resource_manager_dmn_p mgr = NULL;
658         mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
659
660         MM_RM_RETM_IF(requests == NULL, "requests is NULL");
661         MM_RM_RETM_IF(conf == NULL, "conf is NULL");
662
663         for (i = 0; i < requests->len; i++) {
664                 request = &g_array_index(requests, mm_resource_manager_dmn_release_cb_request_s, i);
665                 mgr = request->manager;
666                 type = request->type;
667
668                 if (!mgr->resources[type]->is_acquired)
669                         continue;
670
671                 id = mgr->id;
672                 MM_RM_HASH64(id);
673
674                 volume = request->volume;
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                 mgr->be_released = TRUE;
697         }
698 }
699
700 static void __handle_release_requests(mm_resource_manager_dmn_p manager,
701                 mm_resource_manager_dmn_res_request_s *requests)
702 {
703         GArray *parts;
704         int i;
705         mm_resource_manager_res_type_e type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
706         mm_resource_manager_res_volume volume = MM_RESOURCE_MANAGER_RES_VOLUME_FULL;
707         mm_resource_manager_conf_s *conf = mm_resource_manager_get_conf();
708
709         MM_RM_RETM_IF(conf == NULL, "conf is NULL");
710         MM_RM_RETM_IF(requests == NULL, "requests is NULL");
711
712         for (; requests->type != MM_RESOURCE_MANAGER_NO_RES; requests++) {
713
714                 type = requests->type;
715                 volume = requests->volume;
716
717                 if (volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL) {
718                         manager->resources[type]->is_acquired = FALSE;
719                 } else {
720                         parts = manager->resources[type]->parts;
721                         for (i = 0; i < parts->len && ((mm_resource_manager_res_volume*)parts->data)[i] != volume; i++);
722
723                         g_array_remove_index_fast(parts, i);
724
725                         if (parts->len == 0) {
726                                 g_array_free(parts, TRUE);
727                                 manager->resources[type]->parts = NULL;
728                                 manager->resources[type]->is_acquired = FALSE;
729                         }
730                 }
731
732                 if (conf->volume_would_be_checked[type]) {
733                         conf->max_volume[type] += volume;
734                         MM_RM_INFO("[type %d] + %d = %d", type, volume, conf->max_volume[type]);
735                 }
736
737                 if (conf->max_instance[type] > 0) {
738                         res_count[type]--;
739                         MM_RM_INFO("The number of type %d #%d", type, res_count[type]);
740                 }
741
742                 mm_resource_manager_backend_release(type);
743         }
744 }
745
746 static void __release_all_resources(mm_resource_manager_dmn_s *manager)
747 {
748         int i, j;
749
750         for (i = 0; i < MM_RESOURCE_MANAGER_RES_TYPE_MAX; i++) {
751                 if (manager->resources[i] && manager->resources[i]->is_acquired) {
752                         if (manager->resources[i]->parts) {
753                                 for (j = 0; j < manager->resources[i]->parts->len; j++)
754                                         mm_resource_manager_backend_release(i);
755                         } else {
756                                 mm_resource_manager_backend_release(i);
757                         }
758                         manager->resources[i]->is_acquired = FALSE;
759                 }
760         }
761 }
762
763 static gboolean __wait_for_release_cb_sync(mm_resource_manager_id id)
764 {
765         gboolean ret = TRUE;
766         struct pollfd sync = {0};
767         mm_resource_manager_id recv_id;
768         ssize_t read_size;
769
770         sync.fd = open(RELEASE_CB_SYNC_PATH, O_RDONLY | O_NONBLOCK);
771         MM_RM_RETVM_IF(sync.fd == -1, FALSE, "Sync FIFO cannot be opened");
772
773         sync.events = POLLIN;
774         switch (poll(&sync, 1, RELEASE_CB_SYNC_TIMEOUT * 1000)) {
775         case -1:
776                 MM_RM_ERROR("Polling is failed");
777                 ret = FALSE;
778                 break;
779         case 0:
780                 MM_RM_DEBUG("Wait timeout is elapsed");
781                 ret = FALSE;
782                 break;
783         default:
784                 read_size = read(sync.fd, &recv_id, sizeof(recv_id));
785                 if (read_size == sizeof(recv_id)) {
786                         ret = id == _mm_rm_hash64(recv_id);
787                         if (ret == FALSE)
788                                 MM_RM_ERROR("Sync is received from wrong client #%"PRIu64, id);
789                         /*
790                          * Wait POLLHUP to avoid situation when client sent last sync
791                          * through the pipe, but not already closed the pipe handle and
792                          * the daemon is already opened the pipe again and waiting for
793                          * the next sync.
794                          */
795                         sync.revents = 0;
796                         if (poll(&sync, 1, RELEASE_CB_SYNC_TIMEOUT * 1000) == 0 || (sync.revents & (POLLHUP | POLLERR)) == 0)
797                                 MM_RM_ERROR("The client didn't close the FIFO");
798                 } else {
799                         MM_RM_ERROR("Read is failed (revents=%hd,read_size=%zd)", sync.revents, read_size);
800                         ret = FALSE;
801                 }
802         }
803
804         close(sync.fd);
805
806         return ret;
807 }