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