summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFelipe Magno de Almeida <felipe@expertisesolutions.com.br>2016-03-06 17:39:20 -0300
committerFelipe Magno de Almeida <felipe@expertisesolutions.com.br>2016-03-06 17:55:33 -0300
commitf9ba80ab33e0b94dad7ec103e6d261a644f7835f (patch)
tree9b730dbf2ba46e47b6b2b7b49c622a021bff1a1c /src
parentd723990955289a5ca62605262f4bc4cd0aa8d25f (diff)
ecore: Create Promises
Add a promise object that allows Eolian interface to include promises as a way to have asynchronous value return and composibility. The usage is like this in a .eo file: class Foo { methods { bar { params { promise: Promise<int>; } } } } Which will create the following API interface: void foo_bar(Ecore_Promise** promise); and the equivalent declaration for implementation. However, the API function will instantiate the Promise for the user and the implementer of the class.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile_Ecore.am5
-rw-r--r--src/bin/eolian/eo_generator.c30
-rw-r--r--src/lib/ecore/Ecore.h1
-rw-r--r--src/lib/ecore/ecore_promise.c452
-rw-r--r--src/lib/ecore/ecore_promise.h136
-rw-r--r--src/lib/eo/Eo.h63
-rw-r--r--src/lib/eolian/eo_lexer.c3
-rw-r--r--src/lib/eolian/eo_lexer.h6
-rw-r--r--src/lib/eolian/eo_parser.c2
-rw-r--r--src/tests/ecore/ecore_suite.c1
-rw-r--r--src/tests/ecore/ecore_suite.h1
-rw-r--r--src/tests/ecore/ecore_test_promise.c364
12 files changed, 1042 insertions, 22 deletions
diff --git a/src/Makefile_Ecore.am b/src/Makefile_Ecore.am
index 49936af..79ac16c 100644
--- a/src/Makefile_Ecore.am
+++ b/src/Makefile_Ecore.am
@@ -47,7 +47,8 @@ lib/ecore/Ecore.h \
47lib/ecore/Ecore_Common.h \ 47lib/ecore/Ecore_Common.h \
48lib/ecore/Ecore_Legacy.h \ 48lib/ecore/Ecore_Legacy.h \
49lib/ecore/Ecore_Eo.h \ 49lib/ecore/Ecore_Eo.h \
50lib/ecore/Ecore_Getopt.h 50lib/ecore/Ecore_Getopt.h \
51lib/ecore/ecore_promise.h
51 52
52nodist_installed_ecoremainheaders_DATA = \ 53nodist_installed_ecoremainheaders_DATA = \
53 $(ecore_eolian_h) 54 $(ecore_eolian_h)
@@ -72,6 +73,7 @@ lib/ecore/ecore_timer.c \
72lib/ecore/ecore_thread.c \ 73lib/ecore/ecore_thread.c \
73lib/ecore/ecore_throttle.c \ 74lib/ecore/ecore_throttle.c \
74lib/ecore/ecore_exe.c \ 75lib/ecore/ecore_exe.c \
76lib/ecore/ecore_promise.c \
75lib/ecore/ecore_exe_private.h \ 77lib/ecore/ecore_exe_private.h \
76lib/ecore/ecore_private.h 78lib/ecore/ecore_private.h
77 79
@@ -199,6 +201,7 @@ tests/ecore/ecore_test_animator.c \
199tests/ecore/ecore_test_ecore_thread_eina_thread_queue.c \ 201tests/ecore/ecore_test_ecore_thread_eina_thread_queue.c \
200tests/ecore/ecore_test_ecore_input.c \ 202tests/ecore/ecore_test_ecore_input.c \
201tests/ecore/ecore_test_ecore_file.c \ 203tests/ecore/ecore_test_ecore_file.c \
204tests/ecore/ecore_test_promise.c \
202tests/ecore/ecore_suite.h 205tests/ecore/ecore_suite.h
203 206
204tests_ecore_ecore_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ 207tests_ecore_ecore_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
diff --git a/src/bin/eolian/eo_generator.c b/src/bin/eolian/eo_generator.c
index a97f2f0..4810658 100644
--- a/src/bin/eolian/eo_generator.c
+++ b/src/bin/eolian/eo_generator.c
@@ -311,6 +311,9 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid,
311 if (ftype != EOLIAN_PROP_GET && ftype != EOLIAN_PROP_SET) ftype = eolian_function_type_get(funcid); 311 if (ftype != EOLIAN_PROP_GET && ftype != EOLIAN_PROP_SET) ftype = eolian_function_type_get(funcid);
312 Eina_Bool is_prop = (ftype == EOLIAN_PROP_GET || ftype == EOLIAN_PROP_SET); 312 Eina_Bool is_prop = (ftype == EOLIAN_PROP_GET || ftype == EOLIAN_PROP_SET);
313 313
314 Eina_Bool has_promise = EINA_FALSE;
315 const char* promise_param_name = NULL;
316 const char* promise_value_type = NULL;
314 Eina_Bool need_implementation = EINA_TRUE; 317 Eina_Bool need_implementation = EINA_TRUE;
315 if (!impl_env && eolian_function_is_virtual_pure(funcid, ftype)) need_implementation = EINA_FALSE; 318 if (!impl_env && eolian_function_is_virtual_pure(funcid, ftype)) need_implementation = EINA_FALSE;
316 319
@@ -337,9 +340,11 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid,
337 if (eina_iterator_next(itr, &data) && !eina_iterator_next(itr, &data2)) 340 if (eina_iterator_next(itr, &data) && !eina_iterator_next(itr, &data2))
338 { 341 {
339 Eolian_Function_Parameter *param = data; 342 Eolian_Function_Parameter *param = data;
343 const char* rettype_str = NULL;
340 rettypet = eolian_parameter_type_get(param); 344 rettypet = eolian_parameter_type_get(param);
341 var_as_ret = EINA_TRUE; 345 var_as_ret = EINA_TRUE;
342 default_ret_val = eolian_parameter_default_value_get(param); 346 default_ret_val = eolian_parameter_default_value_get(param);
347 eina_stringshare_del(rettype_str);
343 } 348 }
344 eina_iterator_free(itr); 349 eina_iterator_free(itr);
345 } 350 }
@@ -375,9 +380,24 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid,
375 const char *ptype = eolian_type_c_type_get(ptypet); 380 const char *ptype = eolian_type_c_type_get(ptypet);
376 Eolian_Parameter_Dir pdir = eolian_parameter_direction_get(param); 381 Eolian_Parameter_Dir pdir = eolian_parameter_direction_get(param);
377 Eina_Bool had_star = !!strchr(ptype, '*'); 382 Eina_Bool had_star = !!strchr(ptype, '*');
383
384 if(!has_promise && !strcmp(ptype, "Ecore_Promise *"))
385 {
386 Eina_Iterator* promise_values;
387 has_promise = EINA_TRUE;
388 promise_param_name = eina_stringshare_add(pname);
389 promise_values = eolian_type_subtypes_get(eolian_type_base_type_get(ptypet));
390 Eolian_Type* subtype;
391 if(eina_iterator_next(promise_values, (void**)&subtype))
392 promise_value_type = eolian_type_c_type_get(subtype);
393 }
394
378 if (ftype == EOLIAN_UNRESOLVED || ftype == EOLIAN_METHOD) add_star = (pdir == EOLIAN_OUT_PARAM || pdir == EOLIAN_INOUT_PARAM); 395 if (ftype == EOLIAN_UNRESOLVED || ftype == EOLIAN_METHOD) add_star = (pdir == EOLIAN_OUT_PARAM || pdir == EOLIAN_INOUT_PARAM);
379 if (eina_strbuf_length_get(params)) eina_strbuf_append(params, ", "); 396 if (eina_strbuf_length_get(params)) eina_strbuf_append(params, ", ");
380 eina_strbuf_append_printf(params, "%s", pname); 397 if(has_promise)
398 eina_strbuf_append_printf(params, "%s", "&__eo_promise");
399 else
400 eina_strbuf_append_printf(params, "%s", pname);
381 eina_strbuf_append_printf(full_params, ", %s%s%s%s%s", 401 eina_strbuf_append_printf(full_params, ", %s%s%s%s%s",
382 ptype, had_star?"":" ", add_star?"*":"", pname, is_empty && !dflt_value ?" EINA_UNUSED":""); 402 ptype, had_star?"":" ", add_star?"*":"", pname, is_empty && !dflt_value ?" EINA_UNUSED":"");
383 if (is_auto) 403 if (is_auto)
@@ -511,8 +531,8 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid,
511 Eina_Bool ret_is_void = (!rettype || !strcmp(rettype, "void")); 531 Eina_Bool ret_is_void = (!rettype || !strcmp(rettype, "void"));
512 _class_func_env_create(class, eolian_function_name_get(funcid), ftype, &func_env); 532 _class_func_env_create(class, eolian_function_name_get(funcid), ftype, &func_env);
513 eina_strbuf_append_printf(eo_func_decl, 533 eina_strbuf_append_printf(eo_func_decl,
514 "EOAPI EO_%sFUNC_BODY%s%s(%s", 534 "EOAPI EO_%sFUNC_%sBODY%s%s(%s",
515 ret_is_void?"VOID_":"", has_params?"V":"", 535 ret_is_void?"VOID_":"", has_promise?"PROMISE_":"", has_params?"V":"",
516 (ftype == EOLIAN_PROP_GET || 536 (ftype == EOLIAN_PROP_GET ||
517 eolian_function_object_is_const(funcid) || 537 eolian_function_object_is_const(funcid) ||
518 eolian_function_is_class(funcid))?"_CONST":"", func_env.lower_eo_func); 538 eolian_function_is_class(funcid))?"_CONST":"", func_env.lower_eo_func);
@@ -535,6 +555,10 @@ eo_bind_func_generate(const Eolian_Class *class, const Eolian_Function *funcid,
535 eina_stringshare_del(string); 555 eina_stringshare_del(string);
536 } 556 }
537 } 557 }
558 if (has_promise)
559 {
560 eina_strbuf_append_printf(eo_func_decl, ", %s, %s", promise_param_name, promise_value_type);
561 }
538 if (has_params) 562 if (has_params)
539 { 563 {
540 eina_strbuf_replace_all(full_params, " EINA_UNUSED", ""); 564 eina_strbuf_replace_all(full_params, " EINA_UNUSED", "");
diff --git a/src/lib/ecore/Ecore.h b/src/lib/ecore/Ecore.h
index e843038..df28b64 100644
--- a/src/lib/ecore/Ecore.h
+++ b/src/lib/ecore/Ecore.h
@@ -356,6 +356,7 @@ extern "C" {
356#endif 356#endif
357#ifdef EFL_EO_API_SUPPORT 357#ifdef EFL_EO_API_SUPPORT
358#include "Ecore_Eo.h" 358#include "Ecore_Eo.h"
359#include "ecore_promise.h"
359#endif 360#endif
360 361
361#ifdef __cplusplus 362#ifdef __cplusplus
diff --git a/src/lib/ecore/ecore_promise.c b/src/lib/ecore/ecore_promise.c
new file mode 100644
index 0000000..c55d519
--- /dev/null
+++ b/src/lib/ecore/ecore_promise.c
@@ -0,0 +1,452 @@
1#ifdef HAVE_CONFIG_H
2#include <config.h>
3#endif
4
5#include <Eina.h>
6#include <Ecore.h>
7
8#include <assert.h>
9
10typedef void(*Ecore_Promise_Free_Cb)(void*);
11
12struct _Ecore_Promise_Then_Cb
13{
14 EINA_INLIST;
15
16 Ecore_Promise_Cb callback;
17 void* data;
18};
19
20struct _Ecore_Promise
21{
22 Eina_Lock lock;
23 Eina_Condition condition;
24 Eina_Bool has_finished : 1;
25 Eina_Bool has_errored : 1;
26 Eina_Bool has_pending_call : 1;
27 Eina_Bool is_then_calls_manual : 1;
28 Eina_Error error;
29 size_t value_size;
30 int ref;
31
32 struct _Ecore_Promise_Then_Cb then_callbacks;
33 Ecore_Promise_Free_Cb free_cb;
34
35 char value[];
36};
37
38struct _Ecore_Promise_Thread_Data
39{
40 const void* data;
41 Ecore_Promise_Thread_Cb func_blocking;
42 Ecore_Promise* promise;
43};
44
45typedef struct _Ecore_Promise_Iterator _Ecore_Promise_Iterator;
46typedef struct _Ecore_Promise_Success_Iterator _Ecore_Promise_Success_Iterator;
47typedef struct _Ecore_Promise_Failure_Iterator _Ecore_Promise_Failure_Iterator;
48struct _Ecore_Promise_Iterator
49{
50 Eina_Iterator* success_iterator;
51 Eina_Iterator* failure_iterator;
52 struct _Ecore_Promise_Success_Iterator
53 {
54 Eina_Iterator success_iterator_impl;
55 struct _Ecore_Promise_Failure_Iterator
56 {
57 Eina_Iterator failure_iterator_impl;
58 unsigned int promise_index;
59 unsigned int num_promises;
60 unsigned int promises_finished;
61 Ecore_Promise* promises[];
62 } data;
63 } data;
64};
65
66static void _ecore_promise_lock_take(Ecore_Promise* promise);
67static void _ecore_promise_lock_release(Ecore_Promise* promise);
68static void _ecore_promise_finish(Ecore_Promise* promise);
69static void _ecore_promise_then_calls(Ecore_Promise* promise);
70static void _ecore_promise_unsafe_ref(Ecore_Promise const* promise);
71static void _ecore_promise_unsafe_unref(Ecore_Promise const* promise);
72static void _ecore_promise_unsafe_free_unref(Ecore_Promise const* promise);
73static Eina_Bool _ecore_promise_unlock_unsafe_free_unref(Ecore_Promise const* promise);
74
75static void _ecore_promise_iterator_setup(_Ecore_Promise_Iterator* iterator, Eina_Array* promises);
76
77static void _ecore_promise_thread_end(void* data, Ecore_Thread* thread EINA_UNUSED)
78{
79 struct _Ecore_Promise_Thread_Data* p = data;
80 _ecore_promise_lock_take(p->promise);
81 if(p->promise->has_finished)
82 {
83 p->promise->has_pending_call = EINA_FALSE;
84 if(!_ecore_promise_unlock_unsafe_free_unref(p->promise))
85 _ecore_promise_then_calls(p->promise);
86 }
87 else
88 {
89 p->promise->is_then_calls_manual = EINA_FALSE;
90 p->promise->has_pending_call = EINA_FALSE;
91 _ecore_promise_unlock_unsafe_free_unref(p->promise);
92 }
93 free(data);
94}
95
96static void
97_ecore_promise_thread_blocking(void* data, Ecore_Thread* thread EINA_UNUSED)
98{
99 struct _Ecore_Promise_Thread_Data* p = data;
100 (p->func_blocking)(p->data, p->promise);
101}
102
103static void
104_ecore_promise_then_calls(Ecore_Promise* promise)
105{
106 _ecore_promise_lock_take(promise);
107 struct _Ecore_Promise_Then_Cb then_callbacks = promise->then_callbacks;
108 memset(&promise->then_callbacks, 0, sizeof(promise->then_callbacks));
109 promise->has_pending_call = EINA_FALSE;
110 _ecore_promise_lock_release(promise);
111
112 struct _Ecore_Promise_Then_Cb* callback;
113
114 if(then_callbacks.callback)
115 {
116 (*then_callbacks.callback)(then_callbacks.data, &promise->value[0]);
117 _ecore_promise_unsafe_free_unref(promise);
118 }
119
120 if(EINA_INLIST_GET(&then_callbacks)->next)
121 {
122 Eina_Inlist* list2;
123 EINA_INLIST_FOREACH_SAFE(EINA_INLIST_GET(&then_callbacks)->next, list2, callback)
124 {
125 if(callback->callback)
126 {
127 (*callback->callback)(callback->data, promise);
128 }
129 _ecore_promise_unsafe_free_unref(promise);
130 }
131 }
132}
133
134Ecore_Promise* ecore_promise_thread_run(Ecore_Promise_Thread_Cb func_blocking, const void* data, size_t value_size)
135{
136 struct _Ecore_Promise_Thread_Data *new_data = malloc(sizeof(struct _Ecore_Promise_Thread_Data));
137 new_data->data = data;
138 new_data->func_blocking = func_blocking;
139 new_data->promise = ecore_promise_add(value_size);
140 new_data->promise->is_then_calls_manual = EINA_TRUE;
141 new_data->promise->has_pending_call = EINA_TRUE;
142 ecore_promise_ref(new_data->promise);
143 ecore_thread_run(&_ecore_promise_thread_blocking, &_ecore_promise_thread_end, NULL, new_data);
144 return new_data->promise;
145}
146
147Ecore_Promise* ecore_promise_add(int value_size)
148{
149 Ecore_Promise* p = malloc(sizeof(Ecore_Promise) + value_size);
150 eina_lock_new(&p->lock);
151 eina_condition_new(&p->condition, &p->lock);
152 p->has_finished = p->has_errored = p->has_pending_call = p->is_then_calls_manual = EINA_FALSE;
153 p->ref = 1;
154 memset(&p->then_callbacks, 0, sizeof(p->then_callbacks));
155 p->value_size = value_size;
156 p->free_cb = NULL;
157 return p;
158}
159
160static void _ecore_promise_del(Ecore_Promise* promise)
161{
162 if(promise->free_cb)
163 promise->free_cb((void*)&promise->value[0]);
164
165 eina_lock_free(&promise->lock);
166 eina_condition_free(&promise->condition);
167}
168
169void* ecore_promise_buffer_get(Ecore_Promise* promise)
170{
171 return &promise->value[0];
172}
173
174void* ecore_promise_value_get(Ecore_Promise const* promise)
175{
176 _ecore_promise_lock_take((Ecore_Promise*)promise);
177 _ecore_promise_unsafe_ref(promise);
178 while(!promise->has_finished)
179 {
180 eina_condition_wait((Eina_Condition*)&promise->condition);
181 }
182
183 void* v = (void*)(promise->value_size && !promise->has_errored ? &promise->value[0] : NULL);
184 _ecore_promise_unsafe_unref(promise);
185 _ecore_promise_lock_release((Ecore_Promise*)promise);
186 return v;
187}
188
189void ecore_promise_value_set(Ecore_Promise* promise, void* data)
190{
191 _ecore_promise_lock_take(promise);
192 if(data && promise->value_size)
193 {
194 memcpy(&promise->value[0], data, promise->value_size);
195 }
196
197 _ecore_promise_finish(promise);
198}
199
200static void _ecore_promise_all_compose_then_cb(Ecore_Promise* promise, void* value EINA_UNUSED)
201{
202 _ecore_promise_lock_take(promise);
203 _Ecore_Promise_Iterator* iterator = (_Ecore_Promise_Iterator*)promise->value;
204
205 if(++iterator->data.data.promises_finished == iterator->data.data.num_promises)
206 {
207 _ecore_promise_finish(promise);
208 }
209 else
210 _ecore_promise_lock_release(promise);
211}
212
213static void _ecore_promise_all_free(_Ecore_Promise_Iterator* value)
214{
215 unsigned i = 0;
216 eina_iterator_free(value->success_iterator);
217 /* eina_iterator_free(value->failure_iterator); */
218
219 for(;i != value->data.data.num_promises; ++i)
220 {
221 ecore_promise_unref(value->data.data.promises[i]);
222 }
223}
224
225Ecore_Promise* ecore_promise_all(Eina_Iterator* it)
226{
227 Ecore_Promise* current, *promise;
228 Eina_Array* promises;
229
230 promises = eina_array_new(20);
231
232 EINA_ITERATOR_FOREACH(it, current)
233 {
234 eina_array_push(promises, current);
235 }
236
237 promise = ecore_promise_add(sizeof(_Ecore_Promise_Iterator) + sizeof(Ecore_Promise*)*eina_array_count_get(promises));
238 //promise->is_then_calls_manual = EINA_TRUE;
239 promise->free_cb = (Ecore_Promise_Free_Cb)_ecore_promise_all_free;
240 _Ecore_Promise_Iterator* internal_it = ecore_promise_buffer_get(promise);
241 _ecore_promise_iterator_setup(internal_it, promises);
242 eina_array_free(promises);
243
244 {
245 Ecore_Promise** cur_promise = internal_it->data.data.promises, ** last =
246 internal_it->data.data.promises + internal_it->data.data.num_promises;
247 for(;cur_promise != last; ++cur_promise)
248 {
249 ecore_promise_ref(*cur_promise);
250 ecore_promise_then(*cur_promise, (Ecore_Promise_Cb)&_ecore_promise_all_compose_then_cb, promise);
251 }
252 }
253
254 return promise;
255}
256
257void ecore_promise_then(Ecore_Promise* promise, Ecore_Promise_Cb callback, void* data)
258{
259 _ecore_promise_lock_take(promise);
260 _ecore_promise_unsafe_ref(promise);
261 if(!promise->then_callbacks.callback && !EINA_INLIST_GET(&promise->then_callbacks)->next)
262 {
263 promise->then_callbacks.callback = callback;
264 promise->then_callbacks.data = data;
265 }
266 else
267 {
268 struct _Ecore_Promise_Then_Cb* p = malloc(sizeof(struct _Ecore_Promise_Then_Cb));
269 p->callback = callback;
270 p->data = data;
271 Eina_Inlist* l = eina_inlist_append(EINA_INLIST_GET(&promise->then_callbacks), EINA_INLIST_GET(p));
272 (void)l;
273 }
274 if(promise->has_finished && !promise->has_pending_call)
275 {
276 promise->has_pending_call = EINA_TRUE;
277 _ecore_promise_lock_release(promise);
278 ecore_job_add((Ecore_Cb)&_ecore_promise_then_calls, promise);
279 }
280 else
281 _ecore_promise_lock_release(promise);
282}
283
284EAPI Eina_Error ecore_promise_error_get(Ecore_Promise const* promise)
285{
286 _ecore_promise_lock_take((Ecore_Promise*)promise);
287 if(promise->has_errored)
288 {
289 Eina_Error error = promise->error;
290 _ecore_promise_lock_release((Ecore_Promise*)promise);
291 return error;
292 }
293 else
294 {
295 _ecore_promise_lock_release((Ecore_Promise*)promise);
296 return 0;
297 }
298}
299
300EAPI void ecore_promise_error_set(Ecore_Promise* promise, Eina_Error error)
301{
302 _ecore_promise_lock_take(promise);
303 promise->error = error;
304 promise->has_errored = EINA_TRUE;
305
306 _ecore_promise_finish(promise);
307}
308
309static void
310_ecore_promise_finish(Ecore_Promise* promise)
311{
312 promise->has_finished = EINA_TRUE;
313 eina_condition_broadcast(&promise->condition);
314 _ecore_promise_unsafe_unref(promise);
315 if(!promise->is_then_calls_manual && !promise->has_pending_call)
316 {
317 promise->has_pending_call = EINA_TRUE;
318 _ecore_promise_lock_release(promise);
319 ecore_job_add((Ecore_Cb)&_ecore_promise_then_calls, promise);
320 }
321 else
322 _ecore_promise_lock_release(promise);
323}
324
325static Eina_Bool
326_ecore_promise_iterator_next(_Ecore_Promise_Success_Iterator *it, void **data)
327{
328 if(it->data.promise_index == it->data.num_promises)
329 return EINA_FALSE;
330
331 if(ecore_promise_error_get(it->data.promises[it->data.promise_index]))
332 {
333 return EINA_FALSE;
334 }
335 else
336 {
337 *data = ecore_promise_value_get(it->data.promises[it->data.promise_index++]);
338 return EINA_TRUE;
339 }
340}
341
342static void**
343_ecore_promise_iterator_get_container(_Ecore_Promise_Success_Iterator *it)
344{
345 return (void**)it->data.promises;
346}
347
348static void
349_ecore_promise_iterator_free(_Ecore_Promise_Success_Iterator *it EINA_UNUSED)
350{
351}
352
353static void _ecore_promise_iterator_setup(_Ecore_Promise_Iterator* it, Eina_Array* promises_array)
354{
355 Ecore_Promise** promises;
356
357 it->success_iterator = &it->data.success_iterator_impl;
358 it->failure_iterator = &it->data.data.failure_iterator_impl;
359 it->data.data.num_promises = eina_array_count_get(promises_array);
360 it->data.data.promise_index = 0;
361 promises = (Ecore_Promise**)promises_array->data;
362
363 memcpy(&it->data.data.promises[0], promises, it->data.data.num_promises*sizeof(Ecore_Promise*));
364
365 EINA_MAGIC_SET(&it->data.success_iterator_impl, EINA_MAGIC_ITERATOR);
366 EINA_MAGIC_SET(&it->data.data.failure_iterator_impl, EINA_MAGIC_ITERATOR);
367
368 it->data.success_iterator_impl.version = EINA_ITERATOR_VERSION;
369 it->data.success_iterator_impl.next = FUNC_ITERATOR_NEXT(_ecore_promise_iterator_next);
370 it->data.success_iterator_impl.get_container = FUNC_ITERATOR_GET_CONTAINER(
371 _ecore_promise_iterator_get_container);
372 it->data.success_iterator_impl.free = FUNC_ITERATOR_FREE(_ecore_promise_iterator_free);
373}
374
375EAPI int ecore_promise_value_size_get(Ecore_Promise const* promise)
376{
377 return promise->value_size;
378}
379
380static void _ecore_promise_lock_take(Ecore_Promise* promise)
381{
382 eina_lock_take(&promise->lock);
383}
384
385static void _ecore_promise_lock_release(Ecore_Promise* promise)
386{
387 eina_lock_release(&promise->lock);
388}
389
390static void _ecore_promise_unsafe_ref(Ecore_Promise const* promise)
391{
392 Ecore_Promise* p = (Ecore_Promise*)promise;
393 ++p->ref;
394}
395
396static void _ecore_promise_free_cb(Ecore_Promise* promise)
397{
398 _ecore_promise_lock_take(promise);
399 _ecore_promise_unlock_unsafe_free_unref(promise);
400}
401
402static void _ecore_promise_unsafe_unref(Ecore_Promise const* promise)
403{
404 Ecore_Promise* p = (Ecore_Promise*)promise;
405 if(p->ref == 1 && !p->has_pending_call)
406 {
407 ecore_job_add((Ecore_Cb)_ecore_promise_free_cb, p);
408 }
409 else
410 --p->ref;
411}
412
413static void _ecore_promise_unsafe_free_unref(Ecore_Promise const* promise)
414{
415 Ecore_Promise* p = (Ecore_Promise*)promise;
416 if(--p->ref == 0)
417 {
418 assert(!p->has_pending_call);
419 _ecore_promise_del(p);
420 }
421}
422
423static Eina_Bool _ecore_promise_unlock_unsafe_free_unref(Ecore_Promise const* promise)
424{
425 Ecore_Promise* p = (Ecore_Promise*)promise;
426 if(--p->ref == 0)
427 {
428 assert(!p->has_pending_call);
429 _ecore_promise_lock_release((Ecore_Promise*)promise);
430 _ecore_promise_del(p);
431 return EINA_TRUE;
432 }
433 else
434 {
435 _ecore_promise_lock_release((Ecore_Promise*)promise);
436 return EINA_FALSE;
437 }
438}
439
440EAPI void ecore_promise_ref(Ecore_Promise* promise)
441{
442 _ecore_promise_lock_take(promise);
443 _ecore_promise_unsafe_ref(promise);
444 _ecore_promise_lock_release(promise);
445}
446
447EAPI void ecore_promise_unref(Ecore_Promise* promise)
448{
449 _ecore_promise_lock_take(promise);
450 _ecore_promise_unsafe_unref(promise);
451 _ecore_promise_lock_release(promise);
452}
diff --git a/src/lib/ecore/ecore_promise.h b/src/lib/ecore/ecore_promise.h
new file mode 100644
index 0000000..834c336
--- /dev/null
+++ b/src/lib/ecore/ecore_promise.h
@@ -0,0 +1,136 @@
1
2#ifdef EFL_BETA_API_SUPPORT
3
4struct _Ecore_Promise;
5
6/*
7 * @def _Ecore_Promise
8 */
9typedef struct _Ecore_Promise Ecore_Promise;
10
11/*
12 * @brief Function callback type for when using ecore_promise_then
13 */
14typedef void(*Ecore_Promise_Cb)(void* data, void* value);
15
16/*
17 * @brief Function callback type for when creating Ecore_Thread that
18 * uses Ecore_Promise for communication
19 */
20typedef void(*Ecore_Promise_Thread_Cb)(const void* data, Ecore_Promise* promise);
21
22/*
23 * @brief Function that instantiates a Ecore_Promise and automatically
24 * executes func_blocking callback function in another thread
25 */
26EAPI Ecore_Promise* ecore_promise_thread_run(Ecore_Promise_Thread_Cb func_blocking, const void* data, size_t value_size);
27
28/*
29 * @brief Creates a Ecore_Promise with a value of size value_size.
30 *
31 * @param value_size Size of value-type that Ecore_Promise will hold
32 */
33EAPI Ecore_Promise* ecore_promise_add(int value_size);
34
35/*
36 * @brief Appends a callback to be called when the Ecore_Promise is
37 * finished.
38 *
39 * @param promise The Ecore_Promise to wait for
40 * @param callback Callback to be called when Ecore_Promise is finished
41 * @param data Private data passed to the callback
42 */
43EAPI void ecore_promise_then(Ecore_Promise* promise, Ecore_Promise_Cb callback, void* data);
44
45/*
46 * @brief Creates a new Ecore_Promise from other Ecore_Promises
47 *
48 * @param promises An Eina_Iterator for all Ecore_Promises
49 */
50EAPI Ecore_Promise* ecore_promise_all(Eina_Iterator* promises);
51
52/*
53 * @brief Sets value for Ecore_Promise. This finishes the callback and
54 * calls all ecore_promise_then callbacks that have been registered on
55 * this Ecore_Promise. This function must be called only once per
56 * Ecore_Promise
57 *
58 * @param promise The promise for which to set the value
59 * @param value The pointer to the value that is going to be copied, or NULL.
60 */
61EAPI void ecore_promise_value_set(Ecore_Promise* promise, void* value);
62
63/*
64 * @brief Returns the pointer to the value if the Ecore_Promise is
65 * finished. Waits for it to be finished, otherwise.
66 *
67 * @param promise The promise for which to get the value
68 */
69EAPI void* ecore_promise_value_get(Ecore_Promise const* promise);
70
71/*
72 * @brief Returns the pointer to the buffer that holds the value. This
73 * function is useful to instantiate the value directly in the correct
74 * buffer, without needing to copy. The ecore_promise_value_set must
75 * still be called, possibly with NULL, to finish the Ecore_Promise
76 * and call the callbacks registered in it.
77 *
78 * @param promise The promise for which to get the buffer pointer
79 */
80EAPI void* ecore_promise_buffer_get(Ecore_Promise* promise);
81
82/*
83 * @brief Sets an error to the Ecore_Promise, thus finishing the
84 * promise and calling all ecore_promise_then callbacks registered.
85 *
86 * @param promise The promise for which to set the error
87 * @param error Eina_Error to be set
88 */
89EAPI void ecore_promise_error_set(Ecore_Promise* promise, Eina_Error error);
90
91/*
92 * @brief Gets an error to the Ecore_Promise if the promise is
93 * finished and has error'ed out. If it hasn't finished, it will wait,
94 * and if it has finished but otherwise not error'ed, returns 0.
95 *
96 * @param promise The promise for which to get the error
97 */
98EAPI Eina_Error ecore_promise_error_get(Ecore_Promise const* promise);
99
100/*
101 * @brief Gets the size of the value in ecore_promise_value_get.
102 *
103 * @param promise The promise for which to get the value size
104 */
105EAPI int ecore_promise_value_size_get(Ecore_Promise const* promise);
106
107/*
108 * @brief Returns @EINA_TRUE if the promise is ready and won't block
109 * on ecore_promise_value_get and @EINA_FALSE otherwise.
110 *
111 * @param promise The promise for which to get the ready status
112 */
113EAPI Eina_Bool ecore_promise_ready_is(Ecore_Promise const* promise);
114
115/*
116 * @brief Increments the reference count for the Ecore_Promise
117 *
118 * @param promise The promise for which to increment its reference
119 */
120EAPI void ecore_promise_ref(Ecore_Promise* promise);
121
122/*
123 * @brief Decrement the reference count for the Ecore_Promise and
124 * possibly schedule its destruction. The Ecore_Promise, if its
125 * reference count drops to zero, will only be free'd when all the
126 * current mainloop events have been processed. This allows the user
127 * to call ecore_promise_then before that happens so it can increment
128 * the reference back to 1 and wait for a value set or error set on
129 * the Ecore_Promise.
130 *
131 * @param promise The promise for which to decrement its reference
132 */
133EAPI void ecore_promise_unref(Ecore_Promise* promise);
134
135#endif
136
diff --git a/src/lib/eo/Eo.h b/src/lib/eo/Eo.h
index ab920ee..936c8c8 100644
--- a/src/lib/eo/Eo.h
+++ b/src/lib/eo/Eo.h
@@ -511,61 +511,96 @@ typedef struct _Eo_Call_Cache
511 __FILE__, __LINE__)) return DefRet; \ 511 __FILE__, __LINE__)) return DefRet; \
512 _Eo_##Name##_func _func_ = (_Eo_##Name##_func) ___call.func; \ 512 _Eo_##Name##_func _func_ = (_Eo_##Name##_func) ___call.func; \
513 513
514#define _EO_FUNC_PROMISE_CREATE0
515#define _EO_FUNC_PROMISE_FREE0
516#define _EO_FUNC_PROMISE_CREATE1 \
517 Ecore_Promise*(*ecore_promise_add)(int size) = dlsym(dlopen(NULL, RTLD_NOW), "ecore_promise_add"); \
518 Ecore_Promise* __eo_promise = ecore_promise_add(sizeof(PromiseValue));
519#define _EO_FUNC_PROMISE_FREE1 \
520 if(Promise) \
521 *Promise = __eo_promise; \
522 else \
523 { \
524 void(*ecore_promise_unref)(Ecore_Promise* p) = dlsym(dlopen(NULL, RTLD_NOW), "ecore_promise_unref"); \
525 ecore_promise_unref(__eo_promise); \
526 }
527#define _EO_EXPANSION_AUX(X) X
528#define _EO_FUNC_PROMISE_CREATE(p) _EO_EXPANSION_AUX(_EO_FUNC_PROMISE_CREATE ## p)
529#define _EO_FUNC_PROMISE_FREE(p) _EO_EXPANSION_AUX(_EO_FUNC_PROMISE_FREE ## p)
530
514// to define an EAPI function 531// to define an EAPI function
515#define _EO_FUNC_BODY(Name, ObjType, Ret, DefRet) \ 532#define _EO_FUNC_BODY(Name, ObjType, Promise, Ret, DefRet) \
516 Ret \ 533 Ret \
517 Name(ObjType obj) \ 534 Name(ObjType obj) \
518 { \ 535 { \
519 typedef Ret (*_Eo_##Name##_func)(Eo *, void *obj_data); \ 536 typedef Ret (*_Eo_##Name##_func)(Eo *, void *obj_data); \
520 Ret _r; \ 537 Ret _r; \
521 EO_FUNC_COMMON_OP(obj, Name, DefRet); \ 538 EO_FUNC_COMMON_OP(obj, Name, DefRet); \
539 _EO_FUNC_PROMISE_CREATE(Promise) \
522 _r = _func_(___call.eo_id, ___call.data); \ 540 _r = _func_(___call.eo_id, ___call.data); \
523 _eo_call_end(&___call); \ 541 _eo_call_end(&___call); \
542 _EO_FUNC_PROMISE_FREE(Promise) \
524 return _r; \ 543 return _r; \
525 } 544 }
526 545
527#define _EO_VOID_FUNC_BODY(Name, ObjType) \ 546#define _EO_VOID_FUNC_BODY(Name, ObjType, Promise) \
528 void \ 547 void \
529 Name(ObjType obj) \ 548 Name(ObjType obj) \
530 { \ 549 { \
531 typedef void (*_Eo_##Name##_func)(Eo *, void *obj_data); \ 550 typedef void (*_Eo_##Name##_func)(Eo *, void *obj_data); \
532 EO_FUNC_COMMON_OP(obj, Name, ); \ 551 EO_FUNC_COMMON_OP(obj, Name, ); \
552 _EO_FUNC_PROMISE_CREATE(Promise) \
533 _func_(___call.eo_id, ___call.data); \ 553 _func_(___call.eo_id, ___call.data); \
534 _eo_call_end(&___call); \ 554 _eo_call_end(&___call); \
555 _EO_FUNC_PROMISE_FREE(Promise) \
535 } 556 }
536 557
537#define _EO_FUNC_BODYV(Name, ObjType, Ret, DefRet, Arguments, ...) \ 558#define _EO_FUNC_BODYV(Name, ObjType, Promise, Ret, DefRet, Arguments, ...) \
538 Ret \ 559 Ret \
539 Name(ObjType obj, __VA_ARGS__) \ 560 Name(ObjType obj, __VA_ARGS__) \
540 { \ 561 { \
541 typedef Ret (*_Eo_##Name##_func)(Eo *, void *obj_data, __VA_ARGS__); \ 562 typedef Ret (*_Eo_##Name##_func)(Eo *, void *obj_data, __VA_ARGS__); \
542 Ret _r; \ 563 Ret _r; \
543 EO_FUNC_COMMON_OP(obj, Name, DefRet); \ 564 EO_FUNC_COMMON_OP(obj, Name, DefRet); \
565 _EO_FUNC_PROMISE_CREATE(Promise) \
544 _r = _func_(___call.eo_id, ___call.data, Arguments); \ 566 _r = _func_(___call.eo_id, ___call.data, Arguments); \
545 _eo_call_end(&___call); \ 567 _eo_call_end(&___call); \
568 _EO_FUNC_PROMISE_FREE(Promise) \
546 return _r; \ 569 return _r; \
547 } 570 }
548 571
549#define _EO_VOID_FUNC_BODYV(Name, ObjType, Arguments, ...) \ 572#define _EO_VOID_FUNC_BODYV(Name, ObjType, Promise, Arguments, ...) \
550 void \ 573 void \
551 Name(ObjType obj, __VA_ARGS__) \ 574 Name(ObjType obj, __VA_ARGS__) \
552 { \ 575 { \
553 typedef void (*_Eo_##Name##_func)(Eo *, void *obj_data, __VA_ARGS__); \ 576 typedef void (*_Eo_##Name##_func)(Eo *, void *obj_data, __VA_ARGS__); \
554 EO_FUNC_COMMON_OP(obj, Name, ); \ 577 EO_FUNC_COMMON_OP(obj, Name, ); \
578 _EO_FUNC_PROMISE_CREATE(Promise) \
555 _func_(___call.eo_id, ___call.data, Arguments); \ 579 _func_(___call.eo_id, ___call.data, Arguments); \
556 _eo_call_end(&___call); \ 580 _eo_call_end(&___call); \
581 _EO_FUNC_PROMISE_FREE(Promise) \
557 } 582 }
558 583
559#define EO_FUNC_BODY(Name, Ret, DefRet) _EO_FUNC_BODY(Name, Eo *, Ret, DefRet) 584#define EO_FUNC_BODY(Name, Ret, DefRet) _EO_FUNC_BODY(Name, Eo *, 0, Ret, DefRet)
560#define EO_VOID_FUNC_BODY(Name) _EO_VOID_FUNC_BODY(Name, Eo *) 585#define EO_VOID_FUNC_BODY(Name) _EO_VOID_FUNC_BODY(Name, Eo *, 0)
561#define EO_FUNC_BODYV(Name, Ret, DefRet, Arguments, ...) _EO_FUNC_BODYV(Name, Eo *, Ret, DefRet, EO_FUNC_CALL(Arguments), __VA_ARGS__) 586#define EO_FUNC_BODYV(Name, Ret, DefRet, Arguments, ...) _EO_FUNC_BODYV(Name, Eo *, 0, Ret, DefRet, EO_FUNC_CALL(Arguments), __VA_ARGS__)
562#define EO_VOID_FUNC_BODYV(Name, Arguments, ...) _EO_VOID_FUNC_BODYV(Name, Eo *, EO_FUNC_CALL(Arguments), __VA_ARGS__) 587#define EO_VOID_FUNC_BODYV(Name, Arguments, ...) _EO_VOID_FUNC_BODYV(Name, Eo *, 0, EO_FUNC_CALL(Arguments), __VA_ARGS__)
563 588
564#define EO_FUNC_BODY_CONST(Name, Ret, DefRet) _EO_FUNC_BODY(Name, const Eo *, Ret, DefRet) 589#define EO_FUNC_BODY_CONST(Name, Ret, DefRet) _EO_FUNC_BODY(Name, const Eo *, 0, Ret, DefRet)
565#define EO_VOID_FUNC_BODY_CONST(Name) _EO_VOID_FUNC_BODY(Name, const Eo *) 590#define EO_VOID_FUNC_BODY_CONST(Name) _EO_VOID_FUNC_BODY(Name, const Eo *, 0)
566#define EO_FUNC_BODYV_CONST(Name, Ret, DefRet, Arguments, ...) _EO_FUNC_BODYV(Name, const Eo *, Ret, DefRet, EO_FUNC_CALL(Arguments), __VA_ARGS__) 591#define EO_FUNC_BODYV_CONST(Name, Ret, DefRet, Arguments, ...) _EO_FUNC_BODYV(Name, const Eo *, 0, Ret, DefRet, EO_FUNC_CALL(Arguments), __VA_ARGS__)
567#define EO_VOID_FUNC_BODYV_CONST(Name, Arguments, ...) _EO_VOID_FUNC_BODYV(Name, const Eo *, EO_FUNC_CALL(Arguments), __VA_ARGS__) 592#define EO_VOID_FUNC_BODYV_CONST(Name, Arguments, ...) _EO_VOID_FUNC_BODYV(Name, const Eo *, 0, EO_FUNC_CALL(Arguments), __VA_ARGS__)
568 593
594#define EO_FUNC_PROMISE_BODY(Name, Ret, DefRet) _EO_FUNC_BODY(Name, Eo *, 1, Ret, DefRet)
595#define EO_VOID_FUNC_PROMISE_BODY(Name) _EO_VOID_FUNC_BODY(Name, Eo *, 1)
596#define EO_FUNC_PROMISE_BODYV(Name, Ret, DefRet, Arguments, ...) _EO_FUNC_BODYV(Name, Eo *, 1, Ret, DefRet, EO_FUNC_CALL(Arguments), __VA_ARGS__)
597#define EO_VOID_FUNC_PROMISE_BODYV(Name, Arguments, ...) _EO_VOID_FUNC_BODYV(Name, Eo *, 1, EO_FUNC_CALL(Arguments), __VA_ARGS__)
598
599#define EO_FUNC_PROMISE_BODY_CONST(Name, Ret, DefRet) _EO_FUNC_BODY(Name, const Eo *, 1, Ret, DefRet)
600#define EO_VOID_FUNC_PROMISE_BODY_CONST(Name) _EO_VOID_FUNC_BODY(Name, const Eo *, 1)
601#define EO_FUNC_PROMISE_BODYV_CONST(Name, Ret, DefRet, Arguments, ...) _EO_FUNC_BODYV(Name, const Eo *, 1, Ret, DefRet, EO_FUNC_CALL(Arguments), __VA_ARGS__)
602#define EO_VOID_FUNC_PROMISE_BODYV_CONST(Name, Arguments, ...) _EO_VOID_FUNC_BODYV(Name, const Eo *, 1, EO_FUNC_CALL(Arguments), __VA_ARGS__)
603
569#ifndef _WIN32 604#ifndef _WIN32
570# define _EO_OP_API_ENTRY(a) (void*)a 605# define _EO_OP_API_ENTRY(a) (void*)a
571#else 606#else
diff --git a/src/lib/eolian/eo_lexer.c b/src/lib/eolian/eo_lexer.c
index 0e98313..1aeb6a9 100644
--- a/src/lib/eolian/eo_lexer.c
+++ b/src/lib/eolian/eo_lexer.c
@@ -75,7 +75,8 @@ static const char * const ctypes[] =
75 "Eina_Accessor", "Eina_Array", "Eina_Iterator", "Eina_Hash", "Eina_List", 75 "Eina_Accessor", "Eina_Array", "Eina_Iterator", "Eina_Hash", "Eina_List",
76 "Eina_Value", 76 "Eina_Value",
77 77
78 "Eo_Event_Cb" 78 "Eo_Event_Cb",
79 "Ecore_Promise"
79}; 80};
80 81
81#undef KW 82#undef KW
diff --git a/src/lib/eolian/eo_lexer.h b/src/lib/eolian/eo_lexer.h
index b28a3fc..bb4385b 100644
--- a/src/lib/eolian/eo_lexer.h
+++ b/src/lib/eolian/eo_lexer.h
@@ -52,7 +52,9 @@ enum Tokens
52 \ 52 \
53 KW(accessor), KW(array), KW(iterator), KW(hash), KW(list), KW(generic_value), \ 53 KW(accessor), KW(array), KW(iterator), KW(hash), KW(list), KW(generic_value), \
54 \ 54 \
55 KW(__builtin_event_cb), KW(__undefined_type), \ 55 KW(__builtin_event_cb), \
56 KW(Promise), \
57 KW(__undefined_type), \
56 \ 58 \
57 KW(true), KW(false), KW(null) 59 KW(true), KW(false), KW(null)
58 60
@@ -206,4 +208,4 @@ void eo_lexer_context_pop (Eo_Lexer *ls);
206void eo_lexer_context_restore(Eo_Lexer *ls); 208void eo_lexer_context_restore(Eo_Lexer *ls);
207void eo_lexer_context_clear (Eo_Lexer *ls); 209void eo_lexer_context_clear (Eo_Lexer *ls);
208 210
209#endif /* __EO_LEXER_H__ */ \ No newline at end of file 211#endif /* __EO_LEXER_H__ */
diff --git a/src/lib/eolian/eo_parser.c b/src/lib/eolian/eo_parser.c
index 6b6df14..a0d9ddd 100644
--- a/src/lib/eolian/eo_parser.c
+++ b/src/lib/eolian/eo_parser.c
@@ -782,7 +782,7 @@ parse_type_void_base(Eo_Lexer *ls, Eina_Bool noptr)
782 _fill_name(eina_stringshare_ref(ls->t.value.s), &def->full_name, 782 _fill_name(eina_stringshare_ref(ls->t.value.s), &def->full_name,
783 &def->name, &def->namespaces); 783 &def->name, &def->namespaces);
784 eo_lexer_get(ls); 784 eo_lexer_get(ls);
785 if (tpid >= KW_accessor && tpid <= KW_list) 785 if ((tpid >= KW_accessor && tpid <= KW_list) || tpid == KW_Promise)
786 { 786 {
787 int bline = ls->line_number, bcol = ls->column; 787 int bline = ls->line_number, bcol = ls->column;
788 def->type = EOLIAN_TYPE_COMPLEX; 788 def->type = EOLIAN_TYPE_COMPLEX;
diff --git a/src/tests/ecore/ecore_suite.c b/src/tests/ecore/ecore_suite.c
index 787a455..04ad191 100644
--- a/src/tests/ecore/ecore_suite.c
+++ b/src/tests/ecore/ecore_suite.c
@@ -26,6 +26,7 @@ static const Efl_Test_Case etc[] = {
26#endif 26#endif
27 { "Ecore_Input", ecore_test_ecore_input }, 27 { "Ecore_Input", ecore_test_ecore_input },
28 { "Ecore_File", ecore_test_ecore_file }, 28 { "Ecore_File", ecore_test_ecore_file },
29 { "Ecore_Promise", ecore_test_ecore_promise },
29 { NULL, NULL } 30 { NULL, NULL }
30}; 31};
31 32
diff --git a/src/tests/ecore/ecore_suite.h b/src/tests/ecore/ecore_suite.h
index f0e4c2a..558e610 100644
--- a/src/tests/ecore/ecore_suite.h
+++ b/src/tests/ecore/ecore_suite.h
@@ -15,5 +15,6 @@ void ecore_test_ecore_drm(TCase *tc);
15void ecore_test_ecore_fb(TCase *tc); 15void ecore_test_ecore_fb(TCase *tc);
16void ecore_test_ecore_input(TCase *tc); 16void ecore_test_ecore_input(TCase *tc);
17void ecore_test_ecore_file(TCase *tc); 17void ecore_test_ecore_file(TCase *tc);
18void ecore_test_ecore_promise(TCase *tc);
18 19
19#endif /* _ECORE_SUITE_H */ 20#endif /* _ECORE_SUITE_H */
diff --git a/src/tests/ecore/ecore_test_promise.c b/src/tests/ecore/ecore_test_promise.c
new file mode 100644
index 0000000..0f003fd
--- /dev/null
+++ b/src/tests/ecore/ecore_test_promise.c
@@ -0,0 +1,364 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <Ecore.h>
6#include "ecore_suite.h"
7#include <time.h>
8
9void promised_thread(const void* data EINA_UNUSED, Ecore_Promise* promise)
10{
11 fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush(stderr);
12 ecore_promise_value_set(promise, NULL);
13}
14
15void promise_callback(void* data EINA_UNUSED, void* value EINA_UNUSED)
16{
17 fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush(stderr);
18 ecore_main_loop_quit();
19}
20
21START_TEST(ecore_test_promise)
22{
23 ecore_init();
24 fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, __func__); fflush(stderr);
25
26 fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush(stderr);
27 Ecore_Promise* promise = ecore_promise_thread_run(&promised_thread, NULL, 0);
28 ecore_promise_then(promise, &promise_callback, NULL);
29 fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush(stderr);
30
31 ecore_main_loop_begin();
32
33 fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, __func__); fflush(stderr);
34 ecore_shutdown();
35}
36END_TEST
37
38void promise_error_thread(const void* data EINA_UNUSED, Ecore_Promise* promise)
39{
40 fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush(stderr);
41 ecore_promise_error_set(promise, EINA_ERROR_OUT_OF_MEMORY);
42}
43
44void promise_error_callback(void* data EINA_UNUSED, void* value EINA_UNUSED)
45{
46 fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush(stderr);
47 ecore_main_loop_quit();
48}
49
50START_TEST(ecore_test_promise_error)
51{
52 ecore_init();
53 fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, __func__); fflush(stderr);
54
55 fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush(stderr);
56 Ecore_Promise* promise = ecore_promise_thread_run(&promise_error_thread, NULL, 0);
57 ecore_promise_then(promise, &promise_error_callback, NULL);
58 fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush(stderr);
59
60 ecore_main_loop_begin();
61
62 fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, __func__); fflush(stderr);
63 ecore_shutdown();
64}
65END_TEST
66
67START_TEST(ecore_test_promise_all)
68{
69 ecore_init();
70 fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, __func__); fflush(stderr);
71
72 fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush(stderr);
73 Ecore_Promise* first[2] = { ecore_promise_thread_run(&promised_thread, NULL, 0), NULL };
74 Ecore_Promise* promise = ecore_promise_all(eina_carray_iterator_new((void**)&first[0]));
75 ecore_promise_then(promise, &promise_callback, NULL);
76 fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush(stderr);
77
78 ecore_main_loop_begin();
79
80 fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, __func__); fflush(stderr);
81 ecore_shutdown();
82}
83END_TEST
84
85void promise_callback2(void* data, void* value EINA_UNUSED)
86{
87 fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush(stderr);
88 if(++(*(int*)data) == 2)
89 ecore_main_loop_quit();
90}
91
92START_TEST(ecore_test_promise_all_then_then)
93{
94 ecore_init();
95 fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, __func__); fflush(stderr);
96
97 int i = 0;
98
99 fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush(stderr);
100 Ecore_Promise* first[2] = { ecore_promise_thread_run(&promised_thread, NULL, 0), NULL };
101 ecore_promise_then(first[0], &promise_callback2, &i);
102 Ecore_Promise* promise = ecore_promise_all(eina_carray_iterator_new((void**)&first[0]));
103 ecore_promise_then(promise, &promise_callback2, &i);
104 fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush(stderr);
105
106 ecore_main_loop_begin();
107
108 fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, __func__); fflush(stderr);
109 ecore_shutdown();
110}
111END_TEST
112
113struct sync_data
114{
115 Eina_Lock lock;
116 Eina_Condition cond;
117 Eina_Bool var;
118};
119
120void promised_exit_thread(struct sync_data* data EINA_UNUSED, Ecore_Promise* promise)
121{
122 fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__); fflush(stderr);
123 ecore_promise_value_set(promise, NULL);
124 eina_lock_take(&data->lock);
125 data->var = EINA_TRUE;
126 eina_condition_broadcast(&data->cond);
127 eina_lock_release(&data->lock);
128}
129
130static void _ecore_test_promise_then_after_thread_finished_main_cb()
131{
132 struct sync_data data;
133 data.var = EINA_FALSE;
134 eina_lock_new(&data.lock);
135 eina_condition_new(&data.cond, &data.lock);
136
137 Ecore_Promise* promise = ecore_promise_thread_run((Ecore_Promise_Thread_Cb)&promised_exit_thread, &data, 0);
138
139 eina_lock_take(&data.lock);
140 while(!data.var)
141 {
142 eina_condition_wait(&data.cond);
143 }
144 eina_lock_release(&data.lock);
145 ecore_promise_then(promise, &promise_callback, NULL);
146}
147
148START_TEST(ecore_test_promise_then_after_thread_finished)
149{
150 ecore_init();
151 fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, __func__); fflush(stderr);
152
153 ecore_job_add(&_ecore_test_promise_then_after_thread_finished_main_cb, NULL);
154 ecore_main_loop_begin();
155
156 fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, __func__); fflush(stderr);
157 ecore_shutdown();
158}
159END_TEST
160
161static void _ecore_test_promise_then_after_thread_finished_all_main_cb()
162{
163 struct sync_data data;
164 data.var = EINA_FALSE;
165 eina_lock_new(&data.lock);
166 eina_condition_new(&data.cond, &data.lock);
167
168 Ecore_Promise* first[] = {ecore_promise_thread_run((Ecore_Promise_Thread_Cb)&promised_exit_thread, &data, 0), NULL};
169 Ecore_Promise* promise = ecore_promise_all(eina_carray_iterator_new((void**)&first[0]));
170
171 eina_lock_take(&data.lock);
172 while(!data.var)
173 {
174 eina_condition_wait(&data.cond);
175 }
176 eina_lock_release(&data.lock);
177 ecore_promise_then(promise, &promise_callback, NULL);
178}
179
180START_TEST(ecore_test_promise_then_after_thread_finished_all)
181{
182 ecore_init();
183 fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, __func__); fflush(stderr);
184
185 ecore_job_add(&_ecore_test_promise_then_after_thread_finished_all_main_cb, NULL);
186 ecore_main_loop_begin();
187
188 fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, __func__); fflush(stderr);
189 ecore_shutdown();
190}
191END_TEST
192
193void promised_block_thread(const void* data EINA_UNUSED, Ecore_Promise* promise)
194{
195 struct timespec v = {.tv_sec = 1, .tv_nsec = 0}, rem;
196 if(nanosleep(&v, &rem) == -1 && errno == EINTR)
197 do
198 {
199 v = rem;
200 }
201 while(nanosleep(&v, &rem) == -1 && errno == EINTR);
202
203 int r = 10;
204 ecore_promise_value_set(promise, &r);
205}
206
207static void
208_ecore_test_promise_blocking_get_quit_cb(void* data EINA_UNUSED)
209{
210 ecore_main_loop_quit();
211}
212
213static void
214_ecore_test_promise_blocking_get_main_cb(void* data EINA_UNUSED)
215{
216 Ecore_Promise* promise = ecore_promise_thread_run(&promised_block_thread, NULL, sizeof(int));
217 const void* value = ecore_promise_value_get(promise);
218 ck_assert(*(int*)value == 10);
219
220 ecore_job_add(&_ecore_test_promise_blocking_get_quit_cb, NULL);
221}
222
223START_TEST(ecore_test_promise_blocking_get)
224{
225 ecore_init();
226 fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, __func__); fflush(stderr);
227
228 ecore_job_add(&_ecore_test_promise_blocking_get_main_cb, NULL);
229 ecore_main_loop_begin();
230
231 fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, __func__); fflush(stderr);
232 ecore_shutdown();
233}
234END_TEST
235
236static void
237_ecore_test_promise_blocking_get_all_value_get_cb(Ecore_Promise* promise, Ecore_Thread* thread EINA_UNUSED)
238{
239 Eina_Iterator** iterator = ecore_promise_value_get(promise);
240 int* v;
241 ck_assert(eina_iterator_next(*iterator, (void**)&v));
242 ck_assert(*v == 10);
243 ecore_main_loop_quit();
244}
245
246static void
247_ecore_test_promise_blocking_get_all_main_cb(void* data EINA_UNUSED)
248{
249 Ecore_Promise* first[2] = {ecore_promise_thread_run(&promised_block_thread, NULL, sizeof(int)), NULL};
250 Ecore_Promise* promise = ecore_promise_all(eina_carray_iterator_new((void**)&first[0]));
251
252 ecore_thread_run((Ecore_Thread_Cb)&_ecore_test_promise_blocking_get_all_value_get_cb, NULL, NULL, promise);
253}
254
255START_TEST(ecore_test_promise_blocking_get_all)
256{
257 ecore_init();
258 fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, __func__); fflush(stderr);
259
260 ecore_job_add(&_ecore_test_promise_blocking_get_all_main_cb, NULL);
261 ecore_main_loop_begin();
262
263 fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, __func__); fflush(stderr);
264 ecore_shutdown();
265}
266END_TEST
267
268static void
269_ecore_test_promise_normal_lifetime_cb(void* data EINA_UNUSED, void* value EINA_UNUSED)
270{
271 ecore_main_loop_quit();
272}
273
274START_TEST(ecore_test_promise_normal_lifetime)
275{
276 ecore_init();
277 fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, __func__); fflush(stderr);
278
279 Ecore_Promise* promise = ecore_promise_add(0);
280
281 ecore_promise_then(promise, &_ecore_test_promise_normal_lifetime_cb, NULL);
282 ecore_promise_value_set(promise, NULL);
283
284 ecore_main_loop_begin();
285
286 fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, __func__); fflush(stderr);
287 ecore_shutdown();
288}
289END_TEST
290
291START_TEST(ecore_test_promise_normal_lifetime_all)
292{
293 ecore_init();
294 fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, __func__); fflush(stderr);
295
296 Ecore_Promise* first[2] = {ecore_promise_add(0), NULL};
297 Ecore_Promise* promise = ecore_promise_all(eina_carray_iterator_new((void**)&first[0]));
298
299 ecore_promise_then(promise, &_ecore_test_promise_normal_lifetime_cb, NULL);
300 ecore_promise_value_set(promise, NULL);
301
302 ecore_main_loop_begin();
303
304 fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, __func__); fflush(stderr);
305 ecore_shutdown();
306}
307END_TEST
308
309static void
310_ecore_test_promise_immediate_set_lifetime_cb(void* data EINA_UNUSED, void* value EINA_UNUSED)
311{
312 ecore_main_loop_quit();
313}
314
315START_TEST(ecore_test_promise_immediate_set_lifetime)
316{
317 ecore_init();
318 fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, __func__); fflush(stderr);
319
320 Ecore_Promise* promise = ecore_promise_add(0);
321
322 ecore_promise_value_set(promise, NULL);
323 ecore_promise_then(promise, &_ecore_test_promise_immediate_set_lifetime_cb, NULL);
324
325 ecore_main_loop_begin();
326
327 fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, __func__); fflush(stderr);
328 ecore_shutdown();
329}
330END_TEST
331
332START_TEST(ecore_test_promise_immediate_set_lifetime_all)
333{
334 ecore_init();
335 fprintf(stderr, "%s:%d %s ---------- BEGIN test\n", __FILE__, __LINE__, __func__); fflush(stderr);
336
337 Ecore_Promise* first[2] = {ecore_promise_add(0), NULL};
338 Ecore_Promise* promise = ecore_promise_all(eina_carray_iterator_new((void**)&first[0]));
339
340 ecore_promise_value_set(first[0], NULL);
341 ecore_promise_then(promise, &_ecore_test_promise_immediate_set_lifetime_cb, NULL);
342
343 ecore_main_loop_begin();
344
345 fprintf(stderr, "%s:%d %s ---------- END test\n", __FILE__, __LINE__, __func__); fflush(stderr);
346 ecore_shutdown();
347}
348END_TEST
349
350void ecore_test_ecore_promise(TCase *tc EINA_UNUSED)
351{
352 tcase_add_test(tc, ecore_test_promise);
353 tcase_add_test(tc, ecore_test_promise_error);
354 tcase_add_test(tc, ecore_test_promise_all);
355 tcase_add_test(tc, ecore_test_promise_all_then_then);
356 tcase_add_test(tc, ecore_test_promise_then_after_thread_finished);
357 tcase_add_test(tc, ecore_test_promise_then_after_thread_finished_all);
358 tcase_add_test(tc, ecore_test_promise_blocking_get);
359 tcase_add_test(tc, ecore_test_promise_blocking_get_all);
360 tcase_add_test(tc, ecore_test_promise_normal_lifetime);
361 tcase_add_test(tc, ecore_test_promise_normal_lifetime_all);
362 tcase_add_test(tc, ecore_test_promise_immediate_set_lifetime);
363 tcase_add_test(tc, ecore_test_promise_immediate_set_lifetime_all);
364}