Skip to content

Commit

Permalink
code clean
Browse files Browse the repository at this point in the history
  • Loading branch information
piaodazhu committed Nov 5, 2022
1 parent bca95c6 commit 1e4bafb
Show file tree
Hide file tree
Showing 18 changed files with 332 additions and 214 deletions.
59 changes: 59 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Features of dyco-coroutine:
9. TLS/SSL non-block concurrent server support.
10. Scheduler and be stopped by any coroutine, and continue running in main process.
11. Multi-thread supported.
12. Asymmetric coroutine is supported.

![DYCOARCH](./img/arch.png)

Expand Down Expand Up @@ -425,6 +426,64 @@ int dyco_SSL_read(SSL *ssl, void *buf, int num);
int dyco_SSL_write(SSL *ssl, const void *buf, int num);
```

## Asymmetric Coroutine & Asymmetric Coroutines Pool

Asymmetric coroutine is also supported, althougth in most case symmetric coroutine is more user-friendly than asymmetric coroutine. There are 2 specific API for asymmetric coroutine: `resume` and `yield`. A asymmetric coroutine can be create in main process or inside any coroutine. **Note that it won't be scheduled by dyco scheduler**. To start the coroutine, you should call `resume` with its `cid`. And inside this coroutines, you can call `yield` to go back to the context where `resume` was called. `resume` will return 0 if the asymmetric coroutine finish. Then you should free this coroutine manually by call `dyco_asymcoro_free`.

Since asymmetric coroutine is not scheduled by dyco scheduler, **all features mentioned before is not supported to asymmetric coroutine**.

`setStack` is **optional**. If a asymmetric coroutine need to be resumed inside a symmetric coroutine, you **must** set a independent stack for this asymmetric coroutine.

See more in `example/asymmetric_example.c`.

**Asymmetric Coroutines Pool** is provided to avoid create and release coroutine/stack memory frequently. The asymmetric coroutines pool can be create at any time and be resized after it created. Asymmetric coroutines who belongs to a asymmetric corotines pool **will not** automatically return to the pool after user function finishes. By calling `obtain`, you can get a free coroutine from the pool. Then by calling `return`, you can return a finished coroutine to the pool.

```c
// return 1 if the coroutine is asymmetric, 0 if symmetric
int dyco_coroutine_isasymmetric(int cid);

// return the coroutine ID on success, < 0 on error
int dyco_asymcoro_create(proc_coroutine func, void *arg);

// return cid on coroutine yield, 0 on coroutine finish, < 0 on error
int dyco_asymcoro_resume(int cid);

// interupt and go back
void dyco_asymcoro_yield();

void dyco_asymcoro_free(int cid);

// return ID of current coroutine
int dyco_asymcoro_coroID();

// stacksize: 0 to cancel independent stack
// return 1 on successfully set, 0 on successfully cancel, < 0 on error
int dyco_asymcoro_setStack(int cid, void *stackptr, size_t stacksize);
int dyco_asymcoro_getStack(int cid, void **stackptr, size_t *stacksize);

// return 0 on success
int dyco_asymcoro_setUdata(int cid, void *udata);
int dyco_asymcoro_getUdata(int cid, void **udata);

// return NULL on error
dyco_coropool* dyco_asymcpool_create(int totalsize, size_t stacksize);
dyco_coropool* dyco_asymcpool_resize(dyco_coropool* cp, int newsize);

// return 0 on success
int dyco_asymcpool_destroy(dyco_coropool** cp);

// return number of available coroutine in this pool
int dyco_asymcpool_available(dyco_coropool* cp);

// obtain a coroutine from the pool.
// If there is no free coroutine, wait timeout
// return 0 on timeout, -1 on error, > 0 on success
int dyco_asymcpool_obtain(dyco_coropool* cp, proc_coroutine func, void *arg, int timeout);

// return a finished coroutine to the pool
void dyco_asymcpool_return(int cid);
```
# About Coroutine
There are 3 mainstream ways to implement coroutine switch:
Expand Down
59 changes: 59 additions & 0 deletions README_ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
9. 支持非阻塞的TLS/SSL并发服务。
10. 调度器及其管理的协程可以被暂停,然后在适当的时机恢复。
11. 支持多线程。
12. 支持非对称协程。

![DYCOARCH](./img/arch.png)

Expand Down Expand Up @@ -445,6 +446,64 @@ int dyco_SSL_read(SSL *ssl, void *buf, int num);
int dyco_SSL_write(SSL *ssl, const void *buf, int num);
```

## Asymmetric Coroutine & Asymmetric Coroutines Pool

