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