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