a69a3c2eb5d0ba5696254201a5a7d2b35652f0af
[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(void) __attribute__((constructor));
79 static void __deinit_lib(void) __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 local_volume = rm->__max_resource_volumes[type];
583         mm_resource_manager_res_p i_res;
584         int i;
585
586         if (local_volume == MM_RESOURCE_MANAGER_NO_RES)
587                 MM_RM_ERROR("[#%"PRIu64" type : %d volume : %d] resource (#%d) for the platform",
588                         _mm_rm_hash64(rm->id), type, volume, local_volume);
589
590         if (volume > 0) {
591                 for (i = 0; i < rm->resources->len; i++) {
592                         i_res = (mm_resource_manager_res_p) rm->resources->pdata[i];
593                         if (i_res->type == type && i_res->state != MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE
594                                         && (i_res->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL
595                                                 || (local_volume -= i_res->volume) < volume)) {
596                                 MM_RM_ERROR("Requested volume %d exceeds remaining local volume %d",
597                                                 volume, i_res->volume == MM_RESOURCE_MANAGER_RES_VOLUME_FULL ?
598                                                 0 : local_volume);
599                                 return MM_RESOURCE_MANAGER_ERROR_NOT_ENOUGH;
600                         }
601                 }
602         }
603
604         return MM_RESOURCE_MANAGER_ERROR_NONE;
605 }
606
607 static int __create_resource(mm_resource_manager_s *rm,
608                 mm_resource_manager_res_type_e type,
609                 mm_resource_manager_res_volume volume, mm_resource_manager_res_p *res)
610 {
611         int ret;
612
613         mm_resource_manager_s *handle = MM_RESOURCE_MANAGER(rm);
614
615         MM_RM_RETVM_IF(handle == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER,
616                         "NULL handle pointer");
617         MM_RM_RETVM_IF(res == NULL, MM_RESOURCE_MANAGER_ERROR_INVALID_PARAMETER, "NULL pointer");
618         ret = __check_resource(rm, type, volume);
619         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
620                 return ret;
621
622         *res = g_new0(mm_resource_manager_res_s, 1);
623         (*res)->type = type;
624         (*res)->volume = volume;
625
626         return MM_RESOURCE_MANAGER_ERROR_NONE;
627 }
628
629 static void __destroy_resource(void *res)
630 {
631         g_free(res);
632 }
633
634 static int __get_resource_index(mm_resource_manager_s *rm, mm_resource_manager_res_p res)
635 {
636         int i;
637
638         for (i = 0; i < rm->resources->len; i++) {
639                 if (rm->resources->pdata[i] == (gpointer) res)
640                         return i;
641         }
642
643         return MM_RESOURCE_MANAGER_RES_NOT_FOUND;
644 }
645
646 static gboolean __mark_resource_for_release(GPtrArray *resources, int index,
647                 mm_resource_manager_res_p resource)
648 {
649         switch (resource->state) {
650         case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
651                 g_ptr_array_remove_index_fast(resources, index);
652                 MM_RM_DEBUG("Resource %p is removed implicitly", resource);
653                 return FALSE;
654         case MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED:
655                 resource->state = MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE;
656                 break;
657         case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
658                 MM_RM_DEBUG("Resource %p is already marked", resource);
659                 break;
660         }
661         return TRUE;
662 }
663
664
665 static gboolean __check_rm_handle(mm_resource_manager_s *handle)
666 {
667         int i;
668
669         for (i = 0; i < handles->len; i++) {
670                 if (g_ptr_array_index(handles, i) == handle)
671                         return TRUE;
672         }
673         return FALSE;
674 }
675
676 static void __send_release_cb_sync(mm_resource_manager_id id)
677 {
678         int sync_fd;
679
680         sync_fd = open(RELEASE_CB_SYNC_PATH, O_WRONLY);
681         MM_RM_RETM_IF(sync_fd == -1, "Sync FIFO cannot be opened");
682
683         if (write(sync_fd, &id, sizeof(id)) == sizeof(id))
684                 MM_RM_DEBUG("Sync message is sent successfully");
685         else
686                 MM_RM_ERROR("Sync message cannot be sent");
687
688         close(sync_fd);
689 }
690
691 static void __init_lib(void)
692 {
693         handles = g_ptr_array_sized_new(MM_RESOURCE_MANAGER_RESERVED_HANDLE_ARRAY_SIZE);
694         MM_RM_RETM_IF(handles == NULL, "API lib cannot be initialized");
695
696         MM_RM_INFO("API lib is loaded [%d] Set signal handler", _mm_resource_manager_set_signal_handlers());
697 }
698
699 static void __deinit_lib(void)
700 {
701         if (handles->len > 0) {
702                 MM_RM_DEBUG("Handles array [%d] is not empty. It will be cleaned now.", handles->len);
703                 while (handles->len > 0)
704                         _mm_resource_manager_destroy(handles->pdata[0]);
705         }
706
707         g_ptr_array_free(handles, TRUE);
708
709         MM_RM_INFO("API lib is unloaded");
710 }
711
712 static int __dbus_init(mm_resource_manager_s *handle)
713 {
714         GError *error = NULL;
715
716         MM_RM_RETVM_IF(handle->dbus_proxy != NULL,
717                         MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION,
718                         "Dbus proxy is not NULL");
719
720         g_main_context_push_thread_default(handle->dispatcher_context);
721         handle->dbus_proxy = mmresource_manager_proxy_new_for_bus_sync(
722                         G_BUS_TYPE_SYSTEM, 0, RMD_GDBUS_NAME, RMD_GDBUS_PATH, NULL, &error);
723         g_main_context_pop_thread_default(handle->dispatcher_context);
724         MM_RM_RET_IF_GERR(error, "Dbus proxy cannot be created");
725
726         if (g_signal_connect(handle->dbus_proxy, "release_callback",
727                         (GCallback)__dbus_release_callback, NULL) < 1 ||
728                         g_signal_connect(handle->dbus_proxy, "status_callback",
729                         (GCallback)__dbus_status_callback, NULL) < 1) {
730
731                 g_object_unref(handle->dbus_proxy);
732                 handle->dbus_proxy = NULL;
733                 MM_RM_ERROR("Release or status callback signals cannot be connected");
734
735                 return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
736         }
737
738         return MM_RESOURCE_MANAGER_ERROR_NONE;
739 }
740
741 static int __dbus_deinit(mm_resource_manager_s *handle)
742 {
743         MM_RM_RETVM_IF(handle->dbus_proxy == NULL,
744                         MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Dbus proxy is NULL");
745         g_object_unref(handle->dbus_proxy);
746         handle->dbus_proxy = NULL;
747         return MM_RESOURCE_MANAGER_ERROR_NONE;
748 }
749
750 static int __dbus_init_conf(mm_resource_manager_s *handle)
751 {
752         int i, j;
753         GError *error = NULL;
754         int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
755         GVariant *max_volume = NULL;
756         GVariant *cond_volume = NULL;
757         GVariant *max_instance = NULL;
758         GVariant *tmp;
759         GVariantIter volume_iter;
760         GVariantIter cond_volume_iter;
761
762         mmresource_manager_call_conf_sync(handle->dbus_proxy, &rm_error, &max_volume,
763                         &cond_volume, &max_instance, NULL, &error);
764         MM_RM_RET_IF_GERR(error, "DBus conf msg cannot be sent");
765
766         MM_RM_RETVM_IF(max_volume == NULL || cond_volume == NULL,
767                         MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION, "Variant data are empty");
768
769         if (g_variant_iter_init(&volume_iter, max_volume) == MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
770                 for (i = 0; g_variant_iter_next(&volume_iter, "i", &handle->__max_resource_volumes[i]); i++);
771                 g_variant_unref(max_volume);
772                 max_volume = NULL;
773         } else {
774                 MM_RM_ERROR("Wrong max volume array size");
775                 goto out;
776         }
777
778         if (g_variant_iter_init(&volume_iter, cond_volume) == MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
779                 for (i = 0; (tmp = g_variant_iter_next_value(&volume_iter)) != NULL; i++) {
780                         if (g_variant_iter_init(&cond_volume_iter, tmp) == MM_RESOURCE_MANAGER_RES_TYPE_COND_MAX) {
781                                 for (j = 0; g_variant_iter_next(&cond_volume_iter, "i", &handle->__condition_volumes[i][j]); j++);
782                                 g_variant_unref(tmp);
783                         } else {
784                                 g_variant_unref(tmp);
785                                 MM_RM_ERROR("Wrong condition volume array size");
786                                 rm_error = MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
787                                 break;
788                         }
789                 }
790                 g_variant_unref(cond_volume);
791                 cond_volume = NULL;
792         } else {
793                 MM_RM_ERROR("Wrong condition volume array size");
794                 goto out;
795         }
796
797         if (g_variant_iter_init(&volume_iter, max_instance) == MM_RESOURCE_MANAGER_RES_TYPE_MAX) {
798                 for (i = 0; g_variant_iter_next(&volume_iter, "i", &handle->__max_instance[i]); i++);
799                 g_variant_unref(max_instance);
800                 max_instance = NULL;
801         } else {
802                 MM_RM_ERROR("Wrong max instance array size");
803                 goto out;
804         }
805
806         return rm_error;
807 out:
808         g_variant_unref(max_volume);
809         g_variant_unref(cond_volume);
810         g_variant_unref(max_instance);
811         return MM_RESOURCE_MANAGER_ERROR_INVALID_OPERATION;
812 }
813
814 static int __dbus_create(mm_resource_manager_s *handle, mm_resource_manager_app_class_e app_class)
815 {
816         GError *error = NULL;
817         int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
818
819         mmresource_manager_call_create_sync(handle->dbus_proxy, app_class, &handle->id,
820                         &rm_error, NULL, &error);
821         MM_RM_RET_IF_GERR(error, "DBus create msg cannot be sent");
822
823         MM_RM_DEBUG("Create returned id - #%"PRIu64", error - %d",
824                         _mm_rm_hash64(handle->id), rm_error);
825
826         return rm_error;
827 }
828
829 static int __dbus_destroy(mm_resource_manager_s *handle)
830 {
831         GError *error = NULL;
832         int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
833
834         mmresource_manager_call_destroy_sync(handle->dbus_proxy, handle->id, &rm_error,
835                         NULL, &error);
836         MM_RM_RET_IF_GERR(error, "DBus destroy msg cannot be sent");
837
838         MM_RM_DEBUG("Destroy for id - #%"PRIu64" returned error - %d", _mm_rm_hash64(handle->id), rm_error);
839
840         return MM_RESOURCE_MANAGER_ERROR_NONE;
841 }
842
843 static int __dbus_commit(mm_resource_manager_s *handle)
844 {
845         GVariant *release;
846         GVariant *acquire;
847         GVariantBuilder *release_builder;
848         GVariantBuilder *acquire_builder;
849         GVariant *flags_variant;
850         GVariantIter flags_iter;
851         mm_resource_manager_res_p resource;
852         int i;
853         int release_num = 0;
854         int acquire_num = 0;
855         GError *error = NULL;
856         int rm_error = MM_RESOURCE_MANAGER_ERROR_NONE;
857
858         release_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
859         acquire_builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
860
861         for (i = 0; i < handle->resources->len; i++) {
862                 resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
863
864                 switch (resource->state) {
865                 case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
866                         g_variant_builder_add_value(acquire_builder, g_variant_new("(ii)",
867                                         resource->type, resource->volume));
868                         acquire_num++;
869                         break;
870                 case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
871                         g_variant_builder_add_value(release_builder, g_variant_new("(ii)",
872                                         resource->type, resource->volume));
873                         release_num++;
874                         break;
875                 default:
876                         break;
877                 }
878         }
879
880         if (release_num + acquire_num == 0) {
881                 g_variant_builder_unref(release_builder);
882                 g_variant_builder_unref(acquire_builder);
883                 MM_RM_DEBUG("There is nothing to commit - dbus request is not sent [%d %d]",
884                                 release_num, acquire_num);
885                 return rm_error;
886         }
887
888         /*
889          * Acquire and release arrays are ended with special element, because
890          * g_variant_builder_end crashes without at least one element
891          */
892         g_variant_builder_add_value(acquire_builder, g_variant_new("(ii)",
893                         MM_RESOURCE_MANAGER_NO_RES, 0));
894         acquire = g_variant_builder_end(acquire_builder);
895         g_variant_builder_unref(acquire_builder);
896
897         g_variant_builder_add_value(release_builder, g_variant_new("(ii)",
898                         MM_RESOURCE_MANAGER_NO_RES, 0));
899         release = g_variant_builder_end(release_builder);
900         g_variant_builder_unref(release_builder);
901
902         mmresource_manager_call_commit_sync(handle->dbus_proxy, handle->id, release,
903                         acquire, &rm_error, &flags_variant, NULL, &error);
904         if (error != NULL)
905                 MM_RM_RET_IF_GERR(error, "DBus commit msg cannot be sent");
906
907         MM_RM_DEBUG("Commit for id - #%"PRIu64" returned error - %d",
908                         _mm_rm_hash64(handle->id), rm_error);
909
910         if (rm_error == MM_RESOURCE_MANAGER_ERROR_NONE) {
911                 for (i = 0; i < handle->resources->len; i++) {
912                         resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
913
914                         switch (resource->state) {
915                         case MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE:
916                                 resource->state = MM_RESOURCE_MANAGER_RES_STATE_ACQUIRED;
917                                 resource->is_acquire_failed = FALSE;
918                                 break;
919                         case MM_RESOURCE_MANAGER_RES_STATE_FOR_RELEASE:
920                                 g_ptr_array_remove_index_fast(handle->resources, i--);
921                                 break;
922                         default:
923                                 ;
924                         }
925                 }
926         } else if (rm_error == MM_RESOURCE_MANAGER_ERROR_LOW_PRIORITY) {
927                 g_variant_iter_init(&flags_iter, flags_variant);
928
929                 for (i = 0; i < handle->resources->len; i++) {
930                         resource = (mm_resource_manager_res_p) handle->resources->pdata[i];
931
932                         if (resource->state == MM_RESOURCE_MANAGER_RES_STATE_FOR_ACQUIRE)
933                                 g_variant_iter_next(&flags_iter, "b", &resource->is_acquire_failed);
934                 }
935         }
936
937         g_variant_unref(flags_variant);
938
939         return rm_error;
940 }
941
942 static void __dbus_release_callback(MMResourceManager *object, guint64 arg_id,
943                 gint arg_resource_type, gint arg_volume)
944 {
945         mm_resource_manager_s *handle;
946         mm_resource_manager_id handle_id;
947         gboolean unlock = TRUE;
948         int i;
949
950         __mm_resource_handles_lock();
951
952         for (i = 0; i < handles->len; i++) {
953                 handle = (mm_resource_manager_s*)handles->pdata[i];
954                 handle_id = handle->id;
955                 MM_RM_HASH64(handle_id);
956                 if (handle->dbus_proxy == object && handle_id == arg_id) {
957                         __mm_resource_manager_release_callback(handle, arg_id,
958                                         arg_resource_type, arg_volume);
959                         unlock = FALSE;
960                         break;
961                 }
962         }
963
964         if (unlock)
965                 __mm_resource_handles_unlock();
966 }
967
968 static void __dbus_status_callback(MMResourceManager *object, gint arg_status)
969 {
970         mm_resource_manager_s *handle;
971         gboolean unlock = TRUE;
972         int i;
973
974         MM_RM_INFO("status callback status %d", arg_status);
975         __mm_resource_handles_lock();
976         for (i = 0; i < handles->len; i++) {
977                 handle = (mm_resource_manager_s*)handles->pdata[i];
978                 if (handle->dbus_proxy == object) {
979                         __mm_resource_manager_status_callback(handle, arg_status);
980                         unlock = FALSE;
981                         break;
982                 }
983         }
984
985         if (unlock)
986                 __mm_resource_handles_unlock();
987 }
988
989 static gpointer __dispatcher_thread(gpointer user_data)
990 {
991         GMainLoop *ml = (GMainLoop *) user_data;
992
993         if (ml) {
994                 g_main_loop_run(ml);
995                 MM_RM_INFO("main loop %p quit", ml);
996         }
997
998         return NULL;
999 }
1000
1001 static void __destroy_dispatcher(mm_resource_manager_s *handle)
1002 {
1003         if (__dbus_deinit(handle) != MM_RESOURCE_MANAGER_ERROR_NONE)
1004                 MM_RM_ERROR("Error while dbus deinitializing");
1005
1006         if (handle->dispatcher_loop) {
1007                 if (g_main_loop_is_running(handle->dispatcher_loop)) {
1008                         MM_RM_INFO("mainloop %p is running", handle->dispatcher_loop);
1009                         g_main_loop_quit(handle->dispatcher_loop);
1010                 }
1011                 g_main_loop_unref(handle->dispatcher_loop);
1012                 handle->dispatcher_loop = NULL;
1013         }
1014
1015         if (handle->dispatcher_thread) {
1016                 g_thread_join(handle->dispatcher_thread);
1017                 MM_RM_INFO("dispatcher thread join %p", handle->dispatcher_thread);
1018                 handle->dispatcher_thread = NULL;
1019         }
1020
1021         if (handle->dispatcher_context) {
1022                 g_main_context_unref(handle->dispatcher_context);
1023                 handle->dispatcher_context = NULL;
1024         }
1025 }