Skip to content

Commit f583a3e

Browse files
committed
update dependency - bug fix, expose future/promise
- transformed `uv_queue_work` to c++11 future/promise thread pool style add working example, same libuv and stage test
1 parent ab20bf0 commit f583a3e

File tree

11 files changed

+526
-108
lines changed

11 files changed

+526
-108
lines changed

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}")
2525
find_package(raii QUIET)
2626
if(NOT raii_FOUND)
2727
FetchContent_Declare(raii
28-
URL https://github.com/zelang-dev/c-raii/archive/refs/tags/2.0.0.zip
29-
URL_MD5 2bb38a0fae3c276139b4ec78c8b670ef
28+
URL https://github.com/zelang-dev/c-raii/archive/refs/tags/2.1.0.zip
29+
URL_MD5 e97338afb9360b320aecf74716be5fdc
3030
)
3131
FetchContent_MakeAvailable(raii)
3232
endif()

README.md

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ The *[tests](https://github.com/dermesser/uvco/tree/master/test)* presented ther
244244
245245
## Design
246246
247-
The *intergration* pattern for all **libuv** functions taking *callback* is as [queue-work.c](https://github.com/zelang-dev/c-asio/tree/main/examples/queue-work.c) **example**:
247+
The *intergration* pattern for all **libuv** functions taking *callback* is as [waitgroup_work.c](https://github.com/zelang-dev/c-asio/tree/main/examples/waitgroup_work.c) **example**:
248248
249249
```c
250250
#define USE_CORO
@@ -489,6 +489,51 @@ C_API bool is_tty_err(void_t);
489489
C_API bool is_addrinfo(void_t);
490490
C_API bool is_nameinfo(void_t);
491491

492+
C_API bool is_promise(void_t);
493+
C_API bool is_future(void_t);
494+
495+
/*
496+
This runs the function `fn` asynchronously (potentially in a separate thread which
497+
might be a part of a thread pool) and returns a `future` that will eventually hold
498+
the result of that function call.
499+
500+
Similar to: https://en.cppreference.com/w/cpp/thread/async.html
501+
https://en.cppreference.com/w/cpp/thread/packaged_task.html
502+
503+
MUST call either `queue_then()` or `queue_get()` to actually start execution in thread.
504+
*/
505+
C_API future queue_work(thrd_func_t fn, size_t num_args, ...);
506+
507+
/*
508+
This will complete an normal `uv_queue_work()` setup execution and allow thread to run
509+
`queue_work()` provided `fn`.
510+
511+
Will return `promise` only useful with `queue_get()`.
512+
513+
Similar to: https://en.cppreference.com/w/cpp/thread/promise.html */
514+
C_API promise *queue_then(future, queue_cb callback);
515+
516+
/*
517+
This waits aka `yield` until the `future` or `promise` is ready, then retrieves
518+
the value stored. Right after calling this function `queue_is_valid()` is `false`.
519+
520+
Similar to: https://en.cppreference.com/w/cpp/thread/future/get.html */
521+
C_API template_t queue_get(void_t);
522+
523+
/*
524+
Checks if the ~future/uv_work_t~ refers to a shared state aka `promise`, and `running`.
525+
526+
Similar to: https://en.cppreference.com/w/cpp/thread/future/valid.html
527+
*/
528+
C_API bool queue_is_valid(future);
529+
530+
/*
531+
Will `pause` and `yield` to another `coroutine` until `ALL` ~future/uv_work_t~
532+
results/requests in `array` become available/done. Calls `queue_is_valid()` on each.
533+
534+
Similar to: https://en.cppreference.com/w/cpp/thread/future/wait.html */
535+
C_API void queue_wait(arrays_t);
536+
492537
/**
493538
* Initializes the process handle and starts the process.
494539
* If the process is successfully spawned, this function will return `spawn_t`

docs/index.md

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ The *[tests](https://github.com/dermesser/uvco/tree/master/test)* presented ther
244244
245245
## Design
246246
247-
The *intergration* pattern for all **libuv** functions taking *callback* is as [queue-work.c](https://github.com/zelang-dev/c-asio/tree/main/examples/queue-work.c) **example**:
247+
The *intergration* pattern for all **libuv** functions taking *callback* is as [waitgroup_work.c](https://github.com/zelang-dev/c-asio/tree/main/examples/waitgroup_work.c) **example**:
248248
249249
```c
250250
#define USE_CORO
@@ -489,6 +489,51 @@ C_API bool is_tty_err(void_t);
489489
C_API bool is_addrinfo(void_t);
490490
C_API bool is_nameinfo(void_t);
491491

492+
C_API bool is_promise(void_t);
493+
C_API bool is_future(void_t);
494+
495+
/*
496+
This runs the function `fn` asynchronously (potentially in a separate thread which
497+
might be a part of a thread pool) and returns a `future` that will eventually hold
498+
the result of that function call.
499+
500+
Similar to: https://en.cppreference.com/w/cpp/thread/async.html
501+
https://en.cppreference.com/w/cpp/thread/packaged_task.html
502+
503+
MUST call either `queue_then()` or `queue_get()` to actually start execution in thread.
504+
*/
505+
C_API future queue_work(thrd_func_t fn, size_t num_args, ...);
506+
507+
/*
508+
This will complete an normal `uv_queue_work()` setup execution and allow thread to run
509+
`queue_work()` provided `fn`.
510+
511+
Will return `promise` only useful with `queue_get()`.
512+
513+
Similar to: https://en.cppreference.com/w/cpp/thread/promise.html */
514+
C_API promise *queue_then(future, queue_cb callback);
515+
516+
/*
517+
This waits aka `yield` until the `future` or `promise` is ready, then retrieves
518+
the value stored. Right after calling this function `queue_is_valid()` is `false`.
519+
520+
Similar to: https://en.cppreference.com/w/cpp/thread/future/get.html */
521+
C_API template_t queue_get(void_t);
522+
523+
/*
524+
Checks if the ~future/uv_work_t~ refers to a shared state aka `promise`, and `running`.
525+
526+
Similar to: https://en.cppreference.com/w/cpp/thread/future/valid.html
527+
*/
528+
C_API bool queue_is_valid(future);
529+
530+
/*
531+
Will `pause` and `yield` to another `coroutine` until `ALL` ~future/uv_work_t~
532+
results/requests in `array` become available/done. Calls `queue_is_valid()` on each.
533+
534+
Similar to: https://en.cppreference.com/w/cpp/thread/future/wait.html */
535+
C_API void queue_wait(arrays_t);
536+
492537
/**
493538
* Initializes the process handle and starts the process.
494539
* If the process is successfully spawned, this function will return `spawn_t`

examples/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ set(TARGET_LIST
1414
create-x509
1515
uv_tls_server
1616
uv_tls_client
17+
waitgroup_work
1718
)
1819

1920
foreach (TARGET ${TARGET_LIST})

examples/queue-work.c

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
#define USE_CORO
2-
#include "raii.h"
1+
#include "asio.h"
32

43
#define FIB_UNTIL 25
54

@@ -10,37 +9,35 @@ long fib_(long t) {
109
return fib_(t-1) + fib_(t-2);
1110
}
1211

13-
void_t fib(params_t req) {
14-
int n = req->integer;
15-
if (random() % 2)
16-
sleepfor(1);
12+
void_t fib(args_t req) {
13+
int n = req->integer;
14+
if (random() % 2)
15+
sleep(1);
1716
else
18-
sleepfor(3);
17+
sleep(3);
18+
long fib = fib_(n);
19+
fprintf(stderr, "%dth fibonacci is %lu"CLR_LN, n, fib);
1920

20-
long fib = fib_(n);
21-
fprintf(stderr, "%dth fibonacci is %lu in thrd: #%d\033[0K\n", n, fib, coro_thrd_id());
22-
23-
return casting(fib);
21+
return $$(n, fib);
2422
}
2523

26-
void after_fib(int status, rid_t id) {
27-
fprintf(stderr, "Done calculating %dth fibonacci, result: %d\n", status, result_for(id).integer);
24+
void after_fib(vectors_t req) {
25+
fprintf(stderr, "Done calculating %dth fibonacci, result: %d"CLR_LN,
26+
req[0].integer, req[1].integer);
2827
}
2928

30-
int main(int argc, char **argv) {
31-
rid_t data[FIB_UNTIL];
32-
int i;
29+
int uv_main(int argc, char **argv) {
30+
arrays_t arr = arrays();
31+
int i;
3332

34-
waitgroup_t wg = waitgroup_ex(FIB_UNTIL);
35-
for (i = 0; i < FIB_UNTIL; i++) {
36-
data[i] = go(fib, 1, casting(i));
37-
}
38-
waitresult_t wgr = waitfor(wg);
33+
yield();
34+
for (i = 0; i < FIB_UNTIL; i++) {
35+
future req = queue_work(fib, 1, casting(i));
36+
$append(arr, req);
37+
queue_then(req, after_fib);
38+
}
3939

40-
if ($size(wgr) == FIB_UNTIL)
41-
for (i = 0; i < FIB_UNTIL; i++) {
42-
after_fib(i, data[i]);
43-
}
40+
queue_wait(arr);
4441

45-
return 0;
42+
return 0;
4643
}

examples/waitgroup_work.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#define USE_CORO
2+
#include "raii.h"
3+
4+
#define FIB_UNTIL 25
5+
6+
long fib_(long t) {
7+
if (t == 0 || t == 1)
8+
return 1;
9+
else
10+
return fib_(t-1) + fib_(t-2);
11+
}
12+
13+
void_t fib(params_t req) {
14+
int n = req->integer;
15+
if (random() % 2)
16+
sleepfor(1);
17+
else
18+
sleepfor(3);
19+
20+
long fib = fib_(n);
21+
fprintf(stderr, "%dth fibonacci is %lu in thrd: #%d\033[0K\n", n, fib, coro_thrd_id());
22+
23+
return casting(fib);
24+
}
25+
26+
void after_fib(int status, rid_t id) {
27+
fprintf(stderr, "Done calculating %dth fibonacci, result: %d\n", status, result_for(id).integer);
28+
}
29+
30+
int main(int argc, char **argv) {
31+
rid_t data[FIB_UNTIL];
32+
int i;
33+
34+
waitgroup_t wg = waitgroup_ex(FIB_UNTIL);
35+
for (i = 0; i < FIB_UNTIL; i++) {
36+
data[i] = go(fib, 1, casting(i));
37+
}
38+
waitresult_t wgr = waitfor(wg);
39+
40+
if ($size(wgr) == FIB_UNTIL)
41+
for (i = 0; i < FIB_UNTIL; i++)
42+
after_fib(i, data[i]);
43+
44+
return 0;
45+
}

include/asio.h

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,17 @@
22
#define _ASIO_H
33

44
#define INTERRUPT_MODE UV_RUN_NOWAIT
5-
#ifndef CERTIFICATE
6-
#define CERTIFICATE "localhost"
7-
#endif
85

96
#include "evt_tls.h"
107
#include "url_http.h"
118
#include "reflection.h"
129

1310
#ifdef _WIN32
14-
#define INVALID_FD -EBADF
1511
#define use_ipc false
1612
#else
17-
#define INVALID_FD -EBADF
1813
#define use_ipc true
1914
#endif
15+
#define INVALID_FD -EBADF
2016

2117
/* Cast ~libuv~ `obj` to `uv_stream_t` ptr. */
2218
#define streamer(obj) ((uv_stream_t *)obj)
@@ -201,6 +197,7 @@ typedef void (*stream_cb)(uv_stream_t *);
201197
typedef void (*packet_cb)(udp_packet_t *);
202198
typedef void (*spawn_cb)(int64_t status, int signal);
203199
typedef void (*spawn_handler_cb)(uv_stream_t *input, string output, uv_stream_t *duplex);
200+
typedef void (*queue_cb)(vectors_t result);
204201

205202
typedef struct {
206203
asio_types type;
@@ -481,6 +478,49 @@ C_API int udp_send(uv_udp_t *handle, string_t message, string_t addr);
481478
C_API udp_packet_t *udp_recv(uv_udp_t *);
482479
C_API int udp_send_packet(udp_packet_t *, string_t);
483480

481+
/*
482+
This runs the function `fn` asynchronously (potentially in a separate thread which
483+
might be a part of a thread pool) and returns a `future` that will eventually hold
484+
the result of that function call.
485+
486+
Similar to: https://en.cppreference.com/w/cpp/thread/async.html
487+
https://en.cppreference.com/w/cpp/thread/packaged_task.html
488+
489+
MUST call either `queue_then()` or `queue_get()` to actually start execution in thread.
490+
*/
491+
C_API future queue_work(thrd_func_t fn, size_t num_args, ...);
492+
493+
/*
494+
This will complete an normal `uv_queue_work()` setup execution and allow thread to run
495+
`queue_work()` provided `fn`.
496+
497+
Will return `promise` only useful with `queue_get()`.
498+
499+
Similar to: https://en.cppreference.com/w/cpp/thread/promise.html */
500+
C_API promise *queue_then(future, queue_cb callback);
501+
502+
/*
503+
This waits aka `yield` until the `future` or `promise` is ready, then retrieves
504+
the value stored. Right after calling this function `queue_is_valid()` is `false`.
505+
506+
Similar to: https://en.cppreference.com/w/cpp/thread/future/get.html */
507+
C_API template_t queue_get(void_t);
508+
509+
/*
510+
Checks if the ~future/uv_work_t~ refers to a shared state aka `promise`, and `running`.
511+
512+
Similar to: https://en.cppreference.com/w/cpp/thread/future/valid.html
513+
*/
514+
C_API bool queue_is_valid(future);
515+
516+
/*
517+
Will `pause` and `yield` to another `coroutine` until `ALL` ~future/uv_work_t~
518+
results/requests in `array` become available/done. Calls `queue_is_valid()` on each.
519+
520+
Similar to: https://en.cppreference.com/w/cpp/thread/future/wait.html */
521+
C_API void queue_wait(arrays_t);
522+
C_API void queue_delete(future);
523+
484524
#define UV_TLS RAII_SCHEME_TLS
485525
#define UV_CTX ASIO_ARGS + RAII_NAN
486526

@@ -517,7 +557,9 @@ C_API bool is_tty_out(void_t);
517557
C_API bool is_tty_err(void_t);
518558
C_API bool is_addrinfo(void_t);
519559
C_API bool is_nameinfo(void_t);
520-
C_API bool is_addressable(void_t);
560+
561+
C_API bool is_promise(void_t);
562+
C_API bool is_future(void_t);
521563

522564
/* This library provides its own ~main~,
523565
which call this function as an coroutine! */

0 commit comments

Comments
 (0)