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