Add new api of stream and instance for multi-instance
[platform/core/multimedia/mm-resource-manager.git] / src / lib / mm_resource_manager_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 "common/mm_resource_manager_utils.h"
18 #include "lib/mm_resource_manager_priv.h"
19 #include "common/mm_resource_manager_dbus.h"
20
21 static GMutex handles_lock;
22 static GPtrArray *handles;
23
24 #define MM_RESOURCE_MANAGER(x) ((mm_resource_manager_s *) (x))
25 #define MM_RESOURCE_MANAGER_CHECK(x) \
26         MM_RM_UNLOCK_RETVM_IF(!__check_rm_handle(x), handles_lock, \
27                 MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, \
28                 "Invalid resource manager handle %p", x)
29 #define MM_RESOURCE_MANAGER_RESERVED_RES_ARRAY_SIZE 16   /* preallocated size */
30 #define MM_RESOURCE_MANAGER_RESERVED_HANDLE_ARRAY_SIZE 8 /* preallocated size */
31 #define MM_RESOURCE_MANAGER_RES_NOT_FOUND -1
32
33
34
35 typedef enum {
36         MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE,   /* uncommitted */
37         MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED,      /* committed   */
38         MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE    /* uncommitted */
39 } mm_resource_manager_res_state_e;
40
41 typedef struct {
42         void *cb;
43         void *user_data;
44 } mm_resource_manager_cb_s;
45
46 typedef struct {
47         mm_resource_manager_res_type_e type;
48         mm_resource_manager_res_volume volume;
49         mm_resource_manager_res_state_e state;
50         gboolean is_acquire_failed;
51 } mm_resource_manager_res_s;
52 typedef mm_resource_manager_res_s *mm_resource_manager_res_p;
53
54 typedef struct {
55         mm_resource_manager_id id;
56
57         GPtrArray *resources;
58
59         mm_resource_manager_cb_s release_cb;
60         mm_resource_manager_cb_s status_cb;
61
62         GMutex resources_lock;
63
64         mm_resource_manager_res_volume __max_resource_volumes
65                 [MM_RESOURCE_MANAGER_RES_TYPE_MAX];
66         mm_resource_manager_res_volume __condition_volumes
67                 [MM_RESOURCE_MANAGER_RES_TYPE_MAX]
68                 [MM_RESOURCE_MANAGER_RES_TYPE_COND_MAX];
69         int __max_instance[MM_RESOURCE_MANAGER_RES_TYPE_MAX];
70
71         MMResourceManager *dbus_proxy;
72
73         GMainContext *dispatcher_context;
74         GMainLoop *dispatcher_loop;
75         GThread *dispatcher_thread;
76 } mm_resource_manager_s;
77
78 static void __init_lib() __attribute__((constructor));
79 static void __deinit_lib() __attribute__((destructor));
80 static int __check_resource(mm_resource_manager_s *rm,
81                 mm_resource_manager_res_type_e type,
82                 mm_resource_manager_res_volume volume);
83 static int __create_resource(mm_resource_manager_s *rm,
84                 mm_resource_manager_res_type_e type,
85                 mm_resource_manager_res_volume volume, mm_resource_manager_res_p *res);
86 static void __destroy_resource(void *res);
87 static int __get_resource_index(mm_resource_manager_s *rm,
88                 mm_resource_manager_res_p res);
89 static gboolean __mark_resource_for_release(GPtrArray *resources, int index,
90                 mm_resource_manager_res_p resource);  /* FALSE if resource is destroyed */
91 static void __send_release_cb_sync(mm_resource_manager_id id);
92 static void __mm_resource_manager_release_callback(mm_resource_manager_s *handle,
93                 mm_resource_manager_id id,
94                 mm_resource_manager_res_type_e type,
95                 mm_resource_manager_res_volume volume);
96 static void __mm_resource_manager_status_callback(mm_resource_manager_s *handle,
97                 mm_resource_manager_status_e status);
98 static void __mm_resource_handles_lock(void);
99 static void __mm_resource_handles_unlock(void);
100 static void __mm_resources_lock(mm_resource_manager_s *h);
101 static void __mm_resources_unlock(mm_resource_manager_s *h);
102
103
104 static int __dbus_init(mm_resource_manager_s *handle);
105 static int __dbus_deinit(mm_resource_manager_s *handle);
106 static int __dbus_init_conf(mm_resource_manager_s *handle);
107 static gboolean __check_rm_handle(mm_resource_manager_s *handle);
108 static int __dbus_create(mm_resource_manager_s *handle,
109                 mm_resource_manager_app_class_e app_class);
110 static int __dbus_destroy(mm_resource_manager_s *handle);
111 static int __dbus_commit(mm_resource_manager_s *handle);
112 static void __dbus_release_callback(MMResourceManager *object, guint64 arg_id,
113                 gint arg_resource_type, gint arg_volume);
114 static void __dbus_status_callback(MMResourceManager *object, gint arg_status);
115 static gpointer __dispatcher_thread(gpointer user_data);
116 static void __destroy_dispatcher(mm_resource_manager_s *handle);
117
118
119 int _mm_resource_manager_create(mm_resource_manager_app_class_e app_class,
120                 mm_resource_manager_release_cb cb, void *cb_data,
121                 mm_resource_manager_h *rm)
122 {
123         mm_resource_manager_s *handle = *rm = NULL;
124         int ret;
125         GError *error = NULL;
126
127         handle = (mm_resource_manager_s *) calloc(1, sizeof(mm_resource_manager_s));
128         MM_RM_RETVM_IF(NULL == handle, MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
129                         "Error allocating memory for Handle");
130
131         handle->dispatcher_context = g_main_context_new();
132         if (!handle->dispatcher_context) {
133                 free(handle);
134                 MM_RM_ERROR("g_main_context_new failed");
135                 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
136         }
137         MM_RM_INFO("new main context %p", handle->dispatcher_context);
138
139         handle->dispatcher_loop = g_main_loop_new(handle->dispatcher_context, FALSE);
140         if (!handle->dispatcher_loop) {
141                 g_main_context_unref(handle->dispatcher_context);
142                 free(handle);
143                 MM_RM_ERROR("g_main_loop_new failed");
144                 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
145         }
146         MM_RM_INFO("new main loop %p", handle->dispatcher_loop);
147
148         ret = __dbus_init(handle);
149         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
150                 __destroy_dispatcher(handle);
151                 free(handle);
152                 MM_RM_ERROR("Error initializing dbus client");
153                 return ret;
154         }
155
156         handle->dispatcher_thread = g_thread_try_new("dispatcher_thread", __dispatcher_thread, handle->dispatcher_loop, &error);
157         if (!handle->dispatcher_thread) {
158                 if (error) {
159                         MM_RM_ERROR("dispatcher_thread creation failed : %s", error->message);
160                         g_error_free(error);
161                 }
162                 __destroy_dispatcher(handle);
163                 free(handle);
164                 return MM_RESOURCE_MANAGER_ERROR_NOT_ENOUGH;
165         }
166         MM_RM_INFO("new dispatcher thread %p", handle->dispatcher_thread);
167
168         ret = __dbus_init_conf(handle);
169         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
170                 __destroy_dispatcher(handle);
171                 free(handle);
172                 MM_RM_ERROR("Configuration cannot be requested");
173                 return ret;
174         }
175
176         ret = __dbus_create(handle, app_class);
177         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
178                 __destroy_dispatcher(handle);
179                 free(handle);
180                 MM_RM_ERROR("Dbus create request failed");
181                 return ret;
182         }
183
184         handle->release_cb.cb = cb;
185         handle->release_cb.user_data = cb_data;
186
187         handle->resources = g_ptr_array_new_full(
188                         MM_RESOURCE_MANAGER_RESERVED_RES_ARRAY_SIZE, __destroy_resource);
189
190         g_mutex_init(&handle->resources_lock);
191
192         *rm = (mm_resource_manager_h *) handle;
193         __mm_resource_handles_lock();
194         g_ptr_array_add(handles, handle);
195
196         MM_RM_INFO("Resource manager #%"PRIu64" is created", _mm_rm_hash64(handle->id));
197         __mm_resource_handles_unlock();
198
199         return MM_RESOURCE_MANAGER_ERROR_NONE;
200 }
201
202 int _mm_resource_manager_destroy(mm_resource_manager_h rm)
203 {
204         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
205         mm_resource_manager_id id;
206         int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
207
208         __mm_resource_handles_lock();
209         MM_RESOURCE_MANAGER_CHECK(handle);
210         g_ptr_array_remove_fast(handles, handle);
211         __mm_resource_handles_unlock();
212
213         id = handle->id;
214
215         MM_RM_INFO("Resource manager #%"PRIu64" would be destroyed", _mm_rm_hash64(id));
216
217         __mm_resources_lock(handle);
218         ret = __dbus_destroy(handle);
219         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
220                 MM_RM_ERROR("Dbus destroy request failed 0x%x", ret);
221
222         __destroy_dispatcher(handle);
223
224         g_ptr_array_free(handle->resources, TRUE);
225         __mm_resources_unlock(handle);
226
227         g_mutex_clear(&handle->resources_lock);
228         free(handle);
229
230         if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
231                 MM_RM_INFO("Resource manager #%"PRIu64" is destroyed", _mm_rm_hash64(id));
232
233         return ret;
234 }
235
236 int _mm_resource_manager_mark_for_acquire(
237                 mm_resource_manager_h rm, mm_resource_manager_res_type_e type,
238                 mm_resource_manager_res_volume volume,
239                 mm_resource_manager_res_h *resource_h)
240 {
241         int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
242         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
243         mm_resource_manager_res_p resource;
244
245         __mm_resource_handles_lock();
246         MM_RESOURCE_MANAGER_CHECK(handle);
247         __mm_resources_lock(handle);
248         __mm_resource_handles_unlock();
249
250         ret = __create_resource(handle, type, volume, &resource);
251         MM_RM_UNLOCK_RETVM_IF(ret != MM_RESOURCE_MANAGER_ERROR_NONE,
252                         handle->resources_lock, ret, "Resource cannot be created");
253         g_ptr_array_add(handle->resources, resource);
254
255         *resource_h = resource;
256
257         MM_RM_INFO("Resource %p of type %d with volume %d is marked for acquire in "
258                         "resource manager #%"PRIu64, *resource_h, type, volume,
259                         _mm_rm_hash64(handle->id));
260         __mm_resources_unlock(handle);
261
262         return ret;
263 }
264
265 int _mm_resource_manager_resize_marked(mm_resource_manager_h rm,
266                 mm_resource_manager_res_h resource_h,
267                 mm_resource_manager_res_volume new_volume)
268 {
269         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
270         mm_resource_manager_res_p resource = (mm_resource_manager_res_p) resource_h;
271         mm_resource_manager_res_p tmp_resource;
272         mm_resource_manager_res_volume add_volume;
273         int i;
274         int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
275
276         __mm_resource_handles_lock();
277         MM_RESOURCE_MANAGER_CHECK(handle);
278         __mm_resources_lock(handle);
279         __mm_resource_handles_unlock();
280
281         i = __get_resource_index(handle, resource);
282         MM_RM_UNLOCK_RETVM_IF(i == MM_RESOURCE_MANAGER_RES_NOT_FOUND,
283                         handle->resources_lock,
284                         MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
285                         "Invalid resource handle");
286         if (new_volume == resource->volume) {
287                 __mm_resources_unlock(handle);
288                 MM_RM_DEBUG("New volume equals the old. Resize is not needed.");
289                 return ret;
290         }
291
292         add_volume = resource->volume != MM_RESOURCE_MANAGER_RES_VOLUME_FULL &&
293                         new_volume != MM_RESOURCE_MANAGER_RES_VOLUME_FULL &&
294                         resource->volume < new_volume ? (new_volume - resource->volume) : 0;
295
296         switch (resource->state) {
297         case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
298                 if (add_volume > 0) {
299                         ret = __check_resource(handle, resource->type, add_volume);
300                         MM_RM_UNLOCK_RETVM_IF(ret != MM_RESOURCE_MANAGER_ERROR_NONE,
301                                 handle->resources_lock, ret, "Resource check failed");
302                 }
303                 resource->volume = new_volume;
304                 break;
305
306         case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
307         case MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED:
308                 ret = __create_resource(handle, resource->type, add_volume, &tmp_resource);
309                 MM_RM_UNLOCK_RETVM_IF(ret != MM_RESOURCE_MANAGER_ERROR_NONE,
310                                 handle->resources_lock, ret, "Resource cannot be created");
311
312                 tmp_resource->volume = resource->volume;
313                 tmp_resource->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE;
314
315                 g_ptr_array_add(handle->resources, resource);
316                 resource->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE;
317                 resource->volume = new_volume;
318
319                 handle->resources->pdata[i] = tmp_resource;
320                 break;
321         }
322
323         MM_RM_INFO("Resource %p is resized for acquire in resource manager #%"PRIu64,
324                         resource_h, _mm_rm_hash64(handle->id));
325         __mm_resources_unlock(handle);
326
327         return ret;
328 }
329
330 int _mm_resource_manager_mark_for_release(mm_resource_manager_h rm,
331                 mm_resource_manager_res_h resource_h)
332 {
333         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
334         mm_resource_manager_res_p resource = (mm_resource_manager_res_p) resource_h;
335         int i;
336
337         __mm_resource_handles_lock();
338         MM_RESOURCE_MANAGER_CHECK(handle);
339         __mm_resources_lock(handle);
340         __mm_resource_handles_unlock();
341
342         i = __get_resource_index(handle, resource);
343         MM_RM_UNLOCK_RETVM_IF(i == MM_RESOURCE_MANAGER_RES_NOT_FOUND,
344                         handle->resources_lock,
345                         MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
346                         "Invalid resource handle");
347
348         __mark_resource_for_release(handle->resources, i, resource);
349
350         MM_RM_INFO("Resource %p is marked for release in resource manager #%"PRIu64,
351                         resource_h, _mm_rm_hash64(handle->id));
352         __mm_resources_unlock(handle);
353
354         return MM_RESOURCE_MANAGER_ERROR_NONE;
355 }
356
357 int _mm_resource_manager_mark_all_for_release(mm_resource_manager_h rm)
358 {
359         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
360         int i;
361
362         __mm_resource_handles_lock();
363         MM_RESOURCE_MANAGER_CHECK(handle);
364         __mm_resources_lock(handle);
365         __mm_resource_handles_unlock();
366
367         for (i = 0; i < handle->resources->len; i++) {
368                 if (!__mark_resource_for_release(handle->resources, i,
369                                 (mm_resource_manager_res_p) handle->resources->pdata[i]))
370                         i--;
371         }
372
373         MM_RM_INFO("All resources are marked for release in resource manager #%"PRIu64,
374                         _mm_rm_hash64(handle->id));
375         __mm_resources_unlock(handle);
376
377         return MM_RESOURCE_MANAGER_ERROR_NONE;
378 }
379
380 int _mm_resource_manager_get_resource_info(mm_resource_manager_h rm,
381                 mm_resource_manager_res_h resource_h,
382                 mm_resource_manager_res_info_s *info)
383 {
384         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
385         mm_resource_manager_res_p resource = (mm_resource_manager_res_p) resource_h;
386         int i;
387
388         __mm_resource_handles_lock();
389         MM_RESOURCE_MANAGER_CHECK(handle);
390         __mm_resources_lock(handle);
391         __mm_resource_handles_unlock();
392
393         i = __get_resource_index(handle, resource);
394         MM_RM_UNLOCK_RETVM_IF(i == MM_RESOURCE_MANAGER_RES_NOT_FOUND,
395                         handle->resources_lock,
396                         MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
397                         "Invalid resource handle");
398
399         info->type = resource->type;
400         info->volume = resource->volume;
401         info->is_acquire_failed = resource->is_acquire_failed;
402
403         MM_RM_INFO("Info structure of resource %p in resource manager #%"PRIu64" is filled",
404                         resource_h, _mm_rm_hash64(handle->id));
405         __mm_resources_unlock(handle);
406
407         return MM_RESOURCE_MANAGER_ERROR_NONE;
408 }
409
410 int _mm_resource_manager_commit(mm_resource_manager_h rm)
411 {
412         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
413         int ret;
414
415         __mm_resource_handles_lock();
416         MM_RESOURCE_MANAGER_CHECK(handle);
417         __mm_resources_lock(handle);
418         __mm_resource_handles_unlock();
419
420         ret = __dbus_commit(handle);
421         if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
422                 MM_RM_INFO("Changes in resource manager #%"PRIu64" have been committed successfully",
423                                 _mm_rm_hash64(handle->id));
424         else
425                 MM_RM_ERROR("Dbus commit request failed");
426         __mm_resources_unlock(handle);
427
428         return ret;
429 }
430
431 int _mm_resource_manager_set_status_cb(mm_resource_manager_h rm,
432                 mm_resource_manager_status_cb cb, void *user_data)
433 {
434         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
435
436         __mm_resource_handles_lock();
437         MM_RESOURCE_MANAGER_CHECK(handle);
438         __mm_resources_lock(handle);
439         __mm_resource_handles_unlock();
440
441         handle->status_cb.cb = cb;
442         handle->status_cb.user_data = user_data;
443         __mm_resources_unlock(handle);
444
445         MM_RM_INFO("Status callback %p in resource manager #%"PRIu64" is set", cb,
446                         _mm_rm_hash64(handle->id));
447
448         return MM_RESOURCE_MANAGER_ERROR_NONE;
449 }
450
451 int _mm_resource_manager_get_res_type_max_volume(mm_resource_manager_h rm,
452                 mm_resource_manager_res_type_e type,
453                 mm_resource_manager_res_volume *max_volume)
454 {
455         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
456
457         if (handle->__max_resource_volumes[type] == MM_RESOURCE_MANAGER_NO_RES) {
458                 MM_RM_DEBUG("No resource for the platform");
459                 return MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED;
460         } else {
461                 *max_volume = handle->__max_resource_volumes[type];
462                 return MM_RESOURCE_MANAGER_ERROR_NONE;
463         }
464 }
465
466 int _mm_resource_manager_get_res_type_volume(mm_resource_manager_h rm,
467                 mm_resource_manager_res_type_e type,
468                 mm_resource_manager_res_type_cond_e condition,
469                 mm_resource_manager_res_volume *volume)
470 {
471         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
472
473         if (handle->__condition_volumes[type][condition] == MM_RESOURCE_MANAGER_NO_RES) {
474                 MM_RM_DEBUG("No pair (resource,condition) for the platform");
475                 return MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED;
476         } else {
477                 *volume = handle->__condition_volumes[type][condition];
478                 return MM_RESOURCE_MANAGER_ERROR_NONE;
479         }
480 }
481
482 int _mm_resource_manager_get_type_max_instance(mm_resource_manager_h rm,
483                 mm_resource_manager_res_type_e type, int *max_instance)
484 {
485         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
486
487         if (handle->__max_instance[type] == MM_RESOURCE_MANAGER_NO_RES) {
488                 MM_RM_DEBUG("No resource for the platform");
489                 return MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED;
490         }
491
492         *max_instance = handle->__max_instance[type];
493         return MM_RESOURCE_MANAGER_ERROR_NONE;
494 }
495
496 void __mm_resource_manager_release_callback(mm_resource_manager_s *handle,
497                 mm_resource_manager_id id,
498                 mm_resource_manager_res_type_e type,
499                 mm_resource_manager_res_volume volume)
500 {
501         mm_resource_manager_res_s *resource;
502         mm_resource_manager_id handle_id;
503         gboolean release_all = FALSE;
504         int i;
505
506         MM_RM_INFO("Release callback is emitted for %s of volume %d in RM #%"PRIu64,
507                         _mm_resource_manager_get_res_str(type), volume, id);
508
509         handle_id = handle->id;
510         MM_RM_HASH64(handle_id);
511         if (handle_id == id) {
512                 __mm_resources_lock(handle);
513                 __mm_resource_handles_unlock();
514
515                 for (i = 0; i < handle->resources->len; i++) {
516                         resource = (mm_resource_manager_res_s*)handle->resources->pdata[i];
517                         if (resource->type == type && resource->volume == volume) {
518
519                                 release_all = ((mm_resource_manager_release_cb)
520                                                 handle->release_cb.cb)(
521                                                 handle, resource, handle->release_cb.user_data);
522
523                                 __send_release_cb_sync(handle->id);
524
525                                 g_ptr_array_remove_index_fast(handle->resources, i);
526                                 break;
527                         }
528                 }
529                 __mm_resources_unlock(handle);
530
531                 if (release_all) {
532                         if (_mm_resource_manager_mark_all_for_release(handle) == MM_RESOURCE_MANAGER_ERROR_NONE
533                                 && _mm_resource_manager_commit(handle) == MM_RESOURCE_MANAGER_ERROR_NONE) {
534                                 MM_RM_DEBUG("All resources are released after release cb");
535                         } else {
536                                 MM_RM_ERROR("Resources cannot be released after release cb");
537                         }
538                 }
539         } else {
540                 __mm_resource_handles_unlock();
541         }
542 }
543
544 void __mm_resource_manager_status_callback(mm_resource_manager_s *handle,
545                 mm_resource_manager_status_e status)
546 {
547         __mm_resources_lock(handle);
548         __mm_resource_handles_unlock();
549         if (handle->status_cb.cb) {
550                 ((mm_resource_manager_status_cb)handle->status_cb.cb)(handle, status,
551                                 handle->status_cb.user_data);
552         }
553         __mm_resources_unlock(handle);
554 }
555
556 static void __mm_resource_handles_lock(void)
557 {
558         g_mutex_lock(&handles_lock);
559 }
560
561 static void __mm_resource_handles_unlock(void)
562 {
563         g_mutex_unlock(&handles_lock);
564 }
565
566 static void __mm_resources_lock(mm_resource_manager_s *h)
567 {
568         MM_RM_RETM_IF(!h, "handle is NULL");
569         g_mutex_lock(&h->resources_lock);
570 }
571
572 static void __mm_resources_unlock(mm_resource_manager_s *h)
573 {
574         MM_RM_RETM_IF(!h, "handle is NULL");
575         g_mutex_unlock(&h->resources_lock);
576 }
577
578 static int __check_resource(mm_resource_manager_s *rm,
579                 mm_resource_manager_res_type_e type,
580                 mm_resource_manager_res_volume volume)
581 {
582         mm_resource_manager_res_volume remaining_local_volume =
583                         rm->__max_resource_volumes[type];
584         mm_resource_manager_res_p i_res;
585         int i;
586
587         MM_RM_RETVM_IF(remaining_local_volume == MM_RESOURCE_MANAGER_NO_RES,
588                         MM_RESOURCE_MANAGER_ERROR_NOT_SUPPORTED,
589                         "No resource for the platform");
590
591         if (volume > 0) {
592                 for (i = 0; i < rm->resources->len; i++) {
593                         i_res = (mm_resource_manager_res_p) rm->resources->pdata[i];
594                         if (i_res->type == type &&
595                                         i_res->state != MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE &&
596                                         (i_res->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL ||
597                                                         (remaining_local_volume -= i_res->volume) < volume)) {
598                                 MM_RM_ERROR("Requested volume %d exceeds remaining local volume %d",
599                                                 volume,
600                                                 i_res->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL ?
601                                                 0 : remaining_local_volume);
602                                 return MM_RESOURCE_MANAGER_ERROR_NOT_ENOUGH;
603                         }
604                 }
605         }
606
607         return MM_RESOURCE_MANAGER_ERROR_NONE;
608 }
609
610 static int __create_resource(mm_resource_manager_s *rm,
611                 mm_resource_manager_res_type_e type,
612                 mm_resource_manager_res_volume volume, mm_resource_manager_res_p *res)
613 {
614         int ret;
615
616         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
617
618         MM_RM_RETVM_IF(handle == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
619                         "NULL handle pointer");
620         MM_RM_RETVM_IF(res == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "NULL pointer");
621         ret = __check_resource(rm, type, volume);
622         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
623                 return ret;
624
625         *res = g_new0(mm_resource_manager_res_s, 1);
626         (*res)->type = type;
627         (*res)->volume = volume;
628
629         return MM_RESOURCE_MANAGER_ERROR_NONE;
630 }
631
632 static void __destroy_resource(void *res)
633 {
634         g_free(res);
635 }
636
637 static int __get_resource_index(mm_resource_manager_s *rm, mm_resource_manager_res_p res)
638 {
639         int i;
640
641         for (i = 0; i < rm->resources->len; i++) {
642                 if (rm->resources->pdata[i] == (gpointer) res)
643                         return i;
644         }
645
646         return MM_RESOURCE_MANAGER_RES_NOT_FOUND;
647 }
648
649 static gboolean __mark_resource_for_release(GPtrArray *resources, int index,
650                 mm_resource_manager_res_p resource)
651 {
652         switch (resource->state) {
653         case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
654                 g_ptr_array_remove_index_fast(resources, index);
655                 MM_RM_DEBUG("Resource %p is removed implicitly", resource);
656                 return FALSE;
657         case MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED:
658                 resource->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE;
659                 break;
660         case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
661                 MM_RM_DEBUG("Resource %p is already marked", resource);
662                 break;
663         }
664         return TRUE;
665 }
666
667
668 static gboolean __check_rm_handle(mm_resource_manager_s *handle)
669 {
670         int i;
671
672         for (i = 0; i < handles->len; i++) {
673                 if (g_ptr_array_index(handles, i) == handle)
674                         return TRUE;
675         }
676         return FALSE;
677 }
678
679 static void __send_release_cb_sync(mm_resource_manager_id id)
680 {
681         int sync_fd;
682
683         sync_fd = open(RELEASE_CB_SYNC_PATH, O_WRONLY);
684         MM_RM_RETM_IF(sync_fd == -1, "Sync FIFO cannot be opened");
685
686         if (write(sync_fd, &id, sizeof(id)) == sizeof(id))
687                 MM_RM_DEBUG("Sync message is sent successfully");
688         else
689                 MM_RM_ERROR("Sync message cannot be sent");
690
691         close(sync_fd);
692 }
693
694 static void __init_lib()
695 {
696         handles = g_ptr_array_sized_new(MM_RESOURCE_MANAGER_RESERVED_HANDLE_ARRAY_SIZE);
697         MM_RM_RETM_IF(handles == NULL, "API lib cannot be initialized");
698
699         MM_RM_INFO("API lib is loaded");
700 }
701
702 static void __deinit_lib()
703 {
704         if (handles->len > 0) {
705                 MM_RM_DEBUG("Handles array [%d] is not empty. It will be cleaned now.", handles->len);
706                 while (handles->len > 0)
707                         _mm_resource_manager_destroy(handles->pdata[0]);
708         }
709
710         g_ptr_array_free(handles, TRUE);
711
712         MM_RM_INFO("API lib is unloaded");
713 }
714
715 static int __dbus_init(mm_resource_manager_s *handle)
716 {
717         GError *error = NULL;
718
719         MM_RM_RETVM_IF(handle->dbus_proxy != NULL,
720                         MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
721                         "Dbus proxy is not NULL");
722
723         g_main_context_push_thread_default(handle->dispatcher_context);
724         handle->dbus_proxy = mmresource_manager_proxy_new_for_bus_sync(
725                         G_BUS_TYPE_SYSTEM, 0, RMD_GDBUS_NAME, RMD_GDBUS_PATH, NULL, &error);
726         g_main_context_pop_thread_default(handle->dispatcher_context);
727         MM_RM_RET_IF_GERR(error, "Dbus proxy cannot be created");
728
729         if (g_signal_connect(handle->dbus_proxy, "release_callback",
730                         (GCallback)__dbus_release_callback, NULL) < 1 ||
731                         g_signal_connect(handle->dbus_proxy, "status_callback",
732                         (GCallback)__dbus_status_callback, NULL) < 1) {
733
734                 g_object_unref(handle->dbus_proxy);
735                 handle->dbus_proxy = NULL;
736                 MM_RM_ERROR("Release or status callback signals cannot be connected");
737
738                 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
739         }
740
741         return MM_RESOURCE_MANAGER_ERROR_NONE;
742 }
743
744 static int __dbus_deinit(mm_resource_manager_s *handle)
745 {
746         MM_RM_RETVM_IF(handle->dbus_proxy == NULL,
747                         MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Dbus proxy is NULL");
748         g_object_unref(handle->dbus_proxy);
749         handle->dbus_proxy = NULL;
750         return MM_RESOURCE_MANAGER_ERROR_NONE;
751 }
752
753 static int __dbus_init_conf(mm_resource_manager_s *handle)
754 {
755         int i, j;
756         GError *error = NULL;
757         int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
758         GVariant *max_volume = NULL;
759         GVariant *cond_volume = NULL;
760         GVariant *max_instance = NULL;
761         GVariant *tmp;
762         GVariantIter volume_iter;
763         GVariantIter cond_volume_iter;
764
765         mmresource_manager_call_conf_sync(handle->dbus_proxy, &rm_error, &max_volume,
766                         &cond_volume, &max_instance, NULL, &error);
767         MM_RM_RET_IF_GERR(error, "DBus conf msg cannot be sent");
768
769         MM_RM_RETVM_IF(max_volume == NULL || cond_volume == NULL,
770                         MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Variant data are empty");
771
772         if (g_variant_iter_init(&volume_iter, max_volume) == MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
773                 for (i = 0; g_variant_iter_next(&volume_iter, "i", &handle->__max_resource_volumes[i]); i++);
774                 g_variant_unref(max_volume);
775                 max_volume = NULL;
776         } else {
777                 MM_RM_ERROR("Wrong max volume array size");
778                 goto out;
779         }
780
781         if (g_variant_iter_init(&volume_iter, cond_volume) == MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
782                 for (i = 0; (tmp = g_variant_iter_next_value(&volume_iter)) != NULL; i++) {
783                         if (g_variant_iter_init(&cond_volume_iter, tmp) == MM_RESOURCE_MANAGER_RES_TYPE_COND_MAX) {
784                                 for (j = 0; g_variant_iter_next(&cond_volume_iter, "i", &handle->__condition_volumes[i][j]); j++);
785                                 g_variant_unref(tmp);
786                         } else {
787                                 g_variant_unref(tmp);
788                                 MM_RM_ERROR("Wrong condition volume array size");
789                                 rm_error = MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
790                                 break;
791                         }
792                 }
793                 g_variant_unref(cond_volume);
794                 cond_volume = NULL;
795         } else {
796                 MM_RM_ERROR("Wrong condition volume array size");
797                 goto out;
798         }
799
800         if (g_variant_iter_init(&volume_iter, max_instance) == MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
801                 for (i = 0; g_variant_iter_next(&volume_iter, "i", &handle->__max_instance[i]); i++);
802                 g_variant_unref(max_instance);
803                 max_instance = NULL;
804         } else {
805                 MM_RM_ERROR("Wrong max instance array size");
806                 goto out;
807         }
808
809         return rm_error;
810 out:
811         g_variant_unref(max_volume);
812         g_variant_unref(cond_volume);
813         g_variant_unref(max_instance);
814         return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
815 }
816
817 static int __dbus_create(mm_resource_manager_s *handle, mm_resource_manager_app_class_e app_class)
818 {
819         GError *error = NULL;
820         int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
821
822         mmresource_manager_call_create_sync(handle->dbus_proxy, app_class, &handle->id,
823                         &rm_error, NULL, &error);
824         MM_RM_RET_IF_GERR(error, "DBus create msg cannot be sent");
825
826         MM_RM_DEBUG("Create returned id - #%"PRIu64", error - %d",
827                         _mm_rm_hash64(handle->id), rm_error);
828
829         return rm_error;
830 }
831
832 static int __dbus_destroy(mm_resource_manager_s *handle)
833 {
834         GError *error = NULL;
835         int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
836
837         mmresource_manager_call_destroy_sync(handle->dbus_proxy, handle->id, &rm_error,
838                         NULL, &error);
839         MM_RM_RET_IF_GERR(error, "DBus destroy msg cannot be sent");
840
841         MM_RM_DEBUG("Destroy for id - #%"PRIu64" returned error - %d", _mm_rm_hash64(handle->id), rm_error);
842
843         return MM_RESOURCE_MANAGER_ERROR_NONE;
844 }
845
846 static int __dbus_commit(mm_resource_manager_s *handle)
847 {
848         GVariant *release;
849         GVariant *acquire;
850         GVariantBuilder *release_builder;
851         GVariantBuilder *acquire_builder;
852         GVariant *flags_variant;
853         GVariantIter flags_iter;
854         mm_resource_manager_res_p resource;
855         int i;
856         int release_num = 0;
857         int acquire_num = 0;
858         GError *error = NULL;
859         int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
860
861         release_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
862         acquire_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
863
864         for (i = 0; i < handle->resources->len; i++) {
865                 resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
866
867                 switch (resource->state) {
868                 case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
869                         g_variant_builder_add_value(acquire_builder, g_variant_new("(ii)",
870                                         resource->type, resource->volume));
871                         acquire_num++;
872                         break;
873                 case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
874                         g_variant_builder_add_value(release_builder, g_variant_new("(ii)",
875                                         resource->type, resource->volume));
876                         release_num++;
877                         break;
878                 default:
879                         break;
880                 }
881         }
882
883         if (release_num + acquire_num == 0) {
884                 g_variant_builder_unref(release_builder);
885                 g_variant_builder_unref(acquire_builder);
886                 MM_RM_DEBUG("There is nothing to commit - dbus request is not sent [%d %d]",
887                                 release_num, acquire_num);
888                 return rm_error;
889         }
890
891         /*
892          * Acquire and release arrays are ended with special element, because
893          * g_variant_builder_end crashes without at least one element
894          */
895         g_variant_builder_add_value(acquire_builder, g_variant_new("(ii)",
896                         MM_RESOURCE_MANAGER_NO_RES, 0));
897         acquire = g_variant_builder_end(acquire_builder);
898         g_variant_builder_unref(acquire_builder);
899
900         g_variant_builder_add_value(release_builder, g_variant_new("(ii)",
901                         MM_RESOURCE_MANAGER_NO_RES, 0));
902         release = g_variant_builder_end(release_builder);
903         g_variant_builder_unref(release_builder);
904
905         mmresource_manager_call_commit_sync(handle->dbus_proxy, handle->id, release,
906                         acquire, &rm_error, &flags_variant, NULL, &error);
907         if (error != NULL)
908                 MM_RM_RET_IF_GERR(error, "DBus commit msg cannot be sent");
909
910         MM_RM_DEBUG("Commit for id - #%"PRIu64" returned error - %d",
911                         _mm_rm_hash64(handle->id), rm_error);
912
913         if (rm_error == MM_RESOURCE_MANAGER_ERROR_NONE) {
914                 for (i = 0; i < handle->resources->len; i++) {
915                         resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
916
917                         switch (resource->state) {
918                         case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
919                                 resource->state = MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED;
920                                 resource->is_acquire_failed = FALSE;
921                                 break;
922                         case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
923                                 g_ptr_array_remove_index_fast(handle->resources, i--);
924                                 break;
925                         default:
926                                 ;
927                         }
928                 }
929         } else if (rm_error == MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY) {
930                 g_variant_iter_init(&flags_iter, flags_variant);
931
932                 for (i = 0; i < handle->resources->len; i++) {
933                         resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
934
935                         if (resource->state == MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE)
936                                 g_variant_iter_next(&flags_iter, "b", &resource->is_acquire_failed);
937                 }
938         }
939
940         g_variant_unref(flags_variant);
941
942         return rm_error;
943 }
944
945 static void __dbus_release_callback(MMResourceManager *object, guint64 arg_id,
946                 gint arg_resource_type, gint arg_volume)
947 {
948         mm_resource_manager_s *handle;
949         mm_resource_manager_id handle_id;
950         gboolean unlock = TRUE;
951         int i;
952
953         __mm_resource_handles_lock();
954
955         for (i = 0; i < handles->len; i++) {
956                 handle = (mm_resource_manager_s*)handles->pdata[i];
957                 handle_id = handle->id;
958                 MM_RM_HASH64(handle_id);
959                 if (handle->dbus_proxy == object && handle_id == arg_id) {
960                         __mm_resource_manager_release_callback(handle, arg_id,
961                                         arg_resource_type, arg_volume);
962                         unlock = FALSE;
963                         break;
964                 }
965         }
966
967         if (unlock)
968                 __mm_resource_handles_unlock();
969 }
970
971 static void __dbus_status_callback(MMResourceManager *object, gint arg_status)
972 {
973         mm_resource_manager_s *handle;
974         gboolean unlock = TRUE;
975         int i;
976
977         MM_RM_INFO("status callback status %d", arg_status);
978         __mm_resource_handles_lock();
979         for (i = 0; i < handles->len; i++) {
980                 handle = (mm_resource_manager_s*)handles->pdata[i];
981                 if (handle->dbus_proxy == object) {
982                         __mm_resource_manager_status_callback(handle, arg_status);
983                         unlock = FALSE;
984                         break;
985                 }
986         }
987
988         if (unlock)
989                 __mm_resource_handles_unlock();
990 }
991
992 static gpointer __dispatcher_thread(gpointer user_data)
993 {
994         GMainLoop *ml = (GMainLoop *) user_data;
995
996         if (ml) {
997                 g_main_loop_run(ml);
998                 MM_RM_INFO("main loop %p quit", ml);
999         }
1000
1001         return NULL;
1002 }
1003
1004 static void __destroy_dispatcher(mm_resource_manager_s *handle)
1005 {
1006         if (__dbus_deinit(handle) != MM_RESOURCE_MANAGER_ERROR_NONE)
1007                 MM_RM_ERROR("Error while dbus deinitializing");
1008
1009         if (handle->dispatcher_loop) {
1010                 if (g_main_loop_is_running(handle->dispatcher_loop)) {
1011                         MM_RM_INFO("mainloop %p is running", handle->dispatcher_loop);
1012                         g_main_loop_quit(handle->dispatcher_loop);
1013                 }
1014                 g_main_loop_unref(handle->dispatcher_loop);
1015                 handle->dispatcher_loop = NULL;
1016         }
1017
1018         if (handle->dispatcher_thread) {
1019                 g_thread_join(handle->dispatcher_thread);
1020                 MM_RM_INFO("dispatcher thread join %p", handle->dispatcher_thread);
1021                 handle->dispatcher_thread = NULL;
1022         }
1023
1024         if (handle->dispatcher_context) {
1025                 g_main_context_unref(handle->dispatcher_context);
1026                 handle->dispatcher_context = NULL;
1027         }
1028 }