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