summaryrefslogtreecommitdiff
path: root/src/lib/ecore/ecore_idler.c
blob: 06f3965a18cd51458f4f030efb24a493759f4e80 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <stdlib.h>

#include <Eo.h>

#include "Ecore.h"
#include "ecore_private.h"

struct _Ecore_Factorized_Idle
{
   Ecore_Task_Cb func;
   void         *data;

   const Efl_Callback_Array_Item *desc;

   short         references;
   Eina_Bool     delete_me : 1;
};

void
_ecore_factorized_idle_event_del(void *data, const Efl_Event *event EINA_UNUSED)
{
   _ecore_factorized_idle_del(data);
}

void
_ecore_factorized_idle_process(void *data, const Efl_Event *event EINA_UNUSED)
{
   Ecore_Factorized_Idle *idler = data;

   idler->references++;
   if (!_ecore_call_task_cb(idler->func, idler->data))
     idler->delete_me = EINA_TRUE;
   idler->references--;

   if (idler->delete_me &&
       idler->references == 0)
     _ecore_factorized_idle_del(idler);
}

void *
_ecore_factorized_idle_del(Ecore_Idler *idler)
{
   void *data;

   if (!idler) return NULL;
   EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);

   if (idler->references > 0)
     {
        idler->delete_me = EINA_TRUE;
        return idler->data;
     }

   efl_event_callback_array_del(_mainloop_singleton, idler->desc, idler);

   data = idler->data;
   free(idler);
   return data;
}

Ecore_Factorized_Idle *
_ecore_factorized_idle_add(const Efl_Callback_Array_Item *desc,
                           Ecore_Task_Cb func,
                           const void   *data)
{
   Ecore_Factorized_Idle *ret;

   if (EINA_UNLIKELY(!eina_main_loop_is()))
     {
        EINA_MAIN_LOOP_CHECK_RETURN;
     }

   if (!func)
     {
        ERR("callback function must be set up for an object of Ecore_Idler.");
        return NULL;
     }

   ret = malloc(sizeof (Ecore_Idler));
   if (!ret) return NULL;

   ret->func = func;
   ret->data = (void*) data;
   ret->desc = desc;
   ret->references = 0;
   ret->delete_me = EINA_FALSE;

   efl_event_callback_array_add(_mainloop_singleton, desc, ret);

   return ret;
}

/* Specific to Ecore_Idler implementation */

EFL_CALLBACKS_ARRAY_DEFINE(ecore_idler_callbacks,
                          { EFL_LOOP_EVENT_IDLE, _ecore_factorized_idle_process },
                          { EFL_EVENT_DEL, _ecore_factorized_idle_event_del });

EAPI Ecore_Idler *
ecore_idler_add(Ecore_Task_Cb func,
                const void   *data)
{
   return _ecore_factorized_idle_add(ecore_idler_callbacks(), func, data);
}

EAPI void *
ecore_idler_del(Ecore_Idler *idler)
{
   return _ecore_factorized_idle_del(idler);
}

void
_ecore_idler_all_call(Eo *loop)
{
   efl_event_callback_call(loop, EFL_LOOP_EVENT_IDLE, NULL);
   // just spin in an idler until the free queue is empty freeing 84 items
   // from the free queue each time.for now this seems like an ok balance
   // between going in and out of a reduce func with mutexes around it
   // vs blocking mainloop for too long. this number is up for discussion
   eina_freeq_reduce(eina_freeq_main_get(), 84);
}

int
_ecore_idler_exist(Eo *loop)
{
   Efl_Loop_Data *dt = efl_data_scope_get(loop, EFL_LOOP_CLASS);

   return dt->idlers || eina_freeq_ptr_pending(eina_freeq_main_get());
}