dyco也支持非对称协程,尽管在大多数情况下对称协程比非对称协程更好用。非对称协程有两个专门的API:`resume``yield`。一个非对称协程可以在主程序或者任意一个协程内部创建。**需要注意的是,非对称协程不会被dyco调度器调度**。要启动这个协程,你应该带上它的`cid`去调用`resume`。在这个协程函数里面,可以通过调用`yield`来返回调用`resume`的上下文。如果协程函数执行完毕,`resume`会返回0。这时需要手动调用`dyco_asymcoro_free`来释放这个非对称协程。

由于非对称协程不会被dyco调度器调度,**因此前面提到的所有特性都不支持非对称协程**

`setStack`**可选的**。如果一个非对称协程需要在一个对程协程内被唤起执行,你**必须**确保这个非对称协程具有独立栈。

详见`example/asymmetric_example.c`

dyco也提供了**非对称协程池**来防止频繁地创建释放非对称协程和栈的内存空间。任何时候都可以创建非对称协程池,创建完成后可以修改协程池的大小。非对称协程池中的协程在用户函数执行完成后**不会**自动归还到协程池。通过调用`obtain`,你可以从协程池中获得一个空闲协程。通过调用`return`,你可以将一个执行完成的协程归还到协程池。

```c
// return 1 if the coroutine is asymmetric, 0 if symmetric
int dyco_coroutine_isasymmetric(int cid);

// return the coroutine ID on success, < 0 on error
int dyco_asymcoro_create(proc_coroutine func, void *arg);

// return cid on coroutine yield, 0 on coroutine finish, < 0 on error
int dyco_asymcoro_resume(int cid);

// interupt and go back
void dyco_asymcoro_yield();

void dyco_asymcoro_free(int cid);

// return ID of current coroutine
int dyco_asymcoro_coroID();

// stacksize: 0 to cancel independent stack
// return 1 on successfully set, 0 on successfully cancel, < 0 on error
int dyco_asymcoro_setStack(int cid, void *stackptr, size_t stacksize);
int dyco_asymcoro_getStack(int cid, void **stackptr, size_t *stacksize);

// return 0 on success
int dyco_asymcoro_setUdata(int cid, void *udata);
int dyco_asymcoro_getUdata(int cid, void **udata);

// return NULL on error
dyco_coropool* dyco_asymcpool_create(int totalsize, size_t stacksize);
dyco_coropool* dyco_asymcpool_resize(dyco_coropool* cp, int newsize);

// return 0 on success
int dyco_asymcpool_destroy(dyco_coropool** cp);

// return number of available coroutine in this pool
int dyco_asymcpool_available(dyco_coropool* cp);

// obtain a coroutine from the pool.
// If there is no free coroutine, wait timeout
// return 0 on timeout, -1 on error, > 0 on success
int dyco_asymcpool_obtain(dyco_coropool* cp, proc_coroutine func, void *arg, int timeout);

// return a finished coroutine to the pool
void dyco_asymcpool_return(int cid);
```
# About Coroutine
有3种实现协程切换的主流方案:
Expand Down
68 changes: 34 additions & 34 deletions example/meson.build
Original file line number Diff line number Diff line change
@@ -1,109 +1,109 @@
example_coropool = executable(
'example_asymmetric',
coropool_example = executable(
'asymmetric_example',
'asymmetric.c',
include_directories : header_dir,
c_args : build_args,
link_with : libdyco
)

example_channel = executable(
'example_channel',
channel_example = executable(
'channel_example',
'channel.c',
include_directories : header_dir,
c_args : build_args,
link_with : libdyco
)

example_coropool = executable(
'example_coropool',
coropool_example = executable(
'coropool_example',
'coropool.c',
include_directories : header_dir,
c_args : build_args,
link_with : libdyco
)

example_epoll = executable(
'example_epoll',
epoll_example = executable(
'epoll_example',
'epoll.c',
include_directories : header_dir,
c_args : build_args,
link_with : libdyco
)

example_multithread = executable(
'example_multithread',
multithread_example = executable(
'multithread_example',
'multithread.c',
include_directories : header_dir,
c_args : build_args,
link_with : libdyco
)

example_pubsub = executable(
'example_pubsub',
pubsub_example = executable(
'pubsub_example',
'pubsub.c',
include_directories : header_dir,
c_args : build_args,
link_with : libdyco
)

example_semaphore = executable(
'example_semaphore',
semaphore_example = executable(
'semaphore_example',
'semaphore.c',
include_directories : header_dir,
c_args : build_args,
link_with : libdyco
)

example_setstack = executable(
'example_setstack',
setstack_example = executable(
'setstack_example',
'setstack.c',
include_directories : header_dir,
c_args : build_args,
link_with : libdyco
)

example_signal = executable(
'example_signal',
signal_example = executable(
'signal_example',
'signal.c',
include_directories : header_dir,
c_args : build_args,
link_with : libdyco
)

example_sleep = executable(
'example_sleep',
sleep_example = executable(
'sleep_example',
'sleep.c',
include_directories : header_dir,
c_args : build_args,
link_with : libdyco
)

example_stop_abort = executable(
'example_stop_abort',
stop_abort_example = executable(
'stop_abort_example',
'stop_abort.c',
include_directories : header_dir,
c_args : build_args,
link_with : libdyco
)

example_waitgroup = executable(
'example_waitgroup',
waitgroup_example = executable(
'waitgroup_example',
'waitgroup.c',
include_directories : header_dir,
c_args : build_args,
link_with : libdyco
)

example_socket_client = executable(
'example_socket_client',
socket_client_example = executable(
'socket_client_example',
'socket_client.c',
include_directories : header_dir,
c_args : build_args,
link_with : libdyco
)

example_socket_server = executable(
'example_socket_server',
socket_server_example = executable(
'socket_server_example',
'socket_server.c',
include_directories : header_dir,
c_args : build_args,
Expand All @@ -112,17 +112,17 @@ example_socket_server = executable(


if crypto_dep.found() and ssl_dep.found()
example_ssl_client = executable(
'example_ssl_client',
ssl_client_example = executable(
'ssl_client_example',
'ssl_client.c',
include_directories : header_dir,
c_args : build_args,
dependencies : [crypto_dep, ssl_dep],
link_with : libdyco
)

example_ssl_server = executable(
'example_ssl_server',
ssl_server_example = executable(
'ssl_server_example',
'ssl_server.c',
include_directories : header_dir,
c_args : build_args,
Expand All @@ -134,8 +134,8 @@ else
endif

if hiredis_dep.found()
example_network = executable(
'example_network',
network_example = executable(
'network_example',
'network.c',
include_directories : header_dir,
c_args : build_args,
Expand Down
10 changes: 10 additions & 0 deletions history.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
## 2022-11-5: v1.2.0 released!

Updates:
1. Support Asymmetric Coroutine & Asymmetric Coroutines Pool for manually schedualing.
2. Adjust scheduler loop policy for better event reaction.
3. Better multi-platform support.
3. Support Meson build.
4. Fix some bugs.
5. Improve the documents. Bring some new plans in future works.

## 2022-10-29: v1.1.0 released!

Updates:
Expand Down
Binary file modified img/arch.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 18 additions & 3 deletions src/dyco_asymcoro.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
#include "dyco_coroutine.h"

int
dyco_coroutine_isasymmetric(int cid)
{
dyco_schedule *sched = _get_sched();
if (sched == NULL) {
return -2;
}
dyco_coroutine *co = _htable_find(&sched->cid_co_map, cid);
if (co == NULL) {
return -1;
}

return TESTBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC);
}

static void
_exec(void *c) {
dyco_coroutine *co = (dyco_coroutine*)c;
Expand Down Expand Up @@ -30,7 +45,7 @@ _init_coro(dyco_coroutine *co)
int
dyco_asymcoro_create(proc_coroutine func, void *arg)
{
dyco_coroutine *co = dyco_coroutine_new();
dyco_coroutine *co = _newcoro();
if (co == NULL) {
printf("Failed to allocate memory for new coroutine\n");
return -2;
Expand Down Expand Up @@ -67,7 +82,7 @@ dyco_asymcoro_resume(int cid)
if (TESTBIT(co_next->status, COROUTINE_STATUS_NEW)) {
_init_coro(co_next);
} else {
_load_stack(co_next);
_loadstk(co_next);
}

++co_next->sched_count;
Expand Down Expand Up @@ -95,7 +110,7 @@ dyco_asymcoro_yield()
assert(co != NULL);

if (TESTBIT(co->status, COROUTINE_STATUS_EXITED) == 0) {
_save_stack(co);
_savestk(co);
}
CLRBIT(co->status, COROUTINE_STATUS_RUNNING);
swapcontext(&co->ctx, &co->ret);
Expand Down
1 change: 1 addition & 0 deletions src/dyco_channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ _hdc_wait(dyco_channel* chan, int fd, int timeout)
if (co == NULL) {
return chan->status;
}
assert(!TESTBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC));

struct epoll_event ev;
ev.data.fd = fd;
Expand Down
Loading

0 comments on commit 1e4bafb

Please sign in to comment.