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