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