summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib/ecore/ecore_thread_promise.c126
-rw-r--r--src/lib/eina/eina_main.c7
-rw-r--r--src/lib/eina/eina_promise.c106
-rw-r--r--src/lib/eina/eina_promise.h14
-rw-r--r--src/tests/ecore/ecore_test_promise.c2
-rw-r--r--src/tests/eina/eina_test_promise.c27
6 files changed, 243 insertions, 39 deletions
diff --git a/src/lib/ecore/ecore_thread_promise.c b/src/lib/ecore/ecore_thread_promise.c
index dbc3ce9..1dea1bc 100644
--- a/src/lib/ecore/ecore_thread_promise.c
+++ b/src/lib/ecore/ecore_thread_promise.c
@@ -7,6 +7,8 @@
7 7
8#include <assert.h> 8#include <assert.h>
9 9
10#include <ecore_private.h>
11
10struct _Ecore_Thread_Data 12struct _Ecore_Thread_Data
11{ 13{
12 Ecore_Thread_Promise_Cb func_blocking; 14 Ecore_Thread_Promise_Cb func_blocking;
@@ -20,10 +22,38 @@ struct _Ecore_Thread_Promise_Owner
20{ 22{
21 Eina_Promise_Owner owner_vtable; 23 Eina_Promise_Owner owner_vtable;
22 Eina_Promise_Owner* eina_owner; 24 Eina_Promise_Owner* eina_owner;
25 Eina_Promise promise_vtable;
26 Eina_Promise* eina_promise;
23 _Ecore_Thread_Data thread_callback_data; 27 _Ecore_Thread_Data thread_callback_data;
28 int ref_count;
29 int then_count;
24}; 30};
25typedef struct _Ecore_Thread_Promise_Owner _Ecore_Thread_Promise_Owner; 31typedef struct _Ecore_Thread_Promise_Owner _Ecore_Thread_Promise_Owner;
26 32
33#define ECORE_PROMISE_GET_OWNER(p) (_Ecore_Thread_Promise_Owner*)((unsigned char*)p - offsetof(struct _Ecore_Thread_Promise_Owner, promise_vtable))
34
35static void _ecore_promise_ref_update(_Ecore_Thread_Promise_Owner* p)
36{
37 if(p->ref_count < 0)
38 {
39 ERR("Reference count is negative for promise %p\n", p);
40 }
41 if(!p->ref_count)
42 {
43 p->eina_promise->unref(p->eina_promise);
44 p->eina_promise = NULL;
45 p->eina_owner = NULL;
46 p->thread_callback_data.thread = NULL;
47 }
48}
49
50static void _ecore_promise_thread_release_ref(void* data, void* value EINA_UNUSED)
51{
52 _Ecore_Thread_Promise_Owner* p = data;
53 p->ref_count -= p->then_count;
54 _ecore_promise_ref_update(p);
55}
56
27static void _ecore_promise_thread_end(void* data, Ecore_Thread* thread EINA_UNUSED) 57static void _ecore_promise_thread_end(void* data, Ecore_Thread* thread EINA_UNUSED)
28{ 58{
29 _Ecore_Thread_Promise_Owner* p = data; 59 _Ecore_Thread_Promise_Owner* p = data;
@@ -31,10 +61,14 @@ static void _ecore_promise_thread_end(void* data, Ecore_Thread* thread EINA_UNUS
31 { 61 {
32 eina_promise_owner_default_manual_then_set(p->eina_owner, EINA_FALSE); 62 eina_promise_owner_default_manual_then_set(p->eina_owner, EINA_FALSE);
33 eina_promise_owner_default_call_then(p->eina_owner); 63 eina_promise_owner_default_call_then(p->eina_owner);
64 p->ref_count -= p->then_count;
65 _ecore_promise_ref_update(p);
34 } 66 }
35 else 67 else
36 { 68 {
37 eina_promise_owner_default_manual_then_set(p->eina_owner, EINA_FALSE); 69 eina_promise_owner_default_manual_then_set(p->eina_owner, EINA_FALSE);
70 eina_promise_then(p->eina_promise, &_ecore_promise_thread_release_ref,
71 (Eina_Promise_Error_Cb)&_ecore_promise_thread_release_ref, p);
38 } 72 }
39} 73}
40 74
@@ -51,7 +85,7 @@ static void _ecore_promise_thread_notify(void* data, Ecore_Thread* thread EINA_U
51 eina_promise_owner_progress(promise->eina_owner, msg_data); 85 eina_promise_owner_progress(promise->eina_owner, msg_data);
52} 86}
53 87
54static void _ecore_promise_cancel(void* data, Eina_Promise_Owner* promise EINA_UNUSED) 88static void _ecore_promise_cancel_cb(void* data, Eina_Promise_Owner* promise EINA_UNUSED)
55{ 89{
56 _Ecore_Thread_Promise_Owner* priv = data; 90 _Ecore_Thread_Promise_Owner* priv = data;
57 (priv->thread_callback_data.func_cancel)(priv->thread_callback_data.data, &priv->owner_vtable, 91 (priv->thread_callback_data.func_cancel)(priv->thread_callback_data.data, &priv->owner_vtable,
@@ -93,12 +127,76 @@ static Eina_Bool _ecore_promise_owner_cancelled_is(_Ecore_Thread_Promise_Owner c
93} 127}
94static Eina_Promise* _ecore_thread_promise_owner_promise_get(_Ecore_Thread_Promise_Owner* promise) 128static Eina_Promise* _ecore_thread_promise_owner_promise_get(_Ecore_Thread_Promise_Owner* promise)
95{ 129{
96 return promise->eina_owner->promise_get(promise->eina_owner); 130 return &promise->promise_vtable;
97} 131}
98static void _ecore_thread_promise_owner_progress(_Ecore_Thread_Promise_Owner* promise, void* data) 132static void _ecore_thread_promise_owner_progress(_Ecore_Thread_Promise_Owner* promise, void* data)
99{ 133{
100 ecore_thread_feedback(promise->thread_callback_data.thread, data); 134 ecore_thread_feedback(promise->thread_callback_data.thread, data);
101} 135}
136static void _ecore_thread_promise_owner_progress_notify(_Ecore_Thread_Promise_Owner* promise,
137 Eina_Promise_Progress_Notify_Cb progress_cb,
138 void* data, Eina_Promise_Free_Cb free_cb)
139{
140 promise->eina_owner->progress_notify(promise->eina_owner, progress_cb, data, free_cb);
141}
142
143static void _ecore_promise_then(Eina_Promise* promise, Eina_Promise_Cb callback,
144 Eina_Promise_Error_Cb error_cb, void* data)
145{
146 _Ecore_Thread_Promise_Owner* v = ECORE_PROMISE_GET_OWNER(promise);
147 v->eina_promise->then(v->eina_promise, callback, error_cb, data);
148 if(v->then_count)
149 {
150 v->ref_count++;
151 }
152 v->then_count++;
153}
154static void* _ecore_promise_value_get(Eina_Promise const* promise)
155{
156 _Ecore_Thread_Promise_Owner* v = ECORE_PROMISE_GET_OWNER(promise);
157 return v->eina_promise->value_get(v->eina_promise);
158}
159static Eina_Error _ecore_promise_error_get(Eina_Promise const* promise)
160{
161 _Ecore_Thread_Promise_Owner* v = ECORE_PROMISE_GET_OWNER(promise);
162 return v->eina_promise->error_get(v->eina_promise);
163}
164static Eina_Bool _ecore_promise_pending_is(Eina_Promise const* promise)
165{
166 _Ecore_Thread_Promise_Owner* v = ECORE_PROMISE_GET_OWNER(promise);
167 return v->eina_promise->pending_is(v->eina_promise);
168}
169static void _ecore_promise_progress_cb_add(Eina_Promise const* promise, Eina_Promise_Progress_Cb callback, void* data,
170 Eina_Promise_Free_Cb free_cb)
171{
172 _Ecore_Thread_Promise_Owner* v = ECORE_PROMISE_GET_OWNER(promise);
173 v->eina_promise->progress_cb_add(v->eina_promise, callback, data, free_cb);
174}
175static void _ecore_promise_cancel(Eina_Promise const* promise)
176{
177 _Ecore_Thread_Promise_Owner* v = ECORE_PROMISE_GET_OWNER(promise);
178 v->eina_promise->cancel(v->eina_promise);
179}
180static void _ecore_promise_ref(Eina_Promise const* promise)
181{
182 _Ecore_Thread_Promise_Owner* v = ECORE_PROMISE_GET_OWNER(promise);
183 ++v->ref_count;
184}
185static void _ecore_promise_unref(Eina_Promise const* promise)
186{
187 _Ecore_Thread_Promise_Owner* v = ECORE_PROMISE_GET_OWNER(promise);
188 --v->ref_count;
189}
190static void* _ecore_promise_buffer_get(Eina_Promise const* promise)
191{
192 _Ecore_Thread_Promise_Owner* v = ECORE_PROMISE_GET_OWNER(promise);
193 return v->eina_promise->buffer_get(v->eina_promise);
194}
195static size_t _ecore_promise_value_size_get(Eina_Promise const* promise)
196{
197 _Ecore_Thread_Promise_Owner* v = ECORE_PROMISE_GET_OWNER(promise);
198 return v->eina_promise->value_size_get(v->eina_promise);
199}
102 200
103Ecore_Thread* ecore_thread_promise_run(Ecore_Thread_Promise_Cb func_blocking, 201Ecore_Thread* ecore_thread_promise_run(Ecore_Thread_Promise_Cb func_blocking,
104 Ecore_Thread_Promise_Cb func_cancel, 202 Ecore_Thread_Promise_Cb func_cancel,
@@ -120,18 +218,36 @@ Ecore_Thread* ecore_thread_promise_run(Ecore_Thread_Promise_Cb func_blocking,
120 priv->owner_vtable.pending_is = EINA_FUNC_PROMISE_OWNER_PENDING_IS(&_ecore_promise_owner_pending_is); 218 priv->owner_vtable.pending_is = EINA_FUNC_PROMISE_OWNER_PENDING_IS(&_ecore_promise_owner_pending_is);
121 priv->owner_vtable.cancelled_is = EINA_FUNC_PROMISE_OWNER_CANCELLED_IS(&_ecore_promise_owner_cancelled_is); 219 priv->owner_vtable.cancelled_is = EINA_FUNC_PROMISE_OWNER_CANCELLED_IS(&_ecore_promise_owner_cancelled_is);
122 priv->owner_vtable.progress = EINA_FUNC_PROMISE_OWNER_PROGRESS(&_ecore_thread_promise_owner_progress); 220 priv->owner_vtable.progress = EINA_FUNC_PROMISE_OWNER_PROGRESS(&_ecore_thread_promise_owner_progress);
123 221 priv->owner_vtable.progress_notify = EINA_FUNC_PROMISE_OWNER_PROGRESS_NOTIFY(&_ecore_thread_promise_owner_progress_notify);
222
223 priv->promise_vtable.then = EINA_FUNC_PROMISE_THEN(&_ecore_promise_then);
224 priv->promise_vtable.value_get = EINA_FUNC_PROMISE_VALUE_GET(&_ecore_promise_value_get);
225 priv->promise_vtable.error_get = EINA_FUNC_PROMISE_ERROR_GET(&_ecore_promise_error_get);
226 priv->promise_vtable.pending_is = EINA_FUNC_PROMISE_PENDING_IS(&_ecore_promise_pending_is);
227 priv->promise_vtable.progress_cb_add = EINA_FUNC_PROMISE_PROGRESS_CB_ADD(&_ecore_promise_progress_cb_add);
228 priv->promise_vtable.cancel = EINA_FUNC_PROMISE_CANCEL(&_ecore_promise_cancel);
229 priv->promise_vtable.ref = EINA_FUNC_PROMISE_REF(&_ecore_promise_ref);
230 priv->promise_vtable.unref = EINA_FUNC_PROMISE_UNREF(&_ecore_promise_unref);
231 priv->promise_vtable.value_size_get = EINA_FUNC_PROMISE_VALUE_SIZE_GET(&_ecore_promise_value_size_get);
232 priv->promise_vtable.buffer_get = EINA_FUNC_PROMISE_BUFFER_GET(&_ecore_promise_buffer_get);
233
124 priv->thread_callback_data.data = data; 234 priv->thread_callback_data.data = data;
125 priv->thread_callback_data.func_blocking = func_blocking; 235 priv->thread_callback_data.func_blocking = func_blocking;
126 priv->thread_callback_data.func_cancel = func_cancel; 236 priv->thread_callback_data.func_cancel = func_cancel;
127 eina_promise_owner_default_manual_then_set(priv->eina_owner, EINA_TRUE); 237 eina_promise_owner_default_manual_then_set(priv->eina_owner, EINA_TRUE);
238
239 priv->eina_promise = priv->eina_owner->promise_get(priv->eina_owner);
240 priv->eina_promise->ref(priv->eina_promise);
241 priv->ref_count = 0;
242 priv->then_count = 0;
243
128 if(func_cancel) 244 if(func_cancel)
129 eina_promise_owner_default_cancel_cb_add(priv->eina_owner, &_ecore_promise_cancel, priv, NULL); 245 eina_promise_owner_default_cancel_cb_add(priv->eina_owner, &_ecore_promise_cancel_cb, priv, NULL);
130 priv->thread_callback_data.thread = 246 priv->thread_callback_data.thread =
131 ecore_thread_feedback_run(&_ecore_promise_thread_blocking, &_ecore_promise_thread_notify, 247 ecore_thread_feedback_run(&_ecore_promise_thread_blocking, &_ecore_promise_thread_notify,
132 &_ecore_promise_thread_end, &_ecore_promise_thread_cancel, priv, 248 &_ecore_promise_thread_end, &_ecore_promise_thread_cancel, priv,
133 EINA_FALSE); 249 EINA_FALSE);
134 if(promise) 250 if(promise)
135 *promise = priv->eina_owner->promise_get(priv->eina_owner); 251 *promise = priv->eina_promise;
136 return priv->thread_callback_data.thread; 252 return priv->thread_callback_data.thread;
137} 253}
diff --git a/src/lib/eina/eina_main.c b/src/lib/eina/eina_main.c
index ffa9c98..52c548e 100644
--- a/src/lib/eina/eina_main.c
+++ b/src/lib/eina/eina_main.c
@@ -87,7 +87,6 @@ static int _eina_main_count = 0;
87static int _eina_main_thread_count = 0; 87static int _eina_main_thread_count = 0;
88#endif 88#endif
89static int _eina_log_dom = -1; 89static int _eina_log_dom = -1;
90void _eina_promise_init(void);
91 90
92#ifdef ERR 91#ifdef ERR
93#undef ERR 92#undef ERR
@@ -155,6 +154,7 @@ EAPI Eina_Inlist *_eina_tracking = NULL;
155 S(cpu); 154 S(cpu);
156 S(thread_queue); 155 S(thread_queue);
157 S(rbtree); 156 S(rbtree);
157 S(promise);
158/* no model for now 158/* no model for now
159 S(model); 159 S(model);
160 */ 160 */
@@ -201,7 +201,8 @@ static const struct eina_desc_setup _eina_desc_setup[] = {
201 S(cow), 201 S(cow),
202 S(cpu), 202 S(cpu),
203 S(thread_queue), 203 S(thread_queue),
204 S(rbtree) 204 S(rbtree),
205 S(promise)
205/* no model for now 206/* no model for now
206 S(model) 207 S(model)
207 */ 208 */
@@ -300,8 +301,6 @@ eina_init(void)
300 } 301 }
301 } 302 }
302 303
303 _eina_promise_init();
304
305 eina_cpu_count_internal(); 304 eina_cpu_count_internal();
306 305
307 eina_log_timing(_eina_log_dom, EINA_LOG_STATE_STOP, EINA_LOG_STATE_INIT); 306 eina_log_timing(_eina_log_dom, EINA_LOG_STATE_STOP, EINA_LOG_STATE_INIT);
diff --git a/src/lib/eina/eina_promise.c b/src/lib/eina/eina_promise.c
index 2f83dc4..2fe19a4 100644
--- a/src/lib/eina/eina_promise.c
+++ b/src/lib/eina/eina_promise.c
@@ -4,8 +4,17 @@
4 4
5#include <Eina.h> 5#include <Eina.h>
6 6
7#include <eina_private.h>
8
7#include <assert.h> 9#include <assert.h>
8 10
11static int _eina_promise_log_dom = -1;
12
13#ifdef ERR
14#undef ERR
15#endif
16#define ERR(...) EINA_LOG_DOM_ERR(_eina_promise_log_dom, __VA_ARGS__)
17
9typedef struct _Eina_Promise_Then_Cb _Eina_Promise_Then_Cb; 18typedef struct _Eina_Promise_Then_Cb _Eina_Promise_Then_Cb;
10typedef struct _Eina_Promise_Progress_Cb _Eina_Promise_Progress_Cb; 19typedef struct _Eina_Promise_Progress_Cb _Eina_Promise_Progress_Cb;
11typedef struct _Eina_Promise_Cancel_Cb _Eina_Promise_Cancel_Cb; 20typedef struct _Eina_Promise_Cancel_Cb _Eina_Promise_Cancel_Cb;
@@ -29,6 +38,7 @@ struct _Eina_Promise_Progress_Cb
29 EINA_INLIST; 38 EINA_INLIST;
30 39
31 Eina_Promise_Progress_Cb callback; 40 Eina_Promise_Progress_Cb callback;
41 Eina_Promise_Free_Cb free;
32 void* data; 42 void* data;
33}; 43};
34 44
@@ -94,6 +104,22 @@ struct _Eina_Promise_Iterator
94 } data; 104 } data;
95}; 105};
96 106
107static void _eina_promise_free_progress_callback_node(void* node)
108{
109 _Eina_Promise_Progress_Cb *progress_cb = node;
110 if(progress_cb->free)
111 progress_cb->free(progress_cb->data);
112 free(progress_cb);
113}
114
115static void _eina_promise_free_progress_notify_callback_node(void* node)
116{
117 _Eina_Promise_Owner_Progress_Notify_Data *progress_notify_cb = node;
118 if(progress_notify_cb->free_cb)
119 progress_notify_cb->free_cb(progress_notify_cb->data);
120 free(progress_notify_cb);
121}
122
97static void _eina_promise_finish(_Eina_Promise_Default_Owner* promise); 123static void _eina_promise_finish(_Eina_Promise_Default_Owner* promise);
98static void _eina_promise_ref(_Eina_Promise_Default* promise); 124static void _eina_promise_ref(_Eina_Promise_Default* promise);
99static void _eina_promise_unref(_Eina_Promise_Default* promise); 125static void _eina_promise_unref(_Eina_Promise_Default* promise);
@@ -119,14 +145,14 @@ static void
119_eina_promise_then_calls(_Eina_Promise_Default_Owner* promise) 145_eina_promise_then_calls(_Eina_Promise_Default_Owner* promise)
120{ 146{
121 _Eina_Promise_Then_Cb* callback; 147 _Eina_Promise_Then_Cb* callback;
122 Eina_Inlist* list2;
123 Eina_Bool error; 148 Eina_Bool error;
124 149
125 _eina_promise_ref(&promise->promise); 150 _eina_promise_ref(&promise->promise);
126 error = promise->promise.has_errored; 151 error = promise->promise.has_errored;
127 152
128 EINA_INLIST_FOREACH_SAFE(promise->promise.then_callbacks, list2, callback) 153 EINA_INLIST_FREE(promise->promise.then_callbacks, callback)
129 { 154 {
155 promise->promise.then_callbacks = eina_inlist_remove(promise->promise.then_callbacks, EINA_INLIST_GET(callback));
130 if (error) 156 if (error)
131 { 157 {
132 if (callback->error_cb) 158 if (callback->error_cb)
@@ -136,6 +162,7 @@ _eina_promise_then_calls(_Eina_Promise_Default_Owner* promise)
136 { 162 {
137 (*callback->callback)(callback->data, &promise->value[0]); 163 (*callback->callback)(callback->data, &promise->value[0]);
138 } 164 }
165 free(callback);
139 _eina_promise_unref(&promise->promise); 166 _eina_promise_unref(&promise->promise);
140 } 167 }
141 _eina_promise_unref(&promise->promise); 168 _eina_promise_unref(&promise->promise);
@@ -145,14 +172,15 @@ static void
145_eina_promise_cancel_calls(_Eina_Promise_Default_Owner* promise, Eina_Bool call_cancel EINA_UNUSED) 172_eina_promise_cancel_calls(_Eina_Promise_Default_Owner* promise, Eina_Bool call_cancel EINA_UNUSED)
146{ 173{
147 _Eina_Promise_Cancel_Cb* callback; 174 _Eina_Promise_Cancel_Cb* callback;
148 Eina_Inlist* list2;
149 175
150 EINA_INLIST_FOREACH_SAFE(promise->promise.cancel_callbacks, list2, callback) 176 EINA_INLIST_FREE(promise->promise.cancel_callbacks, callback)
151 { 177 {
152 if (callback->callback) 178 promise->promise.cancel_callbacks = eina_inlist_remove(promise->promise.cancel_callbacks, EINA_INLIST_GET(callback));
153 { 179 if (callback->callback)
154 (*callback->callback)(callback->data, (Eina_Promise_Owner*)promise); 180 {
155 } 181 (*callback->callback)(callback->data, (Eina_Promise_Owner*)promise);
182 }
183 free(callback);
156 } 184 }
157 185
158 if (!promise->promise.is_manual_then) 186 if (!promise->promise.is_manual_then)
@@ -164,15 +192,19 @@ _eina_promise_cancel_calls(_Eina_Promise_Default_Owner* promise, Eina_Bool call_
164static void 192static void
165_eina_promise_del(_Eina_Promise_Default_Owner* promise) 193_eina_promise_del(_Eina_Promise_Default_Owner* promise)
166{ 194{
167 if (promise->promise.has_finished) 195 if (!promise->promise.has_finished)
168 {
169 if (promise->promise.value_free_cb)
170 promise->promise.value_free_cb((void*)&promise->value[0]);
171 }
172 else
173 { 196 {
174 _eina_promise_cancel_calls(promise, EINA_TRUE); 197 ERR("Promise is being deleted, despite not being finished yet. This will cause intermitent crashes");
175 } 198 }
199
200 if (promise->promise.value_free_cb)
201 promise->promise.value_free_cb((void*)&promise->value[0]);
202
203 _eina_promise_free_callback_list(&promise->promise.progress_callbacks,
204 &_eina_promise_free_progress_callback_node);
205 _eina_promise_free_callback_list(&promise->promise.progress_notify_callbacks,
206 &_eina_promise_free_progress_notify_callback_node);
207 free(promise);
176} 208}
177 209
178static void * 210static void *
@@ -234,8 +266,9 @@ _eina_promise_then(_Eina_Promise_Default* p, Eina_Promise_Cb callback,
234 if (!promise->promise.is_first_then) 266 if (!promise->promise.is_first_then)
235 { 267 {
236 _eina_promise_ref(p); 268 _eina_promise_ref(p);
237 promise->promise.is_first_then = EINA_FALSE;
238 } 269 }
270 else
271 promise->promise.is_first_then = EINA_FALSE;
239 if (promise->promise.has_finished) 272 if (promise->promise.has_finished)
240 { 273 {
241 _eina_promise_then_calls(promise); 274 _eina_promise_then_calls(promise);
@@ -259,6 +292,10 @@ _eina_promise_finish(_Eina_Promise_Default_Owner* promise)
259 { 292 {
260 _eina_promise_then_calls(promise); 293 _eina_promise_then_calls(promise);
261 } 294 }
295 if(promise->promise.ref == 0)
296 {
297 _eina_promise_del(promise);
298 }
262} 299}
263 300
264static Eina_Error 301static Eina_Error
@@ -293,7 +330,8 @@ _eina_promise_owner_cancelled_is(_Eina_Promise_Default_Owner const* promise)
293} 330}
294 331
295static void 332static void
296_eina_promise_progress_cb_add(_Eina_Promise_Default* promise, Eina_Promise_Progress_Cb callback, void* data) 333_eina_promise_progress_cb_add(_Eina_Promise_Default* promise, Eina_Promise_Progress_Cb callback, void* data,
334 Eina_Promise_Free_Cb free_cb)
297{ 335{
298 _Eina_Promise_Progress_Cb* cb; 336 _Eina_Promise_Progress_Cb* cb;
299 _Eina_Promise_Owner_Progress_Notify_Data* notify_data; 337 _Eina_Promise_Owner_Progress_Notify_Data* notify_data;
@@ -302,13 +340,15 @@ _eina_promise_progress_cb_add(_Eina_Promise_Default* promise, Eina_Promise_Progr
302 cb = malloc(sizeof(struct _Eina_Promise_Progress_Cb)); 340 cb = malloc(sizeof(struct _Eina_Promise_Progress_Cb));
303 cb->callback = callback; 341 cb->callback = callback;
304 cb->data = data; 342 cb->data = data;
343 cb->free = free_cb;
305 promise->progress_callbacks = eina_inlist_append(promise->progress_callbacks, EINA_INLIST_GET(cb)); 344 promise->progress_callbacks = eina_inlist_append(promise->progress_callbacks, EINA_INLIST_GET(cb));
306 345
307 EINA_INLIST_FOREACH(owner->promise.progress_notify_callbacks, notify_data) 346 EINA_INLIST_FOREACH(owner->promise.progress_notify_callbacks, notify_data)
308 { 347 {
309 (*notify_data->callback)(notify_data->data, &owner->owner_vtable); 348 (*notify_data->callback)(notify_data->data, &owner->owner_vtable);
310 } 349 }
311 _eina_promise_free_callback_list(&owner->promise.progress_notify_callbacks, &free); 350 _eina_promise_free_callback_list(&owner->promise.progress_notify_callbacks,
351 &_eina_promise_free_progress_notify_callback_node);
312} 352}
313 353
314static void 354static void
@@ -393,7 +433,8 @@ _eina_promise_owner_progress(_Eina_Promise_Default_Owner* promise, void* data)
393 433
394 EINA_INLIST_FOREACH_SAFE(promise->promise.progress_callbacks, list2, callback) 434 EINA_INLIST_FOREACH_SAFE(promise->promise.progress_callbacks, list2, callback)
395 { 435 {
396 (*callback->callback)(callback->data, data); 436 if(callback->callback)
437 (*callback->callback)(callback->data, data);
397 } 438 }
398} 439}
399 440
@@ -605,6 +646,7 @@ _eina_promise_progress_notify_fulfilled(void* data, Eina_Promise_Owner* p EINA_U
605} 646}
606 647
607EAPI Eina_Error EINA_ERROR_PROMISE_NO_NOTIFY; 648EAPI Eina_Error EINA_ERROR_PROMISE_NO_NOTIFY;
649EAPI Eina_Error EINA_ERROR_PROMISE_CANCEL;
608 650
609static void 651static void
610_eina_promise_progress_notify_failed(void* data) 652_eina_promise_progress_notify_failed(void* data)
@@ -666,9 +708,10 @@ eina_promise_pending_is(Eina_Promise const* promise)
666} 708}
667 709
668EAPI void 710EAPI void
669eina_promise_progress_cb_add(Eina_Promise* promise, Eina_Promise_Progress_Cb callback, void* data) 711eina_promise_progress_cb_add(Eina_Promise* promise, Eina_Promise_Progress_Cb callback, void* data,
712 Eina_Promise_Free_Cb free_cb)
670{ 713{
671 promise->progress_cb_add(promise, callback, data); 714 promise->progress_cb_add(promise, callback, data, free_cb);
672} 715}
673 716
674EAPI void 717EAPI void
@@ -739,8 +782,27 @@ eina_promise_owner_progress_notify(Eina_Promise_Owner* promise, Eina_Promise_Pro
739} 782}
740 783
741static const char EINA_ERROR_PROMISE_NO_NOTIFY_STR[] = "Out of memory"; 784static const char EINA_ERROR_PROMISE_NO_NOTIFY_STR[] = "Out of memory";
785static const char EINA_ERROR_PROMISE_CANCEL_STR[] = "Promise cancelled";
742 786
743void _eina_promise_init() 787Eina_Bool eina_promise_init()
744{ 788{
745 EINA_ERROR_PROMISE_NO_NOTIFY = eina_error_msg_static_register(EINA_ERROR_PROMISE_NO_NOTIFY_STR); 789 EINA_ERROR_PROMISE_NO_NOTIFY = eina_error_msg_static_register(EINA_ERROR_PROMISE_NO_NOTIFY_STR);
790 EINA_ERROR_PROMISE_CANCEL = eina_error_msg_static_register(EINA_ERROR_PROMISE_CANCEL_STR);
791
792 _eina_promise_log_dom = eina_log_domain_register("eina_promise",
793 EINA_LOG_COLOR_DEFAULT);
794 if (_eina_promise_log_dom < 0)
795 {
796 EINA_LOG_ERR("Could not register log domain: eina_promise");
797 return EINA_FALSE;
798 }
799
800 return EINA_TRUE;
801}
802
803Eina_Bool eina_promise_shutdown()
804{
805 eina_log_domain_unregister(_eina_promise_log_dom);
806 _eina_promise_log_dom = -1;
807 return EINA_TRUE;
746} 808}
diff --git a/src/lib/eina/eina_promise.h b/src/lib/eina/eina_promise.h
index 75508be..51bdb80 100644
--- a/src/lib/eina/eina_promise.h
+++ b/src/lib/eina/eina_promise.h
@@ -71,7 +71,8 @@ typedef Eina_Bool(*Eina_Promise_Pending_Is_Cb)(Eina_Promise const* promise);
71/* 71/*
72 * @brief Function callback type for promise's progress add function override 72 * @brief Function callback type for promise's progress add function override
73 */ 73 */
74typedef void(*Eina_Promise_Progress_Cb_Add_Cb)(Eina_Promise* promise, Eina_Promise_Progress_Cb callback, void* data); 74typedef void(*Eina_Promise_Progress_Cb_Add_Cb)(Eina_Promise* promise, Eina_Promise_Progress_Cb callback, void* data
75 , Eina_Promise_Free_Cb free_cb);
75 76
76#define EINA_FUNC_PROMISE_PROGRESS_CB_ADD(Function) ((Eina_Promise_Progress_Cb_Add_Cb)Function) 77#define EINA_FUNC_PROMISE_PROGRESS_CB_ADD(Function) ((Eina_Promise_Progress_Cb_Add_Cb)Function)
77 78
@@ -338,7 +339,8 @@ EAPI Eina_Bool eina_promise_pending_is(Eina_Promise const* promise);
338 * @param progress The callback to be called when progress is made 339 * @param progress The callback to be called when progress is made
339 * @param data The private data that will be passed to the progress callback 340 * @param data The private data that will be passed to the progress callback
340 */ 341 */
341EAPI void eina_promise_progress_cb_add(Eina_Promise* promise, Eina_Promise_Progress_Cb progress, void* data); 342EAPI void eina_promise_progress_cb_add(Eina_Promise* promise, Eina_Promise_Progress_Cb progress, void* data,
343 Eina_Promise_Free_Cb free_cb);
342 344
343/* 345/*
344 * @brief Increments the reference count for the Eina_Promise 346 * @brief Increments the reference count for the Eina_Promise
@@ -483,6 +485,14 @@ EAPI void eina_promise_owner_default_call_then(Eina_Promise_Owner* promise);
483 */ 485 */
484EAPI extern Eina_Error EINA_ERROR_PROMISE_NO_NOTIFY; 486EAPI extern Eina_Error EINA_ERROR_PROMISE_NO_NOTIFY;
485 487
488/**
489 * @var EINA_ERROR_PROMISE_CANCEL
490 *
491 * @brief The error identifier corresponding to when a promise was
492 * cancelled before the callback can be called
493 */
494EAPI extern Eina_Error EINA_ERROR_PROMISE_CANCEL;
495
486/* 496/*
487 * @internal 497 * @internal
488 */ 498 */
diff --git a/src/tests/ecore/ecore_test_promise.c b/src/tests/ecore/ecore_test_promise.c
index f137d65..5a54281 100644
--- a/src/tests/ecore/ecore_test_promise.c
+++ b/src/tests/ecore/ecore_test_promise.c
@@ -378,7 +378,7 @@ START_TEST(ecore_test_promise_progress_promise)
378 378
379 ecore_thread_promise_run(&promise_progress_thread, NULL, NULL, 0, &promise); 379 ecore_thread_promise_run(&promise_progress_thread, NULL, NULL, 0, &promise);
380 380
381 eina_promise_progress_cb_add(promise, &_progress_callback, NULL); 381 eina_promise_progress_cb_add(promise, &_progress_callback, NULL, NULL);
382 382
383 ecore_main_loop_begin(); 383 ecore_main_loop_begin();
384 384
diff --git a/src/tests/eina/eina_test_promise.c b/src/tests/eina/eina_test_promise.c
index f21f5ff..59199e1 100644
--- a/src/tests/eina/eina_test_promise.c
+++ b/src/tests/eina/eina_test_promise.c
@@ -226,7 +226,7 @@ START_TEST(eina_test_promise_progress)
226 owner = eina_promise_default_add(0); 226 owner = eina_promise_default_add(0);
227 227
228 promise = eina_promise_owner_promise_get(owner); 228 promise = eina_promise_owner_promise_get(owner);
229 eina_promise_progress_cb_add(promise, &progress_callback, &progress_ran); 229 eina_promise_progress_cb_add(promise, &progress_callback, &progress_ran, NULL);
230 230
231 eina_promise_owner_progress(owner, &i); 231 eina_promise_owner_progress(owner, &i);
232 232
@@ -254,8 +254,8 @@ START_TEST(eina_test_promise_progress_notify1)
254 eina_promise_owner_progress_notify(owner, &progress_notify, &progress_notify_ran, NULL); 254 eina_promise_owner_progress_notify(owner, &progress_notify, &progress_notify_ran, NULL);
255 255
256 promise = eina_promise_owner_promise_get(owner); 256 promise = eina_promise_owner_promise_get(owner);
257 eina_promise_progress_cb_add(promise, &progress_callback, NULL); // never run 257 eina_promise_progress_cb_add(promise, &progress_callback, NULL, NULL); // never run
258 eina_promise_progress_cb_add(promise, &progress_callback, NULL); // never run 258 eina_promise_progress_cb_add(promise, &progress_callback, NULL, NULL); // never run
259 259
260 ck_assert(progress_notify_ran); 260 ck_assert(progress_notify_ran);
261 261
@@ -311,8 +311,8 @@ START_TEST(eina_test_promise_progress_notify3)
311 &_eina_promise_progress_notify_error, &progress_notify_ran); 311 &_eina_promise_progress_notify_error, &progress_notify_ran);
312 312
313 promise = eina_promise_owner_promise_get(owner); 313 promise = eina_promise_owner_promise_get(owner);
314 eina_promise_progress_cb_add(promise, &progress_callback, NULL); // never run 314 eina_promise_progress_cb_add(promise, &progress_callback, NULL, NULL); // never run
315 eina_promise_progress_cb_add(promise, &progress_callback, NULL); // never run 315 eina_promise_progress_cb_add(promise, &progress_callback, NULL, NULL); // never run
316 316
317 ck_assert(progress_notify_ran); 317 ck_assert(progress_notify_ran);
318 318
@@ -320,6 +320,22 @@ START_TEST(eina_test_promise_progress_notify3)
320} 320}
321END_TEST 321END_TEST
322 322
323START_TEST(eina_test_promise_ignored)
324{
325 Eina_Promise_Owner* owner;
326 Eina_Promise* promise;
327
328 eina_init();
329
330 owner = eina_promise_default_add(0);
331 promise = eina_promise_owner_promise_get(owner);
332 eina_promise_unref(promise);
333 eina_promise_owner_value_set(owner, NULL, NULL);
334
335 eina_shutdown();
336}
337END_TEST
338
323void 339void
324eina_test_promise(TCase *tc) 340eina_test_promise(TCase *tc)
325{ 341{
@@ -333,4 +349,5 @@ eina_test_promise(TCase *tc)
333 tcase_add_test(tc, eina_test_promise_progress_notify1); 349 tcase_add_test(tc, eina_test_promise_progress_notify1);
334 tcase_add_test(tc, eina_test_promise_progress_notify2); 350 tcase_add_test(tc, eina_test_promise_progress_notify2);
335 tcase_add_test(tc, eina_test_promise_progress_notify3); 351 tcase_add_test(tc, eina_test_promise_progress_notify3);
352 tcase_add_test(tc, eina_test_promise_ignored);
336} 353}