├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── README_ZH.md ├── cert ├── gen_key └── meson.build ├── evaluation.txt ├── example ├── Makefile ├── asymmetric.c ├── channel.c ├── coropool.c ├── epoll.c ├── meson.build ├── multithread.c ├── network.c ├── pubsub.c ├── semaphore.c ├── setstack.c ├── signal.c ├── sleep.c ├── socket_client.c ├── socket_server.c ├── ssl_client.c ├── ssl_server.c ├── stack_dont_overflow.c ├── stop_abort.c └── waitgroup.c ├── history.md ├── img ├── arch.png └── dyco.png ├── include └── dyco │ ├── dyco_coroutine.h │ ├── dyco_htable.h │ ├── dyco_ucontext.h │ ├── sys_queue.h │ ├── sys_tree.h │ ├── uctx_386.h │ ├── uctx_amd64.h │ ├── uctx_mips.h │ └── uctx_power.h ├── meson.build ├── src ├── Makefile ├── dyco_asymcoro.c ├── dyco_channel.c ├── dyco_coropool.c ├── dyco_coroutine.c ├── dyco_epoll.c ├── dyco_hook.c ├── dyco_pubsub.c ├── dyco_schedcall.c ├── dyco_schedule.c ├── dyco_semaphore.c ├── dyco_signal.c ├── dyco_socket.c ├── dyco_ssl.c ├── dyco_waitgroup.c ├── uctx_asm.S └── uctx_context.c └── switchtest ├── switch_dyco.c ├── switch_libco.cc └── switch_ntyco.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | .vscode 55 | tmp/** 56 | bin/** 57 | .vscode/** 58 | todo 59 | .vscode/settings.json 60 | contextswitch.txt 61 | *.cert 62 | *.pem 63 | *.crt 64 | *.key 65 | build/** 66 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | ECHO = echo 3 | 4 | PROJECTNAME = dyco 5 | SUB_DIR = src/ example/ 6 | ROOT_DIR = $(shell pwd) 7 | OBJS_DIR = $(ROOT_DIR)/objs 8 | BIN_DIR = $(ROOT_DIR)/bin 9 | LIB_DIR = $(ROOT_DIR)/lib 10 | SRC_DIR = $(ROOT_DIR)/src 11 | HDR_DIR = $(ROOT_DIR)/include 12 | 13 | OBJS = $(patsubst %.c, %.o, $(notdir $(wildcard $(SRC_DIR)/*.c))) 14 | OBJS += $(patsubst %.S, %.o, $(notdir $(wildcard $(SRC_DIR)/*.S))) 15 | HDR_DIR_INSTALL_DIR = /usr/local/include 16 | LIB = libdyco.so 17 | LIB_INSTALL_DIR = /usr/local/lib 18 | 19 | BIN = socket_server_example socket_client_example epoll_example sleep_example setstack_example signal_example stop_abort_example channel_example waitgroup_example pubsub_example semaphore_example multithread_example coropool_example asymmetric_example stack_dont_overflow_example 20 | 21 | FLAG = -O3 -lpthread -ldl -I $(HDR_DIR) 22 | SSLFLAG = -lssl -lcrypto -D DYCO_SSL_OK 23 | 24 | HASSSL := $(shell if [ -d /usr/local/include/openssl ] || [ -d /usr/include/openssl ]; then echo 1; fi) 25 | HASRDS := $(shell if [ -d /usr/local/include/hiredis ] || [ -d /usr/include/hiredis ]; then echo 1; fi) 26 | 27 | ifdef HASRDS 28 | BIN += network_example 29 | endif 30 | 31 | ifdef HASSSL 32 | BIN += ssl_server_example ssl_client_example 33 | FLAG += $(SSLFLAG) 34 | endif 35 | 36 | export CC BIN_DIR OBJS_DIR ROOT_DIR FLAG BIN ECHO LIB_DIR 37 | 38 | all : PREPARE $(SUB_DIR) $(BIN) $(LIB) 39 | .PHONY : all clean 40 | 41 | PREPARE: 42 | mkdir -p $(OBJS_DIR) $(BIN_DIR) $(LIB_DIR) 43 | 44 | $(SUB_DIR) : ECHO 45 | make -C $@ 46 | 47 | ECHO : 48 | @echo $(SUB_DIR) 49 | 50 | 51 | socket_server_example : $(addprefix $(OBJS_DIR)/, $(OBJS)) $(OBJS_DIR)/socket_server.o 52 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 53 | 54 | socket_client_example : $(addprefix $(OBJS_DIR)/, $(OBJS)) $(OBJS_DIR)/socket_client.o 55 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 56 | 57 | epoll_example : $(addprefix $(OBJS_DIR)/, $(OBJS)) $(OBJS_DIR)/epoll.o 58 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 59 | 60 | sleep_example: $(addprefix $(OBJS_DIR)/, $(OBJS)) $(OBJS_DIR)/sleep.o 61 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 62 | 63 | setstack_example: $(addprefix $(OBJS_DIR)/, $(OBJS)) $(OBJS_DIR)/setstack.o 64 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 65 | 66 | signal_example: $(addprefix $(OBJS_DIR)/, $(OBJS)) $(OBJS_DIR)/signal.o 67 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 68 | 69 | stop_abort_example: $(addprefix $(OBJS_DIR)/, $(OBJS)) $(OBJS_DIR)/stop_abort.o 70 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 71 | 72 | channel_example: $(addprefix $(OBJS_DIR)/, $(OBJS)) $(OBJS_DIR)/channel.o 73 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 74 | 75 | waitgroup_example: $(addprefix $(OBJS_DIR)/, $(OBJS)) $(OBJS_DIR)/waitgroup.o 76 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 77 | 78 | pubsub_example: $(addprefix $(OBJS_DIR)/, $(OBJS)) $(OBJS_DIR)/pubsub.o 79 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 80 | 81 | semaphore_example: $(addprefix $(OBJS_DIR)/, $(OBJS)) $(OBJS_DIR)/semaphore.o 82 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 83 | 84 | network_example: $(addprefix $(OBJS_DIR)/, $(OBJS)) $(OBJS_DIR)/network.o 85 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) -lhiredis 86 | 87 | ssl_server_example: $(addprefix $(OBJS_DIR)/, $(OBJS)) $(OBJS_DIR)/ssl_server.o 88 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 89 | 90 | ssl_client_example: $(addprefix $(OBJS_DIR)/, $(OBJS)) $(OBJS_DIR)/ssl_client.o 91 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 92 | 93 | multithread_example: $(addprefix $(OBJS_DIR)/, $(OBJS)) $(OBJS_DIR)/multithread.o 94 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 95 | 96 | coropool_example: $(addprefix $(OBJS_DIR)/, $(OBJS)) $(OBJS_DIR)/coropool.o 97 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 98 | 99 | asymmetric_example: $(addprefix $(OBJS_DIR)/, $(OBJS)) $(OBJS_DIR)/asymmetric.o 100 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 101 | 102 | stack_dont_overflow_example: $(addprefix $(OBJS_DIR)/, $(OBJS)) $(OBJS_DIR)/stack_dont_overflow.o 103 | $(CC) -o $(BIN_DIR)/$@ $^ $(FLAG) 104 | 105 | $(LIB): $(addprefix $(LIB_DIR)/, $(OBJS)) 106 | $(CC) -shared -o $(LIB_DIR)/$@ $^ $(FLAG) 107 | 108 | install: $(LIB) 109 | cp $(LIB_DIR)/$(LIB) $(LIB_INSTALL_DIR) 110 | cp -r $(HDR_DIR)/$(PROJECTNAME) $(HDR_DIR_INSTALL_DIR) 111 | ldconfig 112 | rm -rf *.o *.so* 113 | echo "Installing done." 114 | 115 | uninstall: 116 | rm -rf $(LIB_INSTALL_DIR)/$(LIB) 117 | rm -rf $(HDR_DIR_INSTALL_DIR)/$(PROJECTNAME) 118 | ldconfig 119 | echo "Uninstalling done." 120 | 121 | clean: 122 | rm -rf $(BIN_DIR)/* $(OBJS_DIR)/* $(LIB_DIR)/* 123 | 124 | -------------------------------------------------------------------------------- /cert/gen_key: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | key_dir=. 3 | 4 | private_key="$key_dir/private_key.pem" 5 | private_password=12345678 6 | 7 | certificate="$key_dir/certificate.crt" 8 | certificate_info="/C=NL/ST=Some-State/O=x x/CN=Server" 9 | 10 | rm "$private_key" 11 | rm "$certificate" 12 | 13 | openssl req -x509 -sha1 -newkey rsa:2048 -keyout "$private_key" -out "$certificate" -outform PEM -days 1825 -subj "$certificate_info" -passout pass:$private_password 14 | 15 | 16 | -------------------------------------------------------------------------------- /cert/meson.build: -------------------------------------------------------------------------------- 1 | run_command('./gen_key', check: true) -------------------------------------------------------------------------------- /evaluation.txt: -------------------------------------------------------------------------------- 1 | A. Concurrency Evalution 2 | setup: 3 | Platform: 11th Gen Intel(R) Core(TM) i7-11700 @ 2.50GHz 4 | Core number: 2 5 | Memory: 2GB 6 | OS: Ubuntu Server 22.04.1 LTS 7 | 8 | Scenerio: 9 | A TCP echo service. Each client connects the service, send a message and receive the reply for 3 times, then close the connection. We change the concurrent number ot the clients and test different implementations this TCP echo server: stupid loop / multi-thread / epoll / dyco / libco. 10 | 11 | Tool: 12 | NeTest (https://github.com/piaodazhu/netest) 13 | 14 | Result: 15 | 16 | a. Service per Second (services/s): 17 | Server stupid loop multi-thread epoll dyco dyco-indepentstack dyco-coropool libco 18 | Concurrent 19 | 100 9130 19526 50854 52854 50968 52336 54973 20 | 500 8751 18647 51647 50841 46977 48955 54207 21 | 1000 8581 15996 64525 43241 41195 39689 43042 22 | 5000 7884 17154 65645 41180 43403 41991 42613 23 | 10000 7252 17726 63414 50169 50747 54430 49130 24 | 25 | b. Average Latency (microseconds): 26 | Server stupid loop **multi-thread epoll dyco dyco-indepentstack dyco-coropool libco 27 | Concurren 28 | 100 10943 5117 1962 1887 1969 1914 1843 29 | 500 57149 26846 9693 9866 10793 10352 9259 30 | 1000 116676 63621 131647 23452 25728 25794 23549 31 | 5000 *706334 266379 127753 131220 143047 129685 127840 32 | 10000 *427296 291597 1570300 1542439 1278003 1441419 1325549 33 | 34 | (* session failure occurs) 35 | (** 2 CPU cores) 36 | 37 | B. Coroutine Switch Evalution 38 | setup: 39 | Platform: 11th Gen Intel(R) Core(TM) i7-700 @ 2.50GHz 40 | Core number: 2 41 | Memory: 2GB 42 | OS: Ubuntu Server 22.04.1 LTS 43 | 44 | Scenerio: 45 | Two simple counter coroutines who alternately execute. After 1000000 times of coroutine switches, we record the spent time and calculate the swithing time. 46 | 47 | Tool: 48 | switchtest/switch_dyco.c switchtest/switch_libco.c 49 | 50 | Result: 51 | dyco dyco-indepentstack libco NtyCo 52 | switch speed (M/s) 0.141227 0.141097 0.040588 0.140463 53 | -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | CUR_SOURCE = ${wildcard *.c} 2 | 3 | CUR_OBJS = ${patsubst %.c, %.o, $(CUR_SOURCE)} 4 | 5 | all : $(CUR_OBJS) 6 | 7 | $(CUR_OBJS) : %.o : %.c 8 | - $(CC) -c $^ -o $(OBJS_DIR)/$@ $(FLAG) 9 | 10 | ECHO : 11 | @echo $(SUB_DIR) 12 | -------------------------------------------------------------------------------- /example/asymmetric.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | void fibo_gen(void *arg) 4 | { 5 | int *times = arg; 6 | int f1 = 1; 7 | int f2 = 1; 8 | int f3 = 0; 9 | int *number = NULL; 10 | dyco_asymcoro_getUdata(dyco_asymcoro_coroID(), (void**)&number); 11 | printf("[fibo_gen] I am coro %d. I can generate fibonacci array\n", dyco_coroutine_coroID()); 12 | 13 | if (*times <= 0) { 14 | return; 15 | } 16 | else if (*times == 1) { 17 | *number = 1; 18 | return; 19 | } 20 | *number = 1; 21 | 22 | dyco_asymcoroyield(); // yield 1 23 | dyco_asymcoroyield(); // yield 1 24 | 25 | int i = 2; 26 | while (i < *times) { 27 | f3 = f1 + f2; 28 | f1 = f2; 29 | f2 = f3; 30 | *number = f3; 31 | dyco_asymcoroyield(); // yield 2 3 5 8 ... 32 | ++i; 33 | } 34 | *number = -1; 35 | return; 36 | } 37 | 38 | int fibogencid; 39 | void foo(void *arg) 40 | { 41 | int sleeptime = *(int*)arg; 42 | printf("I am coro %d. I'm about sleep %d ms\n", dyco_coroutine_coroID(), sleeptime); 43 | dyco_coroutine_sleep(sleeptime); 44 | printf("I am coro %d. Now I wake up and resume fibo_gen\n", dyco_coroutine_coroID()); 45 | 46 | int *number = NULL; 47 | int ret = dyco_asymcoro_getUdata(fibogencid, (void**)&number); 48 | if (ret != 0) { 49 | return; 50 | } 51 | ret = dyco_asymcororesume(fibogencid); 52 | 53 | printf("[+] coro %d get: %d. ret = %d\n", dyco_coroutine_coroID(), *number, ret); 54 | if (ret == 0) { 55 | printf("second asymmetric coroutine finished.\n"); 56 | dyco_asymcoro_free(fibogencid); 57 | } 58 | return; 59 | } 60 | 61 | void bar(void *arg) 62 | { 63 | int sleeptime = *(int*)arg; 64 | int i = 0; 65 | int *times = (int*)malloc(sizeof(int)); 66 | *times = 10; 67 | int cid = dyco_asymcoro_create(fibo_gen, times); 68 | assert(cid > 0); 69 | 70 | int *number = (int*)malloc(sizeof(int)); 71 | *number = 0; 72 | dyco_asymcoro_setUdata(cid, number); 73 | 74 | dyco_asymcoro_setStack(cid, NULL, 4096); 75 | while (dyco_asymcororesume(cid)) { 76 | printf("[+] coro %d get %d\n", dyco_coroutine_coroID(), *number); 77 | dyco_coroutine_sleep(sleeptime); 78 | } 79 | dyco_asymcoro_free(cid); 80 | } 81 | 82 | int main() 83 | { 84 | printf("\tA. create and resume asymmetric coroutines in main thread.\n"); 85 | int i = 0; 86 | int *times = (int*)malloc(sizeof(int)); 87 | *times = 30; 88 | int cid = dyco_asymcoro_create(fibo_gen, times); 89 | assert(cid > 0); 90 | 91 | int *number = (int*)malloc(sizeof(int)); 92 | *number = 0; 93 | dyco_asymcoro_setUdata(cid, number); 94 | 95 | dyco_asymcoro_setStack(cid, NULL, 4096); 96 | while (dyco_asymcororesume(cid)) { 97 | printf("%dth generate: %d\n", ++i, *number); 98 | } 99 | dyco_asymcoro_free(cid); 100 | printf("first asymmetric coroutine finished.\n"); 101 | 102 | printf("\tB. create asymmetric coroutines in main thread and resume in coroutines.\n"); 103 | *times = 4; 104 | fibogencid = dyco_asymcoro_create(fibo_gen, times); 105 | *number = -1; 106 | dyco_asymcoro_setUdata(fibogencid, number); 107 | 108 | int sleeptime[8]; 109 | for (i = 0; i < 8; i++) { 110 | sleeptime[i] = (i + 1) * 1000; 111 | dyco_coroutine_create(foo, sleeptime + i); 112 | } 113 | printf("[+] scheduler start running.\n"); 114 | dyco_schedule_run(); 115 | printf("[-] scheduler stopped.\n"); 116 | 117 | printf("\tC. create and resume asymmetric coroutines in coroutines.\n"); 118 | int t1 = 900, t2 = 500; 119 | dyco_coroutine_create(bar, &t1); 120 | dyco_coroutine_create(bar, &t2); 121 | printf("[+] scheduler start running.\n"); 122 | dyco_schedule_run(); 123 | printf("[-] scheduler stopped.\n"); 124 | 125 | return 0; 126 | } -------------------------------------------------------------------------------- /example/channel.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | void alice(void *arg) 4 | { 5 | void *udata; 6 | dyco_schedule_getUdata(&udata); 7 | dyco_channel *c = udata; 8 | 9 | printf("[alice] I am coro %d. I'm about read channel\n", dyco_coroutine_coroID()); 10 | 11 | ssize_t ret; 12 | char buf[64]; 13 | printf("[alice] I am coro %d. I want to recv msg1\n", dyco_coroutine_coroID()); 14 | ret = dyco_channel_recv(c, buf, 64, -1); 15 | printf("[alice] I am coro %d. recv {%.*s}, ret = %ld\n", dyco_coroutine_coroID(), (int)ret, buf, ret); 16 | 17 | printf("[alice] I am coro %d. I'm about sleep 2s\n", dyco_coroutine_coroID()); 18 | dyco_coroutine_sleep(2000); 19 | 20 | printf("[alice] I am coro %d. I want to recv msg2\n", dyco_coroutine_coroID()); 21 | ret = dyco_channel_recv(c, buf, 64, -1); 22 | printf("[alice] I am coro %d. recv {%.*s}, ret = %ld\n", dyco_coroutine_coroID(), (int)ret, buf, ret); 23 | 24 | printf("[alice] I am coro %d. I want to recv msg3\n", dyco_coroutine_coroID()); 25 | ret = dyco_channel_recv(c, buf, 64, -1); 26 | printf("[alice] I am coro %d. recv {%.*s}, ret = %ld\n", dyco_coroutine_coroID(), (int)ret, buf, ret); 27 | 28 | char *msg1 = "is any one there?"; 29 | char *msg2 = "xxxxyyyyzzzz"; 30 | printf("[alice] I am coro %d. I want to send msg1\n", dyco_coroutine_coroID()); 31 | ret = dyco_channel_send(c, msg1, strlen(msg1), 3000); 32 | printf("[alice] I am coro %d. send {%s}, ret = %ld\n", dyco_coroutine_coroID(), msg1, ret); 33 | 34 | printf("[alice] I am coro %d. I want to send msg2\n", dyco_coroutine_coroID()); 35 | ret = dyco_channel_send(c, msg2, strlen(msg2), 3000); 36 | printf("[alice] I am coro %d. send {%s}, ret = %ld\n", dyco_coroutine_coroID(), msg2, ret); 37 | 38 | return; 39 | } 40 | 41 | void bob(void *arg) 42 | { 43 | void *udata; 44 | dyco_schedule_getUdata(&udata); 45 | dyco_channel *c = udata; 46 | 47 | printf("[bob] I am coro %d. I'm about sleep 3 s\n", dyco_coroutine_coroID()); 48 | dyco_coroutine_sleep(3000); 49 | printf("[bob] I am coro %d. I wake up. Now I write the channel 3 times\n", dyco_coroutine_coroID()); 50 | 51 | char *msg1 = "hello"; 52 | char *msg2 = "world"; 53 | char *msg3 = "!"; 54 | ssize_t ret; 55 | 56 | printf("[bob] I am coro %d. I want to send msg1\n", dyco_coroutine_coroID()); 57 | ret = dyco_channel_send(c, msg1, strlen(msg1), -1); 58 | printf("[bob] I am coro %d. send {%s}, ret = %ld\n", dyco_coroutine_coroID(), msg1, ret); 59 | 60 | printf("[bob] I am coro %d. I want to send msg2\n", dyco_coroutine_coroID()); 61 | dyco_channel_send(c, msg2, strlen(msg2), -1); 62 | printf("[bob] I am coro %d. send {%s}, ret = %ld\n", dyco_coroutine_coroID(), msg2, ret); 63 | 64 | printf("[bob] I am coro %d. I want to send msg3\n", dyco_coroutine_coroID()); 65 | dyco_channel_send(c, msg3, strlen(msg3), -1); 66 | printf("[bob] I am coro %d. send {%s}, ret = %ld. EXIT...\n", dyco_coroutine_coroID(), msg3, ret); 67 | 68 | return; 69 | } 70 | 71 | 72 | int main() 73 | { 74 | dyco_coroutine_create(alice, NULL); 75 | dyco_coroutine_create(bob, NULL); 76 | 77 | dyco_channel *c = dyco_channel_create(64); 78 | dyco_schedule_setUdata(c); 79 | 80 | printf("[+] scheduler start running.\n"); 81 | dyco_schedule_run(); 82 | printf("[-] scheduler stopped.\n"); 83 | 84 | dyco_channel_destroy(&c); 85 | return 0; 86 | } -------------------------------------------------------------------------------- /example/coropool.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | dyco_coropool *pool1; 3 | dyco_coropool *pool2; 4 | 5 | void corofunc1(void *arg) 6 | { 7 | printf("I am coro %d. Hello\n", dyco_coroutine_coroID()); 8 | dyco_coroutine_sleep(1000); 9 | printf("I am coro %d. Bye.\n", dyco_coroutine_coroID()); 10 | return; 11 | } 12 | 13 | void corofunc2(void *arg) 14 | { 15 | int ret; 16 | printf("I am coro %d. Hello\n", dyco_coroutine_coroID()); 17 | dyco_coroutine_sleep(1000); 18 | 19 | ret = dyco_coropool_obtain(pool2, corofunc1, NULL, 3000); 20 | printf("6: ret = %d\n", ret); 21 | 22 | // will wait a coroutine finishes 23 | ret = dyco_coropool_obtain(pool2, corofunc1, NULL, 3000); 24 | printf("7: ret = %d\n", ret); 25 | 26 | dyco_coroutine_sleep(2000); 27 | dyco_coropool_resize(pool2, 1); 28 | // will timeout and return 0 29 | ret = dyco_coropool_obtain(pool2, corofunc1, NULL, 3000); 30 | printf("8: ret = %d\n", ret); 31 | 32 | printf("I am coro %d. Bye.\n", dyco_coroutine_coroID()); 33 | return; 34 | } 35 | 36 | int main() 37 | { 38 | // independent stack coroutines pool 39 | pool1 = dyco_coropool_create(2, 4000); 40 | 41 | // shared stack coroutines pool 42 | pool2 = dyco_coropool_create(2, 0); 43 | 44 | int ret; 45 | ret = dyco_coropool_obtain(pool1, corofunc1, NULL, 3000); 46 | printf("1: ret = %d\n", ret); 47 | ret = dyco_coropool_obtain(pool1, corofunc1, NULL, 3000); 48 | printf("2: ret = %d\n", ret); 49 | 50 | // will immediately return -1 51 | ret = dyco_coropool_obtain(pool1, corofunc1, NULL, 3000); 52 | printf("3: ret = %d\n", ret); 53 | 54 | dyco_coropool_resize(pool1, 4); 55 | ret = dyco_coropool_obtain(pool1, corofunc1, NULL, 3000); 56 | printf("4: ret = %d\n", ret); 57 | 58 | ret = dyco_coropool_obtain(pool2, corofunc2, NULL, 3000); 59 | printf("5: ret = %d\n", ret); 60 | 61 | printf("[+] scheduler start running.\n"); 62 | dyco_schedule_run(); 63 | printf("[-] scheduler stopped.\n"); 64 | 65 | ret = dyco_coropool_destroy(&pool1); 66 | assert(ret == 0); 67 | ret = dyco_coropool_destroy(&pool2); 68 | assert(ret == 0); 69 | return 0; 70 | } -------------------------------------------------------------------------------- /example/epoll.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int inittimerfd(int start_s, int interval_s) { 8 | int tfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); 9 | struct itimerspec timebuf; 10 | timebuf.it_interval.tv_nsec = 0; 11 | timebuf.it_interval.tv_sec = interval_s; 12 | timebuf.it_value.tv_nsec = 0; 13 | timebuf.it_value.tv_sec = start_s; 14 | timerfd_settime(tfd, 0, &timebuf, NULL); 15 | printf("inittimerfd create fd = %d\n", tfd); 16 | return tfd; 17 | } 18 | 19 | void cofunc0(void *arg) 20 | { 21 | int id = *(int*)arg; 22 | int tfd1 = inittimerfd(2, 1); 23 | int tfd2 = inittimerfd(6, 1); 24 | int tfd3 = inittimerfd(7, 2); 25 | 26 | struct epoll_event events[3]; 27 | struct epoll_event ev; 28 | ev.events = EPOLLIN | EPOLLERR | EPOLLHUP; 29 | 30 | int epollfd = epoll_create(1); 31 | 32 | ev.data.fd = tfd1; 33 | epoll_ctl(epollfd, EPOLL_CTL_ADD, tfd1, &ev); 34 | ev.data.fd = tfd2; 35 | epoll_ctl(epollfd, EPOLL_CTL_ADD, tfd2, &ev); 36 | ev.data.fd = tfd3; 37 | epoll_ctl(epollfd, EPOLL_CTL_ADD, tfd3, &ev); 38 | int x = 0; 39 | while (x < 16) { 40 | int nevents = epoll_wait(epollfd, events, 3, -1); 41 | int ret, i = 0; 42 | uint64_t cnt; 43 | for (i = 0; i < nevents; i++) { 44 | ret = read(events[i].data.fd, &cnt, sizeof(cnt)); 45 | printf("[%ld] cofunc0: fd %d, read counter val %lu\n", time(NULL), events[i].data.fd, cnt); 46 | ++x; 47 | } 48 | } 49 | close(tfd1); 50 | close(tfd2); 51 | close(tfd3); 52 | close(epollfd); 53 | return; 54 | } 55 | 56 | // void cofunc1(void *arg) 57 | // { 58 | // int id = *(int*)arg; 59 | // int tfd1 = inittimerfd(1, 1); 60 | // int tfd2 = inittimerfd(2, 1); 61 | // int tfd3 = inittimerfd(1, 2); 62 | 63 | // struct epoll_event events[3]; 64 | // struct epoll_event ev; 65 | // ev.events = EPOLLIN | EPOLLERR | EPOLLHUP; 66 | 67 | // int epollfd = epoll_create(1); 68 | 69 | // ev.data.fd = tfd1; 70 | // epoll_ctl(epollfd, EPOLL_CTL_ADD, tfd1, &ev); 71 | // ev.data.fd = tfd2; 72 | // epoll_ctl(epollfd, EPOLL_CTL_ADD, tfd2, &ev); 73 | // ev.data.fd = tfd3; 74 | // epoll_ctl(epollfd, EPOLL_CTL_ADD, tfd3, &ev); 75 | // int x = 0; 76 | // while (x < 16) { 77 | // int nevents = epoll_wait(epollfd, events, 3, -1); 78 | // int ret, i = 0; 79 | // uint64_t cnt; 80 | // for (i = 0; i < nevents; i++) { 81 | // ret = read(events[i].data.fd, &cnt, sizeof(cnt)); 82 | // printf("[%ld] cofunc1: fd %d, read counter val %lu\n", time(NULL), events[i].data.fd, cnt); 83 | // ++x; 84 | // } 85 | // } 86 | // close(tfd1); 87 | // close(tfd2); 88 | // close(tfd3); 89 | // close(epollfd); 90 | // return; 91 | // } 92 | 93 | // void cofunc0(void *arg) 94 | // { 95 | // int id = *(int*)arg; 96 | // int tfd1 = inittimerfd(5, 1); 97 | // int tfd2 = inittimerfd(6, 1); 98 | // int tfd3 = inittimerfd(7, 2); 99 | 100 | // struct epoll_event events[3]; 101 | // struct epoll_event ev; 102 | // ev.events = EPOLLIN | EPOLLERR | EPOLLHUP; 103 | 104 | // dyco_epoll_init(); 105 | 106 | // ev.data.fd = tfd1; 107 | // dyco_epoll_add(ev.data.fd, &ev); 108 | // ev.data.fd = tfd2; 109 | // dyco_epoll_add(ev.data.fd, &ev); 110 | // ev.data.fd = tfd3; 111 | // dyco_epoll_add(ev.data.fd, &ev); 112 | // int x = 0; 113 | // while (x < 16) { 114 | // int nevents = dyco_epoll_wait(events, 3, -1); 115 | // int ret, i = 0; 116 | // uint64_t cnt; 117 | // for (i = 0; i < nevents; i++) { 118 | // ret = read(events[i].data.fd, &cnt, sizeof(cnt)); 119 | // printf("[%ld] cofunc0: fd %d, read counter val %lu\n", time(NULL), events[i].data.fd, cnt); 120 | // ++x; 121 | // } 122 | // } 123 | 124 | // // dyco_epoll_destroy(); 125 | // return; 126 | // } 127 | 128 | void cofunc1(void *arg) 129 | { 130 | 131 | int id = *(int*)arg; 132 | int tfd1 = inittimerfd(1, 1); 133 | int tfd2 = inittimerfd(2, 1); 134 | int tfd3 = inittimerfd(1, 2); 135 | 136 | struct epoll_event events[3]; 137 | struct epoll_event ev; 138 | ev.events = EPOLLIN | EPOLLERR | EPOLLHUP; 139 | 140 | dyco_epoll_init(); 141 | 142 | ev.data.fd = tfd1; 143 | dyco_epoll_add(ev.data.fd, &ev); 144 | ev.data.fd = tfd2; 145 | dyco_epoll_add(ev.data.fd, &ev); 146 | ev.data.fd = tfd3; 147 | dyco_epoll_add(ev.data.fd, &ev); 148 | 149 | int x = 0; 150 | while (x < 16) { 151 | int nevents = dyco_epoll_wait(events, 3, -1); 152 | int ret, i = 0; 153 | uint64_t cnt; 154 | for (i = 0; i < nevents; i++) { 155 | ret = read(events[i].data.fd, &cnt, sizeof(cnt)); 156 | printf("[%ld] cofunc1: fd %d, read counter val %lu\n", time(NULL), events[i].data.fd, cnt); 157 | ++x; 158 | } 159 | } 160 | 161 | dyco_epoll_del(tfd1, NULL); 162 | dyco_epoll_del(tfd2, NULL); 163 | dyco_epoll_del(tfd3, NULL); 164 | 165 | dyco_epoll_destroy(); 166 | return; 167 | } 168 | 169 | int main() 170 | { 171 | int id1 = 1, id2 = 2; 172 | dyco_coroutine_create(cofunc0, &id1); 173 | dyco_coroutine_create(cofunc1, &id2); 174 | dyco_schedule_run(); 175 | return 0; 176 | } -------------------------------------------------------------------------------- /example/meson.build: -------------------------------------------------------------------------------- 1 | coropool_example = executable( 2 | 'asymmetric_example', 3 | 'asymmetric.c', 4 | include_directories : header_dir, 5 | c_args : build_args, 6 | link_with : libdyco 7 | ) 8 | 9 | stack_dont_overflow_example = executable( 10 | 'stack_dont_overflow_example', 11 | 'stack_dont_overflow.c', 12 | include_directories : header_dir, 13 | c_args : build_args, 14 | link_with : libdyco 15 | ) 16 | 17 | channel_example = executable( 18 | 'channel_example', 19 | 'channel.c', 20 | include_directories : header_dir, 21 | c_args : build_args, 22 | link_with : libdyco 23 | ) 24 | 25 | coropool_example = executable( 26 | 'coropool_example', 27 | 'coropool.c', 28 | include_directories : header_dir, 29 | c_args : build_args, 30 | link_with : libdyco 31 | ) 32 | 33 | epoll_example = executable( 34 | 'epoll_example', 35 | 'epoll.c', 36 | include_directories : header_dir, 37 | c_args : build_args, 38 | link_with : libdyco 39 | ) 40 | 41 | multithread_example = executable( 42 | 'multithread_example', 43 | 'multithread.c', 44 | include_directories : header_dir, 45 | c_args : build_args, 46 | link_with : libdyco 47 | ) 48 | 49 | pubsub_example = executable( 50 | 'pubsub_example', 51 | 'pubsub.c', 52 | include_directories : header_dir, 53 | c_args : build_args, 54 | link_with : libdyco 55 | ) 56 | 57 | semaphore_example = executable( 58 | 'semaphore_example', 59 | 'semaphore.c', 60 | include_directories : header_dir, 61 | c_args : build_args, 62 | link_with : libdyco 63 | ) 64 | 65 | setstack_example = executable( 66 | 'setstack_example', 67 | 'setstack.c', 68 | include_directories : header_dir, 69 | c_args : build_args, 70 | link_with : libdyco 71 | ) 72 | 73 | signal_example = executable( 74 | 'signal_example', 75 | 'signal.c', 76 | include_directories : header_dir, 77 | c_args : build_args, 78 | link_with : libdyco 79 | ) 80 | 81 | sleep_example = executable( 82 | 'sleep_example', 83 | 'sleep.c', 84 | include_directories : header_dir, 85 | c_args : build_args, 86 | link_with : libdyco 87 | ) 88 | 89 | stop_abort_example = executable( 90 | 'stop_abort_example', 91 | 'stop_abort.c', 92 | include_directories : header_dir, 93 | c_args : build_args, 94 | link_with : libdyco 95 | ) 96 | 97 | waitgroup_example = executable( 98 | 'waitgroup_example', 99 | 'waitgroup.c', 100 | include_directories : header_dir, 101 | c_args : build_args, 102 | link_with : libdyco 103 | ) 104 | 105 | socket_client_example = executable( 106 | 'socket_client_example', 107 | 'socket_client.c', 108 | include_directories : header_dir, 109 | c_args : build_args, 110 | link_with : libdyco 111 | ) 112 | 113 | socket_server_example = executable( 114 | 'socket_server_example', 115 | 'socket_server.c', 116 | include_directories : header_dir, 117 | c_args : build_args, 118 | link_with : libdyco 119 | ) 120 | 121 | 122 | if crypto_dep.found() and ssl_dep.found() 123 | ssl_client_example = executable( 124 | 'ssl_client_example', 125 | 'ssl_client.c', 126 | include_directories : header_dir, 127 | c_args : build_args, 128 | dependencies : [crypto_dep, ssl_dep], 129 | link_with : libdyco 130 | ) 131 | 132 | ssl_server_example = executable( 133 | 'ssl_server_example', 134 | 'ssl_server.c', 135 | include_directories : header_dir, 136 | c_args : build_args, 137 | dependencies : [crypto_dep, ssl_dep], 138 | link_with : libdyco 139 | ) 140 | else 141 | message('libssl not found! ssl example will not be compiled.') 142 | endif 143 | 144 | if hiredis_dep.found() 145 | network_example = executable( 146 | 'network_example', 147 | 'network.c', 148 | include_directories : header_dir, 149 | c_args : build_args, 150 | dependencies : [hiredis_dep], 151 | link_with : libdyco 152 | ) 153 | else 154 | message('libhiredis not found! hiredis example will not be compiled.') 155 | endif -------------------------------------------------------------------------------- /example/multithread.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | #include 3 | #define MAX_CLIENT_NUM_PERTHEAD 1000000 4 | struct thread_arg { 5 | int coreidx; 6 | unsigned short port; 7 | pthread_t tid; 8 | }; 9 | 10 | struct reader_arg { 11 | int fd; 12 | struct thread_arg *targ; 13 | }; 14 | 15 | void server_reader(void *arg) { 16 | struct reader_arg *rarg = arg; 17 | int fd = rarg->fd; 18 | int ret = 0; 19 | 20 | while (1) { 21 | char buf[1024] = {0}; 22 | ret = dyco_recv(fd, buf, 1024, 0); 23 | if (ret > 0) { 24 | if(fd > MAX_CLIENT_NUM_PERTHEAD) 25 | DYCO_ABORT(); 26 | printf("[thread %lu] read from client: %.*s\n", rarg->targ->tid, ret, buf); 27 | 28 | ret = dyco_send(fd, buf, strlen(buf), 0); 29 | if (ret == -1) { 30 | dyco_close(fd); 31 | printf("[thread %lu] server_reader send failed: fd=%d\n", rarg->targ->tid, fd); 32 | break; 33 | } 34 | } else if (ret == 0) { 35 | dyco_close(fd); 36 | printf("[thread %lu] server_reader close: fd=%d\n", rarg->targ->tid, fd); 37 | break; 38 | } 39 | } 40 | dyco_close(fd); 41 | return; 42 | } 43 | 44 | void server(void *arg) 45 | { 46 | struct thread_arg *args = arg; 47 | unsigned short port = args->port; 48 | 49 | int fd = socket(AF_INET, SOCK_STREAM, 0); 50 | assert(fd > 0); 51 | 52 | struct sockaddr_in local, remote; 53 | local.sin_family = AF_INET; 54 | local.sin_port = htons(port); 55 | local.sin_addr.s_addr = INADDR_ANY; 56 | bind(fd, (struct sockaddr*)&local, sizeof(struct sockaddr_in)); 57 | 58 | listen(fd, 100); 59 | printf("[thread %lu] listen port : %d\n", args->tid, port); 60 | 61 | while (1) { 62 | socklen_t len = sizeof(struct sockaddr_in); 63 | int cli_fd = dyco_accept(fd, (struct sockaddr*)&remote, &len); 64 | printf("[thread %lu] new client comming\n", args->tid); 65 | struct reader_arg *rarg = calloc(1, sizeof(struct reader_arg)); 66 | rarg->fd = cli_fd; 67 | rarg->targ = args; 68 | dyco_coroutine_create(server_reader, rarg); 69 | } 70 | dyco_close(fd); 71 | return; 72 | } 73 | 74 | void* tfunc(void *arg) 75 | { 76 | struct thread_arg *args = arg; 77 | cpu_set_t cpuset; 78 | CPU_ZERO(&cpuset); 79 | CPU_SET(args->coreidx, &cpuset); 80 | pthread_setaffinity_np(args->tid, sizeof(cpu_set_t), &cpuset); 81 | 82 | int cid = dyco_coroutine_create(server, args); 83 | char stack[4096]; 84 | dyco_coroutine_setStack(cid, stack, 4096); 85 | 86 | printf("[thread %lu] scheduler start running.\n", args->tid); 87 | dyco_schedule_run(); 88 | printf("[thread %lu] scheduler stopped.\n", args->tid); 89 | return NULL; 90 | } 91 | 92 | int main() 93 | { 94 | int corenum = sysconf(_SC_NPROCESSORS_CONF); 95 | struct thread_arg *args = (struct thread_arg*)malloc(corenum * sizeof(struct thread_arg)); 96 | pthread_t *tid = (pthread_t*)malloc(corenum * sizeof(pthread_t)); 97 | int i; 98 | unsigned short base_port = 5000; 99 | 100 | for (i = 0; i < corenum; i++) { 101 | args[i].coreidx = i; 102 | args[i].port = base_port + i; 103 | pthread_create(&args[i].tid, NULL, tfunc, &args[i]); 104 | } 105 | for (i = 0; i < corenum; i++) { 106 | pthread_join(args[i].tid, NULL); 107 | } 108 | return 0; 109 | } -------------------------------------------------------------------------------- /example/network.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int inittimerfd(time_t start_ns, time_t interval_ns) { 9 | int tfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); 10 | struct itimerspec timebuf; 11 | timebuf.it_interval.tv_nsec = interval_ns; 12 | timebuf.it_interval.tv_sec = 0; 13 | timebuf.it_value.tv_nsec = interval_ns; 14 | timebuf.it_value.tv_sec = 0; 15 | timerfd_settime(tfd, 0, &timebuf, NULL); 16 | printf("inittimerfd create fd = %d\n", tfd); 17 | return tfd; 18 | } 19 | 20 | void timer(void *arg) 21 | { 22 | // int tfd = inittimerfd(0, 10000); // 10ns 23 | int tfd = inittimerfd(0, 200000000); 24 | 25 | struct epoll_event events[3]; 26 | struct epoll_event ev; 27 | ev.events = EPOLLIN | EPOLLERR | EPOLLHUP; 28 | 29 | dyco_epoll_init(); 30 | 31 | ev.data.fd = tfd; 32 | dyco_epoll_add(ev.data.fd, &ev); 33 | 34 | while (1) { 35 | int nevents = dyco_epoll_wait(events, 3, -1); 36 | int ret, i = 0; 37 | uint64_t cnt; 38 | for (i = 0; i < nevents; i++) { 39 | ret = read(events[i].data.fd, &cnt, sizeof(cnt)); 40 | printf("."); 41 | } 42 | } 43 | 44 | dyco_epoll_del(tfd, NULL); 45 | 46 | dyco_epoll_destroy(); 47 | return; 48 | } 49 | 50 | 51 | void dns(void *arg) 52 | { 53 | printf("[dns] I am coro %d.\n", dyco_coroutine_coroID()); 54 | char *dnames[] = {"cnblogs.com", "www.baidu.com", "bilibili.com", 55 | "leetcode.cn", "blog.csdn.net", "www.xuetangx.com"}; 56 | int i = 0; 57 | char *dname; 58 | struct hostent *ret; 59 | while (1) 60 | { 61 | dname = dnames[i]; 62 | ret = gethostbyname(dname); 63 | printf("%s: %d\n", dname, ret->h_length); 64 | i = (i + 1) % 6; 65 | } 66 | 67 | return; 68 | } 69 | 70 | void redis(void *arg) 71 | { 72 | printf("[redis] I am coro %d.\n", dyco_coroutine_coroID()); 73 | 74 | redisReply *reply; 75 | redisContext *c; 76 | c = redisConnect("127.0.0.1", 6379); 77 | reply = redisCommand(c, "PING"); 78 | assert(reply != NULL); 79 | printf("PING: %s\n", reply->str); 80 | freeReplyObject(reply); 81 | 82 | while (1) 83 | { 84 | // set 85 | char *set_ = "set Key Value"; 86 | reply = redisCommand(c, set_); 87 | if (reply != NULL && reply->type == REDIS_REPLY_STATUS) 88 | { 89 | printf("%s\n", reply->str); 90 | } 91 | freeReplyObject(reply); 92 | 93 | // get 94 | char *get_ = "get Key"; 95 | reply = redisCommand(c, get_); 96 | if (reply != NULL && reply->type == REDIS_REPLY_STRING) 97 | { 98 | printf("%s\n", reply->str); 99 | } 100 | freeReplyObject(reply); 101 | 102 | // del 103 | char *del_ = "del Key"; 104 | reply = redisCommand(c, del_); 105 | if (reply != NULL && reply->type == REDIS_REPLY_STRING) 106 | { 107 | printf("%s\n", reply->str); 108 | } 109 | freeReplyObject(reply); 110 | 111 | // dyco_coroutine_sleep(2000); 112 | } 113 | return; 114 | } 115 | 116 | void server_reader(void *arg) { 117 | int fd = *(int *)arg; 118 | int ret = 0; 119 | 120 | while (1) { 121 | 122 | char buf[1024] = {0}; 123 | ret = recv(fd, buf, 1024, 0); 124 | if (ret > 0) { 125 | printf("From Client: %.*s\n", ret, buf); 126 | 127 | ret = send(fd, buf, strlen(buf), 0); 128 | if (ret == -1) { 129 | dyco_close(fd); 130 | printf("server_reader send failed: fd=%d\n",fd); 131 | break; 132 | } 133 | } else if (ret == 0) { 134 | printf("Shutdown\n"); 135 | close(fd); 136 | break; 137 | } 138 | 139 | } 140 | return; 141 | } 142 | 143 | void tcpserver(void *arg) 144 | { 145 | printf("[tcpserver] I am coro %d.\n", dyco_coroutine_coroID()); 146 | 147 | unsigned short port = 9096; 148 | int fd = socket(AF_INET, SOCK_STREAM, 0); 149 | 150 | struct sockaddr_in local, remote; 151 | local.sin_family = AF_INET; 152 | local.sin_port = htons(port); 153 | local.sin_addr.s_addr = INADDR_ANY; 154 | bind(fd, (struct sockaddr*)&local, sizeof(struct sockaddr_in)); 155 | 156 | listen(fd, 20); 157 | printf("listen port : %d\n", port); 158 | 159 | struct timeval tv_begin; 160 | gettimeofday(&tv_begin, NULL); 161 | 162 | while (1) { 163 | socklen_t len = sizeof(struct sockaddr_in); 164 | int cli_fd = accept(fd, (struct sockaddr*)&remote, &len); 165 | printf("new client comming\n"); 166 | dyco_coroutine_create(server_reader, &cli_fd); 167 | } 168 | 169 | return; 170 | } 171 | 172 | int main() 173 | { 174 | dyco_coroutine_create(timer, NULL); 175 | dyco_coroutine_create(dns, NULL); 176 | dyco_coroutine_create(redis, NULL); 177 | dyco_coroutine_create(tcpserver, NULL); 178 | 179 | printf("[+] scheduler start running.\n"); 180 | dyco_schedule_run(); 181 | printf("[-] scheduler stopped.\n"); 182 | return 0; 183 | } -------------------------------------------------------------------------------- /example/pubsub.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | 4 | void subscriber(void *arg) 5 | { 6 | void *udata; 7 | dyco_schedule_getUdata(&udata); 8 | dyco_pubsubchannel *psc = udata; 9 | 10 | int *times = arg; 11 | 12 | printf("[subscriber] I am coro %d. I'm about subscribe %d messages\n", dyco_coroutine_coroID(), *times); 13 | 14 | int ret, i; 15 | char buf[64]; 16 | for (i = 0; i < *times; i++) { 17 | ret = dyco_pubsub_subscribe(psc, buf, 64, 3000); 18 | if (ret > 0) { 19 | printf("[subscriber] I am coro %d. I receive {%.*s}\n", dyco_coroutine_coroID(), ret, buf); 20 | } else { 21 | printf("[subscriber] I am coro %d. ret = %d\n", dyco_coroutine_coroID(), ret); 22 | } 23 | } 24 | 25 | return; 26 | } 27 | 28 | void publisher(void *arg) 29 | { 30 | void *udata; 31 | dyco_schedule_getUdata(&udata); 32 | dyco_pubsubchannel *psc = udata; 33 | 34 | printf("[publisher] I am coro %d. I'm about sleep 1 s\n", dyco_coroutine_coroID()); 35 | dyco_coroutine_sleep(1000); 36 | 37 | printf("[publisher] I am coro %d. I'm about wait publish 5 messages\n", dyco_coroutine_coroID()); 38 | 39 | int ret, i, len; 40 | char msg[64]; 41 | for (i = 0; i < 5; i++) { 42 | len = sprintf(msg, "message %d", i); 43 | ret = dyco_pubsub_publish(psc, msg, len); 44 | printf("[publisher] I am coro %d. message %d is sent\n", dyco_coroutine_coroID(), i); 45 | } 46 | printf("[publisher] I am coro %d. I'm about sleep 4 s\n", dyco_coroutine_coroID()); 47 | dyco_coroutine_sleep(4000); 48 | return; 49 | } 50 | int main() 51 | { 52 | int times[3] = {2, 5, 6}; 53 | dyco_coroutine_create(publisher, NULL); 54 | dyco_coroutine_create(subscriber, times); 55 | dyco_coroutine_create(subscriber, times + 1); 56 | dyco_coroutine_create(subscriber, times + 2); 57 | 58 | dyco_pubsubchannel *psc = dyco_pubsub_create(64); 59 | dyco_schedule_setUdata(psc); 60 | 61 | printf("[+] scheduler start running.\n"); 62 | dyco_schedule_run(); 63 | printf("[-] scheduler stopped.\n"); 64 | 65 | dyco_pubsub_destroy(&psc); 66 | return 0; 67 | } -------------------------------------------------------------------------------- /example/semaphore.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | void cofunc(void *arg) 4 | { 5 | void *udata; 6 | dyco_schedule_getUdata(&udata); 7 | dyco_semaphore *sem = udata; 8 | int ret; 9 | 10 | printf("[cofunc] I am coro %d. I'm going to critical section\n", dyco_coroutine_coroID()); 11 | 12 | ret = dyco_semaphore_wait(sem, -1); 13 | assert(ret == 0); 14 | 15 | printf("[cofunc] I am coro %d. I'm in critical section\n", dyco_coroutine_coroID()); 16 | dyco_coroutine_sleep(1000); 17 | 18 | ret = dyco_semaphore_signal(sem); 19 | assert(ret == 0); 20 | printf("[cofunc] I am coro %d. I exited critical section\n", dyco_coroutine_coroID()); 21 | 22 | return; 23 | } 24 | 25 | 26 | 27 | int main() 28 | { 29 | int i; 30 | for (i = 0; i < 10; i++) { 31 | dyco_coroutine_create(cofunc, NULL); 32 | } 33 | 34 | dyco_semaphore *sem = dyco_semaphore_create(3); 35 | dyco_schedule_setUdata(sem); 36 | 37 | printf("[+] scheduler start running.\n"); 38 | dyco_schedule_run(); 39 | printf("[-] scheduler stopped.\n"); 40 | 41 | dyco_semaphore_destroy(&sem); 42 | return 0; 43 | } -------------------------------------------------------------------------------- /example/setstack.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | void corofun(void *arg) 4 | { 5 | int sleeptime = *(int*)arg; 6 | int counter = 0; 7 | int randadder = 0; 8 | int iter = 10; 9 | int i; 10 | for (i = 0; i < iter; i++) { 11 | randadder = rand() % 100; 12 | printf("I am coro %d [ownstack? %d]. I will calculate %d + %d\n", dyco_coroutine_coroID(), dyco_coroutine_getStack(dyco_coroutine_coroID(), NULL, NULL), counter, randadder); 13 | dyco_coroutine_sleep(sleeptime); 14 | counter += randadder; 15 | printf("I am coro %d [ownstack? %d]. My answer is %d\n", dyco_coroutine_coroID(), dyco_coroutine_getStack(dyco_coroutine_coroID(), NULL, NULL), counter); 16 | } 17 | return; 18 | } 19 | 20 | int main() 21 | { 22 | int i, cid, ret; 23 | int sleeptime = 1000; 24 | char stack[3][4096]; 25 | // char* stack[3]; 26 | // for (i = 0; i < 3; i++) { 27 | // stack[i] = malloc(4096); 28 | // } 29 | 30 | for (i = 0; i < 3; i++) { 31 | dyco_coroutine_create(corofun, &sleeptime); 32 | } 33 | for (i = 0; i < 3; i++) { 34 | cid = dyco_coroutine_create(corofun, &sleeptime); 35 | ret = dyco_coroutine_setStack(cid, stack[i], 4096); 36 | assert(ret == 1); 37 | } 38 | printf("[+] scheduler start running.\n"); 39 | dyco_schedule_run(); 40 | printf("[-] scheduler stopped.\n"); 41 | 42 | // for (i = 0; i < 3; i++) { 43 | // free(stack[i]); 44 | // } 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /example/signal.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | void foobar(void *arg) 4 | { 5 | while (1) { 6 | printf("[foobar] I am coro %d. I'm about sleep %d ms\n", dyco_coroutine_coroID(), 1000); 7 | dyco_coroutine_sleep(1000); 8 | printf("[foobar] I am coro %d. Now I wake up\n", dyco_coroutine_coroID()); 9 | } 10 | return; 11 | } 12 | 13 | void wait_interrupt(void *arg) 14 | { 15 | int ret; 16 | sigset_t sigmask; 17 | struct signalfd_siginfo fdsi; 18 | sigemptyset(&sigmask); 19 | sigaddset(&sigmask, SIGINT); 20 | dyco_signal_init(&sigmask); 21 | 22 | printf("[wait_interrupt] I am coro %d. I'm about waiting for Ctrl+C\n", dyco_coroutine_coroID()); 23 | 24 | ret = dyco_signal_wait(&fdsi, 3000); 25 | if (ret < 0) { 26 | printf("[wait_interrupt] I am coro %d. I haven't detected Ctrl+C. I'll keep waiting...\n", dyco_coroutine_coroID()); 27 | 28 | ret = dyco_signal_wait(&fdsi, -1); 29 | } 30 | assert(fdsi.ssi_signo == SIGINT); 31 | printf("[wait_interrupt] I am coro %d. Now I detected Ctrl+C\n", dyco_coroutine_coroID()); 32 | printf("[wait_interrupt] I am coro %d. Now I'm about sleep 3s. You can't Ctrl+C me.\n", dyco_coroutine_coroID()); 33 | 34 | dyco_coroutine_sleep(3000); 35 | 36 | printf("[wait_interrupt] I am coro %d. Now I wake up. I'm about waiting for Ctrl+C\n", dyco_coroutine_coroID()); 37 | 38 | ret = dyco_signal_wait(&fdsi, -1); 39 | 40 | printf("[wait_interrupt] I am coro %d. Now I detected Ctrl+C\n", dyco_coroutine_coroID()); 41 | 42 | dyco_signal_destroy(); 43 | 44 | printf("[wait_interrupt] I am coro %d. Now I'm about sleep 7s. But you can Ctrl+C me.\n", dyco_coroutine_coroID()); 45 | 46 | dyco_coroutine_sleep(7000); 47 | 48 | printf("[wait_interrupt] I am coro %d. Bye Bye.\n", dyco_coroutine_coroID()); 49 | return; 50 | } 51 | 52 | void wait_child(void *arg) 53 | { 54 | pid_t pid; 55 | int ret; 56 | int status; 57 | 58 | printf("[wait_child] I am coro %d. I'm about fork myself\n", dyco_coroutine_coroID()); 59 | 60 | if ((pid = fork()) == 0) { 61 | printf("[wait_child] I am coro %d's child. I'm about sleep 1000 ms\n", dyco_coroutine_coroID()); 62 | dyco_coroutine_sleep(1000); 63 | printf("[wait_child] I am coro %d's child. I wake up\n", dyco_coroutine_coroID()); 64 | exit(2); 65 | } 66 | else if (pid > 0) { 67 | printf("[wait_child] I am coro %d. I'm about wait my child...\n", dyco_coroutine_coroID()); 68 | dyco_signal_waitchild(pid, &status, -1); 69 | assert(WIFEXITED(status)); 70 | } 71 | else { 72 | perror("Fork()"); 73 | exit(1); 74 | } 75 | 76 | printf("[wait_child] I am coro %d. I wait my child, status is %d\n", dyco_coroutine_coroID(), status); 77 | return; 78 | } 79 | 80 | int main() 81 | { 82 | int sleeptime[10]; 83 | // dyco_coroutine_create(foobar, NULL); 84 | dyco_coroutine_create(wait_interrupt, NULL); 85 | // dyco_coroutine_create(wait_child, NULL); 86 | 87 | printf("[+] scheduler start running.\n"); 88 | dyco_schedule_run(); 89 | printf("[-] scheduler stopped.\n"); 90 | return 0; 91 | } -------------------------------------------------------------------------------- /example/sleep.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | void corofun(void *arg) 4 | { 5 | int sleeptime = *(int*)arg; 6 | printf("I am coro %d. I'm about sleep %d ms\n", dyco_coroutine_coroID(), sleeptime); 7 | dyco_coroutine_sleep(sleeptime); 8 | printf("I am coro %d. Now I wake up\n", dyco_coroutine_coroID()); 9 | return; 10 | } 11 | 12 | int main() 13 | { 14 | int i; 15 | int sleeptime[10]; 16 | for (i = 0; i < 10; i++) { 17 | sleeptime[i] = 1000 * i; 18 | dyco_coroutine_create(corofun, sleeptime + i); 19 | } 20 | printf("[+] scheduler start running.\n"); 21 | dyco_schedule_run(); 22 | printf("[-] scheduler stopped.\n"); 23 | return 0; 24 | } -------------------------------------------------------------------------------- /example/socket_client.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | #include 3 | 4 | char* ip; 5 | unsigned short port; 6 | 7 | int init_client(void) 8 | { 9 | int clientfd = dyco_socket(AF_INET, SOCK_STREAM, 0); 10 | if (clientfd <= 0) { 11 | printf("socket failed\n"); 12 | return -1; 13 | } 14 | 15 | struct sockaddr_in serveraddr = {0}; 16 | serveraddr.sin_family = AF_INET; 17 | serveraddr.sin_port = htons(port); 18 | serveraddr.sin_addr.s_addr = inet_addr(ip); 19 | 20 | int result = dyco_connect(clientfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)); 21 | if (result != 0) { 22 | printf("connect failed\n"); 23 | return -2; 24 | } 25 | 26 | return clientfd; 27 | } 28 | 29 | void client(void *arg) 30 | { 31 | int clientfd = init_client(); 32 | char *msg = "Hello. I'm TCP Client."; 33 | int length; 34 | char buf[2048]; 35 | 36 | while (1) { 37 | 38 | length = dyco_send(clientfd, msg, strlen(msg), 0); 39 | printf("echo send length : %d\n", length); 40 | if (length <= 0) { 41 | perror("dyco_send() wrong!\n"); 42 | DYCO_ABORT(); 43 | } 44 | length = dyco_recv(clientfd, buf, 2048, 0); 45 | printf("echo recv length : %d\n", length); 46 | if (length <= 0) { 47 | perror("dyco_recv() wrong!\n"); 48 | DYCO_ABORT(); 49 | } 50 | dyco_coroutine_sleep(1000); 51 | } 52 | dyco_close(clientfd); 53 | } 54 | 55 | 56 | int main(int argc, char *argv[]) 57 | { 58 | if (argc != 3) { 59 | printf("usage: ./socket_client [ip] [port]\n"); 60 | return 1; 61 | } 62 | ip = argv[1]; 63 | port = atoi(argv[2]); 64 | dyco_coroutine_create(client, NULL); 65 | 66 | printf("[+] scheduler start running.\n"); 67 | dyco_schedule_run(); 68 | printf("[-] scheduler stopped.\n"); 69 | 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /example/socket_server.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | #include 4 | #include 5 | 6 | #define MAX_CLIENT_NUM 1000000 7 | 8 | void server_reader(void *arg) { 9 | int fd = *(int *)arg; 10 | free(arg); 11 | int ret = 0; 12 | 13 | printf("server_reader start\n"); 14 | while (1) { 15 | char buf[1024] = {0}; 16 | ret = dyco_recv(fd, buf, 1024, 0); 17 | if (ret > 0) { 18 | if(fd > MAX_CLIENT_NUM) 19 | DYCO_ABORT(); 20 | printf("read from client: %.*s\n", ret, buf); 21 | 22 | ret = dyco_send(fd, buf, ret, 0); 23 | if (ret == -1) { 24 | dyco_close(fd); 25 | printf("server_reader send failed: fd=%d\n",fd); 26 | break; 27 | } 28 | } else if (ret == 0) { 29 | dyco_close(fd); 30 | printf("server_reader close: fd=%d\n",fd); 31 | break; 32 | } 33 | } 34 | dyco_close(fd); 35 | return; 36 | } 37 | 38 | void server(void *arg) { 39 | 40 | unsigned short port = *(unsigned short *)arg; 41 | free(arg); 42 | 43 | int fd = dyco_socket(AF_INET, SOCK_STREAM, 0); 44 | assert(fd > 0); 45 | 46 | struct sockaddr_in local, remote; 47 | local.sin_family = AF_INET; 48 | local.sin_port = htons(port); 49 | local.sin_addr.s_addr = INADDR_ANY; 50 | bind(fd, (struct sockaddr*)&local, sizeof(struct sockaddr_in)); 51 | 52 | listen(fd, 20); 53 | printf("listen port : %d\n", port); 54 | 55 | while (1) { 56 | socklen_t len = sizeof(struct sockaddr_in); 57 | int cli_fd = dyco_accept(fd, (struct sockaddr*)&remote, &len); 58 | printf("new client comming\n"); 59 | int *client = malloc(sizeof(int)); 60 | *client = cli_fd; 61 | dyco_coroutine_create(server_reader, client); 62 | } 63 | dyco_close(fd); 64 | return; 65 | } 66 | 67 | int main() 68 | { 69 | int i = 0; 70 | unsigned short base_port = 5000; 71 | for (i = 0;i < 1;i ++) { 72 | unsigned short *port = calloc(1, sizeof(unsigned short)); 73 | *port = base_port + i; 74 | dyco_coroutine_create(server, port); 75 | } 76 | 77 | printf("[+] scheduler start running.\n"); 78 | dyco_schedule_run(); 79 | printf("[-] scheduler stopped.\n"); 80 | 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /example/ssl_client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "dyco/dyco_coroutine.h" 12 | 13 | // Added the LoadCertificates how in the server-side makes. 14 | void LoadCertificates(SSL_CTX *ctx, char *CertFile, char *KeyFile, char *password) 15 | { 16 | /* set the local certificate from CertFile */ 17 | if (SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0) 18 | { 19 | ERR_print_errors_fp(stderr); 20 | DYCO_ABORT(); 21 | } 22 | 23 | /* set the private key from KeyFile (may be the same as CertFile) */ 24 | SSL_CTX_set_default_passwd_cb_userdata(ctx, password); 25 | if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0) 26 | { 27 | ERR_print_errors_fp(stderr); 28 | DYCO_ABORT(); 29 | } 30 | 31 | /* verify private key */ 32 | if (!SSL_CTX_check_private_key(ctx)) 33 | { 34 | fprintf(stderr, "Private key does not match the public certificate\n"); 35 | DYCO_ABORT(); 36 | } 37 | } 38 | 39 | int OpenConnection(const char *hostname, int port) 40 | { 41 | int fd; 42 | struct hostent *host; 43 | struct sockaddr_in addr; 44 | 45 | fd = socket(PF_INET, SOCK_STREAM, 0); 46 | bzero(&addr, sizeof(addr)); 47 | addr.sin_family = AF_INET; 48 | addr.sin_port = htons(port); 49 | addr.sin_addr.s_addr = inet_addr(hostname); 50 | if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) 51 | { 52 | close(fd); 53 | perror(hostname); 54 | DYCO_ABORT(); 55 | } 56 | return fd; 57 | } 58 | 59 | SSL_CTX *InitCTX(void) 60 | { 61 | const SSL_METHOD *method; 62 | SSL_CTX *ctx; 63 | 64 | SSL_library_init(); 65 | OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */ 66 | SSL_load_error_strings(); /* Bring in and register error messages */ 67 | 68 | method = SSLv23_client_method(); 69 | ctx = SSL_CTX_new(method); /* Create new context */ 70 | if (ctx == NULL) 71 | { 72 | ERR_print_errors_fp(stderr); 73 | DYCO_ABORT(); 74 | } 75 | return ctx; 76 | } 77 | 78 | void ShowCerts(SSL *ssl) 79 | { 80 | X509 *cert; 81 | char *line; 82 | 83 | cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */ 84 | if (cert != NULL) 85 | { 86 | printf("Server certificates:\n"); 87 | line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); 88 | printf("Subject: %s\n", line); 89 | free(line); /* free the malloc'ed string */ 90 | line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); 91 | printf("Issuer: %s\n", line); 92 | free(line); /* free the malloc'ed string */ 93 | X509_free(cert); /* free the malloc'ed certificate copy */ 94 | } 95 | else 96 | printf("No certificates.\n"); 97 | } 98 | 99 | // void sslclient(void *arg) 100 | // { 101 | // SSL_CTX *ctx; 102 | // SSL *ssl; 103 | // int serverfd; 104 | // int len, ret, err; 105 | // char buf[1024]; 106 | // char *msg = "Hello. I'm SSL Client."; 107 | 108 | // char CertFile[] = "key/certificate.crt"; 109 | // char KeyFile[] = "key/private_key.pem"; 110 | 111 | // ctx = InitCTX(); 112 | // LoadCertificates(ctx, CertFile, KeyFile, "12345678"); 113 | // serverfd = OpenConnection("127.0.0.1", 5000); 114 | 115 | // ssl = SSL_new(ctx); 116 | // SSL_set_fd(ssl, serverfd); 117 | 118 | // while(1) 119 | // { 120 | // ret = SSL_connect(ssl); 121 | // if(ret == -1) 122 | // { 123 | // err = SSL_get_error(ssl, ret); 124 | // if ((err == SSL_ERROR_WANT_WRITE) || (err == SSL_ERROR_WANT_READ)) 125 | // { 126 | // continue; 127 | // } 128 | // else 129 | // { 130 | // SSL_free(ssl); 131 | // ssl = NULL; 132 | // close(serverfd); 133 | // return; 134 | // } 135 | // } 136 | // else 137 | // { 138 | // printf("SSL_connect success\n"); 139 | // break; 140 | // } 141 | // } 142 | 143 | 144 | 145 | // printf("Connected with %s encryption\n", SSL_get_cipher(ssl)); 146 | // // ShowCerts(ssl); 147 | // while (1) { 148 | // // write message 149 | // while (1) { 150 | // ret = SSL_write(ssl, msg, strlen(msg)); 151 | // err = SSL_get_error(ssl, ret); 152 | // if(err == SSL_ERROR_NONE) 153 | // { 154 | // len = ret; 155 | // break; 156 | // } 157 | // else if (err == SSL_ERROR_WANT_WRITE) 158 | // { 159 | // continue; 160 | // } 161 | // else 162 | // { 163 | // printf("SSL_write failed\n"); 164 | // SSL_shutdown(ssl); 165 | // close(SSL_get_fd(ssl)); 166 | // SSL_free(ssl); 167 | // ssl = NULL; 168 | // SSL_CTX_free(ctx); 169 | // return; 170 | // } 171 | // } 172 | 173 | // if (ret == 0) { 174 | // printf("SSL closed\n"); 175 | // SSL_shutdown(ssl); 176 | // close(SSL_get_fd(ssl)); 177 | // SSL_free(ssl); 178 | // ssl = NULL; 179 | // SSL_CTX_free(ctx); 180 | // return; 181 | // } 182 | 183 | // while (1) 184 | // { 185 | // ret = SSL_read(ssl, buf, 1024); 186 | // err = SSL_get_error(ssl, ret); 187 | // if(err == SSL_ERROR_NONE) 188 | // { 189 | // len = ret; 190 | // break; 191 | // } 192 | // else if (err == SSL_ERROR_WANT_READ) 193 | // { 194 | // continue; 195 | // } 196 | // else 197 | // { 198 | // printf("SSL_read failed\n"); 199 | // SSL_shutdown(ssl); 200 | // close(SSL_get_fd(ssl)); 201 | // SSL_free(ssl); 202 | // ssl = NULL; 203 | // SSL_CTX_free(ctx); 204 | // return; 205 | // } 206 | // } 207 | 208 | // printf("Receive from server: %.*s\n", len, buf); 209 | // dyco_coroutine_sleep(1000); 210 | // } 211 | 212 | // SSL_shutdown(ssl); 213 | // close(SSL_get_fd(ssl)); 214 | // SSL_free(ssl); 215 | // ssl = NULL; 216 | // SSL_CTX_free(ctx); 217 | // return; 218 | // } 219 | 220 | void sslclient(void *arg) 221 | { 222 | SSL_CTX *ctx; 223 | SSL *ssl; 224 | int serverfd; 225 | int len, ret, err; 226 | char buf[1024]; 227 | char *msg = "Hello. I'm SSL Client."; 228 | 229 | char CertFile[] = "cert/certificate.crt"; 230 | char KeyFile[] = "cert/private_key.pem"; 231 | 232 | ctx = InitCTX(); 233 | LoadCertificates(ctx, CertFile, KeyFile, "12345678"); 234 | serverfd = OpenConnection("127.0.0.1", 5000); 235 | 236 | ssl = SSL_new(ctx); 237 | SSL_set_fd(ssl, serverfd); 238 | 239 | ret = dyco_SSL_connect(ssl); 240 | printf("ret = %d\n", ret); 241 | if (ret != 1) { 242 | close(serverfd); 243 | SSL_free(ssl); 244 | SSL_CTX_free(ctx); 245 | return; 246 | } 247 | 248 | printf("Connected with %s encryption\n", SSL_get_cipher(ssl)); 249 | // ShowCerts(ssl); 250 | while (1) { 251 | // write message 252 | if ((len = dyco_SSL_write(ssl, msg, strlen(msg))) <= 0) { 253 | SSL_shutdown(ssl); 254 | close(serverfd); 255 | SSL_free(ssl); 256 | SSL_CTX_free(ctx); 257 | return; 258 | } 259 | 260 | // read response 261 | if ((len = dyco_SSL_read(ssl, buf, 1024)) <= 0) { 262 | SSL_shutdown(ssl); 263 | close(serverfd); 264 | SSL_free(ssl); 265 | SSL_CTX_free(ctx); 266 | return; 267 | } 268 | 269 | printf("Receive from client: %.*s\n", len, buf); 270 | dyco_coroutine_sleep(1000); 271 | } 272 | 273 | SSL_shutdown(ssl); 274 | close(SSL_get_fd(ssl)); 275 | SSL_free(ssl); 276 | ssl = NULL; 277 | SSL_CTX_free(ctx); 278 | return; 279 | } 280 | 281 | void foo(void*arg) { 282 | while (1) { 283 | dyco_coroutine_sleep(400); 284 | putchar('.'); 285 | fflush(stdout); 286 | } 287 | return; 288 | } 289 | 290 | int main() 291 | { 292 | dyco_coroutine_create(sslclient, NULL); 293 | dyco_coroutine_create(foo, NULL); 294 | 295 | printf("[+] scheduler start running.\n"); 296 | dyco_schedule_run(); 297 | printf("[-] scheduler stopped.\n"); 298 | 299 | return 0; 300 | } -------------------------------------------------------------------------------- /example/ssl_server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "dyco/dyco_coroutine.h" 14 | 15 | int OpenListener(int port) 16 | { 17 | int sd; 18 | struct sockaddr_in addr; 19 | 20 | sd = socket(PF_INET, SOCK_STREAM, 0); 21 | bzero(&addr, sizeof(addr)); 22 | addr.sin_family = AF_INET; 23 | addr.sin_port = htons(port); 24 | addr.sin_addr.s_addr = INADDR_ANY; 25 | if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0) 26 | { 27 | perror("can't bind port"); 28 | DYCO_ABORT(); 29 | } 30 | if (listen(sd, 10) != 0) 31 | { 32 | perror("Can't configure listening port"); 33 | DYCO_ABORT(); 34 | } 35 | return sd; 36 | } 37 | 38 | SSL_CTX *InitServerCTX(void) 39 | { 40 | const SSL_METHOD *method; 41 | SSL_CTX *ctx; 42 | 43 | SSL_library_init(); 44 | OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */ 45 | SSL_load_error_strings(); /* load all error messages */ 46 | 47 | method = SSLv23_server_method(); 48 | ctx = SSL_CTX_new(method); /* create new context from method */ 49 | if (ctx == NULL) 50 | { 51 | ERR_print_errors_fp(stderr); 52 | DYCO_ABORT(); 53 | } 54 | return ctx; 55 | } 56 | 57 | void LoadCertificates(SSL_CTX *ctx, char *CertFile, char *KeyFile) 58 | { 59 | // New lines 60 | if (SSL_CTX_load_verify_locations(ctx, CertFile, KeyFile) != 1) 61 | ERR_print_errors_fp(stderr); 62 | 63 | if (SSL_CTX_set_default_verify_paths(ctx) != 1) 64 | ERR_print_errors_fp(stderr); 65 | // End new lines 66 | 67 | /* set the local certificate from CertFile */ 68 | if (SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0) 69 | { 70 | ERR_print_errors_fp(stderr); 71 | DYCO_ABORT(); 72 | } 73 | /* set the private key from KeyFile (may be the same as CertFile) */ 74 | SSL_CTX_set_default_passwd_cb_userdata(ctx, "12345678"); 75 | if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0) 76 | { 77 | ERR_print_errors_fp(stderr); 78 | DYCO_ABORT(); 79 | } 80 | /* verify private key */ 81 | if (!SSL_CTX_check_private_key(ctx)) 82 | { 83 | fprintf(stderr, "Private key does not match the public certificate\n"); 84 | DYCO_ABORT(); 85 | } 86 | 87 | // New lines - Force the client-side have a certificate 88 | SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); 89 | SSL_CTX_set_verify_depth(ctx, 4); 90 | // End new lines 91 | } 92 | 93 | void ShowCerts(SSL *ssl) 94 | { 95 | X509 *cert; 96 | char *line; 97 | 98 | cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */ 99 | if (cert != NULL) 100 | { 101 | printf("Server certificates:\n"); 102 | line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); 103 | printf("Subject: %s\n", line); 104 | free(line); 105 | line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); 106 | printf("Issuer: %s\n", line); 107 | free(line); 108 | X509_free(cert); 109 | } 110 | else 111 | printf("No certificates.\n"); 112 | } 113 | 114 | // void sslconnection(void *arg) 115 | // { 116 | // SSL *ssl = arg; 117 | // char buf[1024]; 118 | // int ret, err, len; 119 | // int fd = SSL_get_fd(ssl); 120 | 121 | // SSL_set_accept_state(ssl); 122 | 123 | // while(1) 124 | // { 125 | // ret = dyco_coroutine_waitRW(fd, 1000); 126 | // assert(ret > 0); 127 | // ret = SSL_accept(ssl); 128 | // if(ret != 1) 129 | // { 130 | // err = SSL_get_error(ssl, ret); 131 | // if ((err == SSL_ERROR_WANT_WRITE) || (err == SSL_ERROR_WANT_READ)) 132 | // { 133 | // continue; 134 | // } 135 | // else 136 | // { 137 | // printf("SSL_accept failed\n"); 138 | // SSL_free(ssl); 139 | // ssl = NULL; 140 | // return; 141 | // } 142 | // } 143 | // else 144 | // { 145 | // printf("SSL_accept success\n"); 146 | // break; 147 | // } 148 | // } 149 | 150 | // // ShowCerts(ssl); 151 | // while (1) { 152 | // // read 153 | // while (1) 154 | // { 155 | // ret = dyco_coroutine_waitRead(fd, -1); 156 | // assert(ret > 0); 157 | // ret = SSL_read(ssl, buf, 1024); 158 | // err = SSL_get_error(ssl, ret); 159 | // if(err == SSL_ERROR_NONE) 160 | // { 161 | // len = ret; 162 | // break; 163 | // } 164 | // else if (err == SSL_ERROR_WANT_READ) 165 | // { 166 | // continue; 167 | // } 168 | // else 169 | // { 170 | // printf("SSL_read failed\n"); 171 | // SSL_shutdown(ssl); 172 | // close(SSL_get_fd(ssl)); 173 | // SSL_free(ssl); 174 | // ssl = NULL; 175 | // return; 176 | // } 177 | // } 178 | 179 | // if (ret == 0) { 180 | // printf("SSL closed\n"); 181 | // SSL_shutdown(ssl); 182 | // close(SSL_get_fd(ssl)); 183 | // SSL_free(ssl); 184 | // ssl = NULL; 185 | // return; 186 | // } 187 | 188 | // printf("Receive from client: %.*s\n", len, buf); 189 | 190 | 191 | // // echo write 192 | // while (1) 193 | // { 194 | // ret = dyco_coroutine_waitWrite(fd, 1000); 195 | // assert(ret > 0); 196 | // ret = SSL_write(ssl, buf, len); 197 | // int nRes = SSL_get_error(ssl, ret); 198 | // if(nRes == SSL_ERROR_NONE) 199 | // { 200 | // len = ret; 201 | // break; 202 | // } 203 | // else if (nRes == SSL_ERROR_WANT_WRITE) 204 | // { 205 | // continue; 206 | // } 207 | // else 208 | // { 209 | // printf("SSL_write failed\n"); 210 | // SSL_shutdown(ssl); 211 | // close(SSL_get_fd(ssl)); 212 | // SSL_free(ssl); 213 | // ssl = NULL; 214 | // return; 215 | // } 216 | // } 217 | // // next read loop 218 | // } 219 | 220 | // SSL_shutdown(ssl); 221 | // close(SSL_get_fd(ssl)); 222 | // SSL_free(ssl); 223 | // ssl = NULL; 224 | // return; 225 | // } 226 | 227 | void sslconnection(void *arg) 228 | { 229 | SSL *ssl = arg; 230 | char buf[1024]; 231 | int ret, err, len; 232 | int fd = SSL_get_fd(ssl); 233 | 234 | if (dyco_SSL_accept(ssl) != 1) { 235 | close(fd); 236 | SSL_free(ssl); 237 | return; 238 | } 239 | 240 | // ShowCerts(ssl); 241 | while (1) { 242 | // read 243 | if ((len = dyco_SSL_read(ssl, buf, 1024)) <= 0) { 244 | SSL_shutdown(ssl); 245 | close(fd); 246 | SSL_free(ssl); 247 | return; 248 | } 249 | 250 | printf("Receive from client: %.*s\n", len, buf); 251 | 252 | // echo write 253 | if ((len = dyco_SSL_write(ssl, buf, 1024)) <= 0) { 254 | SSL_shutdown(ssl); 255 | close(fd); 256 | SSL_free(ssl); 257 | return; 258 | } 259 | // next read loop 260 | } 261 | 262 | SSL_shutdown(ssl); 263 | close(SSL_get_fd(ssl)); 264 | SSL_free(ssl); 265 | ssl = NULL; 266 | return; 267 | } 268 | 269 | void sslserver(void *arg) 270 | { 271 | SSL_CTX *ctx; 272 | int listenfd; 273 | 274 | char CertFile[] = "cert/certificate.crt"; 275 | char KeyFile[] = "cert/private_key.pem"; 276 | 277 | ctx = InitServerCTX(); 278 | LoadCertificates(ctx, CertFile, KeyFile); 279 | listenfd = OpenListener(5000); 280 | while (1) 281 | { 282 | struct sockaddr_in addr; 283 | socklen_t len = sizeof(addr); 284 | SSL *ssl; 285 | 286 | int client = accept(listenfd, (struct sockaddr *)&addr, &len); 287 | printf("Connection: %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); 288 | ssl = SSL_new(ctx); 289 | SSL_set_fd(ssl, client); 290 | dyco_coroutine_create(sslconnection, ssl); 291 | } 292 | close(listenfd); 293 | SSL_CTX_free(ctx); 294 | } 295 | 296 | void foo(void*arg) { 297 | while (1) { 298 | dyco_coroutine_sleep(400); 299 | putchar('.'); 300 | fflush(stdout); 301 | } 302 | return; 303 | } 304 | 305 | int main() 306 | { 307 | dyco_coroutine_create(sslserver, NULL); 308 | dyco_coroutine_create(foo, NULL); 309 | 310 | printf("[+] scheduler start running.\n"); 311 | dyco_schedule_run(); 312 | printf("[-] scheduler stopped.\n"); 313 | 314 | return 0; 315 | } 316 | -------------------------------------------------------------------------------- /example/stack_dont_overflow.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | static int slptime; 4 | 5 | void otherfunc(void *arg) 6 | { 7 | while (1) { 8 | printf("I am coro %d. I'm about sleep %d ms\n", dyco_coroutine_coroID(), 1000); 9 | dyco_coroutine_sleep(1000); 10 | printf("I am coro %d. Now I wake up\n", dyco_coroutine_coroID()); 11 | } 12 | return; 13 | } 14 | 15 | int cal(int num) { 16 | if (num == 1 || num == 2) { 17 | return num; 18 | } 19 | char buf[1000] = "foo bar just use memory"; 20 | int n1, n2, ret; 21 | n1 = num - 1; 22 | n2 = num - 2; 23 | int v1, v2; 24 | 25 | // Here we check stack usage: if stack usage is > 7/8, we abort this coroutine! 26 | if (dyco_coroutine_checkStack() != 0) { 27 | printf("almost overflow! Abort...\n"); 28 | dyco_coroutine_abort(); 29 | } 30 | dyco_coroutine_sleep(slptime); 31 | v1 = cal(n1); 32 | v2 = cal(n2); 33 | ret = v1 + v2; 34 | printf("%s:%d\n", buf, ret); 35 | return ret; 36 | } 37 | 38 | void fibo(void *arg) { 39 | // calculate fibonacci (a task that need many stack space) 40 | int num = *(int*)arg; 41 | cal(num); 42 | } 43 | 44 | int main() 45 | { 46 | slptime = 10; 47 | int fn = 100; 48 | dyco_coroutine_create(otherfunc, NULL); 49 | dyco_coroutine_create(fibo, &fn); 50 | printf("[+] scheduler start running.\n"); 51 | dyco_schedule_run(); 52 | printf("[-] scheduler stopped.\n"); 53 | return 0; 54 | } -------------------------------------------------------------------------------- /example/stop_abort.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | void corofun(void *arg) 4 | { 5 | int sleeptime = *(int*)arg; 6 | int counter = 0; 7 | int randadder = 0; 8 | int iter = 10; 9 | int i; 10 | for (i = 0; i < iter; i++) { 11 | randadder = rand() % 100; 12 | printf("I am coro %d. I will calculate %d + %d\n", dyco_coroutine_coroID(), counter, randadder); 13 | dyco_coroutine_sleep(sleeptime); 14 | counter += randadder; 15 | printf("I am coro %d. My answer is %d\n", dyco_coroutine_coroID(), counter); 16 | } 17 | return; 18 | } 19 | 20 | void foobar(void *arg) 21 | { 22 | int actiontime = *(int*)arg; 23 | printf("I am coro %d. I will sleep %d then stop the schedualer\n", dyco_coroutine_coroID(), actiontime); 24 | dyco_coroutine_sleep(actiontime); 25 | dyco_schedcall_stop(); 26 | 27 | printf("I am coro %d. I will sleep %d then abort the schedualer\n", dyco_coroutine_coroID(), actiontime); 28 | dyco_coroutine_sleep(actiontime); 29 | dyco_schedcall_abort(); 30 | 31 | return; 32 | } 33 | 34 | int main() 35 | { 36 | int i, ret; 37 | int sleeptime = 1000; 38 | int actiontime = 3600; 39 | 40 | for (i = 0; i < 4; i++) { 41 | dyco_coroutine_create(corofun, &sleeptime); 42 | } 43 | dyco_coroutine_create(foobar, &actiontime); 44 | printf("[+] scheduler start running.\n"); 45 | ret = dyco_schedule_run(); 46 | printf("[-] scheduler stopped. ret = %d\n", ret); 47 | 48 | sleep(3); 49 | printf("[+] scheduler restart.\n"); 50 | ret = dyco_schedule_run(); 51 | printf("[-] scheduler stopped. ret = %d\n", ret); 52 | 53 | sleep(3); 54 | printf("[+] scheduler restart.\n"); 55 | ret = dyco_schedule_run(); 56 | printf("[-] scheduler stopped. ret = %d\n", ret); 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /example/waitgroup.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | void worker(void *arg) 4 | { 5 | void *udata; 6 | dyco_schedule_getUdata(&udata); 7 | dyco_waitgroup *wg = udata; 8 | 9 | int *t = arg; 10 | 11 | printf("[worker] I am coro %d. I'm about work %d ms\n", dyco_coroutine_coroID(), *t); 12 | dyco_coroutine_sleep(*t); 13 | 14 | printf("[worker] I am coro %d. I'm done\n", dyco_coroutine_coroID()); 15 | dyco_waitgroup_done(wg); 16 | 17 | return; 18 | } 19 | 20 | void watcher1(void *arg) 21 | { 22 | void *udata; 23 | dyco_schedule_getUdata(&udata); 24 | dyco_waitgroup *wg = udata; 25 | 26 | printf("[watcher1] I am coro %d. I'm about wait just 5 workers\n", dyco_coroutine_coroID()); 27 | int ret = dyco_waitgroup_wait(wg, 5, -1); 28 | printf("[watcher1] I am coro %d. I have finish waiting and ret = %d\n", dyco_coroutine_coroID(), ret); 29 | return; 30 | } 31 | 32 | void watcher2(void *arg) 33 | { 34 | void *udata; 35 | dyco_schedule_getUdata(&udata); 36 | dyco_waitgroup *wg = udata; 37 | 38 | printf("[watcher2] I am coro %d. I'm about wait just 5 workers\n", dyco_coroutine_coroID()); 39 | int ret = dyco_waitgroup_wait(wg, 5, -1); 40 | printf("[watcher2] I am coro %d. I have finish waiting and ret = %d\n", dyco_coroutine_coroID(), ret); 41 | return; 42 | } 43 | 44 | void watcher3(void *arg) 45 | { 46 | void *udata; 47 | dyco_schedule_getUdata(&udata); 48 | dyco_waitgroup *wg = udata; 49 | 50 | dyco_coroutine_sleep(6000); 51 | printf("[watcher3] I am coro %d. I'm about wait just 5 workers\n", dyco_coroutine_coroID()); 52 | int ret = dyco_waitgroup_wait(wg, 5, -1); 53 | printf("[watcher3] I am coro %d. I have finish waiting and ret = %d\n", dyco_coroutine_coroID(), ret); 54 | return; 55 | } 56 | 57 | void boss(void *arg) 58 | { 59 | void *udata; 60 | dyco_schedule_getUdata(&udata); 61 | dyco_waitgroup *wg = udata; 62 | 63 | printf("[boss] I am coro %d. I'm about create 8 workers\n", dyco_coroutine_coroID()); 64 | 65 | int i, ret, cid, totol = 8; 66 | int *sleeptime = (int*)malloc(8 * sizeof(int)); 67 | for (i = 0; i < totol; i++) { 68 | sleeptime[i] = (i + 1) * 1000; 69 | cid = dyco_coroutine_create(worker, sleeptime + i); 70 | ret = dyco_waitgroup_add(wg, cid); 71 | assert(ret == 1); 72 | } 73 | 74 | printf("[boss] I am coro %d. I'm about wait all workers\n", dyco_coroutine_coroID()); 75 | ret = dyco_waitgroup_wait(wg, -1, -1); 76 | printf("[boss] I am coro %d. I have finish waiting and ret = %d\n", dyco_coroutine_coroID(), ret); 77 | 78 | // printf("[boss] I am coro %d. I'm about wait all workers\n", dyco_coroutine_coroID()); 79 | // int ret = dyco_waitgroup_wait(wg, -1, 6000); 80 | // printf("[boss] I am coro %d. I have finish waiting and ret = %d\n", dyco_coroutine_coroID(), ret); 81 | 82 | // printf("[boss] I am coro %d. I'm about wait just 6 workers\n", dyco_coroutine_coroID()); 83 | // int ret = dyco_waitgroup_wait(wg, 6, -1); 84 | // printf("[boss] I am coro %d. I have finish waiting and ret = %d\n", dyco_coroutine_coroID(), ret); 85 | return; 86 | } 87 | 88 | int main() 89 | { 90 | int i; 91 | dyco_coroutine_create(boss, NULL); 92 | dyco_coroutine_create(watcher1, NULL); 93 | dyco_coroutine_create(watcher2, NULL); 94 | dyco_coroutine_create(watcher3, NULL); 95 | 96 | dyco_waitgroup *wg = dyco_waitgroup_create(10); 97 | dyco_schedule_setUdata(wg); 98 | 99 | printf("[+] scheduler start running.\n"); 100 | dyco_schedule_run(); 101 | printf("[-] scheduler stopped.\n"); 102 | 103 | dyco_waitgroup_destroy(&wg); 104 | return 0; 105 | } -------------------------------------------------------------------------------- /history.md: -------------------------------------------------------------------------------- 1 | ## 2022-11-13: v2.1.0 released! 2 | 3 | Updates: 4 | 1. 2-level priority scheduling to support urgent coroutine. 5 | 2. Adjusted the behaviors of the scheduler to make it more reasonable. 6 | 3. Recorrect the performance evaluation. 7 | 4. `libdyco` now can be linked with Cpp code. 8 | 5. Improve the documents, and fix some bugs. 9 | 10 | ## 2022-11-10: v2.0.0 released! 11 | 12 | Updates: 13 | 1. Build the testbench and conduct the performance evaluation. 14 | 2. Add some debug macros. 15 | 3. Add some security patches for better rubustness. 16 | 4. Improve the documents. Bring some new plans in future works. 17 | 18 | ## 2022-11-5: v1.2.0 released! 19 | 20 | Updates: 21 | 1. Support Asymmetric Coroutine & Asymmetric Coroutines Pool for manually schedualing. 22 | 2. Adjust scheduler loop policy for better event reaction. 23 | 3. Better multi-platform support. 24 | 3. Support Meson build. 25 | 4. Fix some bugs. 26 | 5. Improve the documents. Bring some new plans in future works. 27 | 28 | ## 2022-10-29: v1.1.0 released! 29 | 30 | Updates: 31 | 1. Support Coroutines Pool for better performance. 32 | 2. Support `poll()` hook. 33 | 3. `libdyco` is build and can be linked easily. 34 | 4. Fix some bugs. 35 | 5. Improve the documents. Bring some new plans in future works. 36 | 37 | ## 2022-10-24: Happy Programers' Day! 38 | Now `libdyco` can be installed, then programers can use it by simply link this lib when compiling. 39 | 40 | ## 2022-10-20: v1.0.0 released! 41 | 42 | Today, the first version of dyco-coroutine has been finished. I hope this framework to be TRULY **practical** and **user-friendly**, rather than just a coroutine demo. This framework was first inspired by the `wangbojing/NtyCo` project. 43 | 44 | With this framework, programers can achieve asynchronous I/O performance by programming in a synchronous manner. And I want this framework to work out-of-the-box: you just create a coroutine to run your functions, and I'll provide all tools that you need (such as scheduler, socket and synchronization), then all the functions run as coroutines do. Besides, I provide detailed examples that covers almost all supported features of dyco. Anyone can get started within 5 minite by reviewing and running this examples. 45 | 46 | Features of dyco-coroutine: 47 | 1. Fully automated coroutine scheduling. 48 | 2. Either shared or separate stacks can be set for coroutines. 49 | 3. Socket/epoll hooks to automatically change the behavior of the socket/epoll API. 50 | 4. Wait signal events. Especially waitchild, which is works well with `fork()+exec()`. 51 | 5. Allow epoll inside each coroutine without blocking the scheduler. 52 | 6. Half duplex channel and Publish-Subcribe channel for coroutine communication. 53 | 7. Semaphore and Waitgroup for coroutine synchronization. 54 | 8. TLS/SSL non-block concurrent server support. 55 | 9. Scheduler and be stopped by any coroutine, and continue running in main process. 56 | 10. Multi-thread supported. 57 | 58 | There are still some future works: 59 | 1. Support different platforms. This part can be referred to `jamwt/libtask`. 60 | 2. Make dyco-coroutine a shared library: **libdyco**. Then programers can use it by simply link this lib when compiling. 61 | 3. Discover more feature requests and bugs by getting more people to use them. 62 | 4. Performance optimization. Using ucontext predestines the framework to not be the best at switching performance. But there is still room for optimization. 63 | -------------------------------------------------------------------------------- /img/arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piaodazhu/dyco-coroutine/a40613b527ae9471057891b76ab8cf77b8fa39d3/img/arch.png -------------------------------------------------------------------------------- /img/dyco.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/piaodazhu/dyco-coroutine/a40613b527ae9471057891b76ab8cf77b8fa39d3/img/dyco.png -------------------------------------------------------------------------------- /include/dyco/dyco_coroutine.h: -------------------------------------------------------------------------------- 1 | #ifndef __COROUTINE_H__ 2 | #define __COROUTINE_H__ 3 | #define DYCO_VERSION "v2.1.1" 4 | 5 | // ------ 1. Included Headers 6 | #define _GNU_SOURCE 7 | #include 8 | 9 | #define NDEBUG 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #ifndef __cplusplus 23 | # include 24 | #else 25 | # include 26 | # define _Atomic(X) std::atomic< X > 27 | #endif 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "dyco/dyco_ucontext.h" 38 | #include "sys_queue.h" 39 | #include "sys_tree.h" 40 | #include "dyco_htable.h" 41 | 42 | #ifdef __cplusplus 43 | extern "C"{ 44 | #endif 45 | 46 | // ------ 2. User Configurations 47 | #define COROUTINE_HOOK 48 | #define DYCO_SSL_ENABLE 49 | // #define DYCO_RANDOM_WAITFD 50 | #define DYCO_MAX_EVENTS 1024 51 | #define DYCO_MAX_STACKSIZE (64 * 1024) 52 | #define DYCO_DEFAULT_STACKSIZE (16 * 1024) 53 | #define DYCO_DEFAULT_TIMEOUT 10000000 54 | #define DYCO_DEFAULT_CHANNELSIZE 256 55 | #define DYCO_URGENT_MAXEXEC 128 56 | #define DYCO_URGENT_MAXWAIT 128 57 | 58 | // ------ 3. Data Structure Defination 59 | // 3.0 sublist 60 | typedef struct notifylist dyco_sublist; 61 | struct notifylist { 62 | int notifyfd; 63 | dyco_sublist *next; 64 | }; 65 | 66 | // 3.1 scheduler 67 | typedef struct dyco_coroutine dyco_coroutine; 68 | typedef struct dyco_coroutine_queue dyco_coroutine_queue; 69 | typedef struct dyco_coroutine_rbtree_sleep dyco_coroutine_rbtree_sleep; 70 | typedef struct dyco_coropool_list dyco_coropool_list; 71 | TAILQ_HEAD(dyco_coroutine_queue, dyco_coroutine); 72 | RB_HEAD(dyco_coroutine_rbtree_sleep, dyco_coroutine); 73 | SLIST_HEAD(dyco_coropool_list, dyco_coroutine); 74 | 75 | typedef struct schedcall dyco_schedcall; 76 | typedef enum { 77 | CALLNUM_SIGPROCMASK, 78 | CALLNUM_SCHED_STOP, 79 | CALLNUM_SCHED_ABORT 80 | } dyco_schedcall_num; 81 | 82 | struct schedcall { 83 | dyco_schedcall_num callnum; 84 | int ret; 85 | void *arg; 86 | }; 87 | 88 | typedef struct dyco_schedule dyco_schedule; 89 | typedef enum 90 | { 91 | SCHEDULE_STATUS_READY, 92 | SCHEDULE_STATUS_RUNNING, 93 | SCHEDULE_STATUS_STOPPED, 94 | SCHEDULE_STATUS_ABORTED, 95 | SCHEDULE_STATUS_DONE 96 | } dyco_schedule_status; 97 | 98 | struct dyco_schedule 99 | { 100 | // context 101 | ucontext_t ctx; 102 | 103 | // events 104 | int epollfd; 105 | struct epoll_event eventlist[DYCO_MAX_EVENTS]; 106 | 107 | // stack 108 | void *stack; 109 | size_t stack_size; 110 | 111 | // static info 112 | unsigned int sched_id; 113 | uint64_t loopwait_timeout; 114 | uint64_t birth; 115 | 116 | // dynamic info 117 | unsigned int coro_count; 118 | unsigned int _cid_gen; 119 | dyco_coroutine *curr_thread; 120 | dyco_schedcall schedcall; 121 | dyco_schedule_status status; 122 | 123 | // user customized data 124 | void *udata; 125 | 126 | // coroutine containers 127 | dyco_coroutine_queue urgent_ready; 128 | dyco_coroutine_queue ready; 129 | dyco_coroutine_rbtree_sleep sleeping; 130 | 131 | dyco_htable fd_co_map; 132 | dyco_htable cid_co_map; 133 | }; 134 | 135 | // 3.2 coroutine 136 | typedef struct coroutinepool dyco_coropool; 137 | struct coroutinepool { 138 | int totalsize; 139 | int activenum; 140 | int stacksize; 141 | dyco_sublist *sublist; 142 | dyco_coropool_list freelist; 143 | }; 144 | 145 | typedef void (*proc_coroutine)(void *); 146 | typedef enum 147 | { 148 | COROUTINE_STATUS_NEW, 149 | COROUTINE_STATUS_READY, 150 | COROUTINE_STATUS_EXITED, 151 | COROUTINE_STATUS_RUNNING, 152 | COROUTINE_STATUS_SLEEPING, 153 | COROUTINE_STATUS_SCHEDCALL, 154 | COROUTINE_STATUS_KILLED, 155 | 156 | COROUTINE_FLAGS_URGENT, 157 | COROUTINE_FLAGS_OWNSTACK, 158 | COROUTINE_FLAGS_ALLOCSTACKMEM, 159 | COROUTINE_FLAGS_WAITING, 160 | COROUTINE_FLAGS_EXPIRED, 161 | COROUTINE_FLAGS_IOMULTIPLEXING, 162 | COROUTINE_FLAGS_WAITSIGNAL, 163 | COROUTINE_FLAGS_INCOROPOOL, 164 | COROUTINE_FLAGS_ASYMMETRIC 165 | } dyco_coroutine_status; 166 | 167 | struct dyco_coroutine 168 | { 169 | // function and arg 170 | proc_coroutine func; 171 | void *arg; 172 | 173 | // scheduler and context 174 | dyco_schedule *sched; 175 | ucontext_t ctx; 176 | ucontext_t ret; 177 | 178 | // coroutine stack 179 | void *stack; 180 | size_t stack_size; 181 | 182 | // dynamic info 183 | uint32_t status; 184 | uint32_t sched_count; 185 | uint64_t sleep_usecs; 186 | sigset_t old_sigmask; 187 | 188 | // static info 189 | int cid; 190 | 191 | // coroutine pool 192 | dyco_coropool *cpool; 193 | 194 | // user customized data 195 | void *udata; 196 | 197 | // events 198 | int epollfd; // for IO multiplexing 199 | int sigfd; // for wait signals 200 | 201 | // container node 202 | TAILQ_ENTRY(dyco_coroutine) ready_next; 203 | SLIST_ENTRY(dyco_coroutine) cpool_next; 204 | RB_ENTRY(dyco_coroutine) sleep_node; 205 | }; 206 | 207 | // 3.3 channel 208 | typedef struct half_duplex_channel dyco_channel; 209 | typedef enum { 210 | HDC_STATUS_NOP, 211 | HDC_STATUS_EMPTY, 212 | HDC_STATUS_FULL, 213 | HDC_STATUS_WANTREAD, 214 | HDC_STATUS_WANTWRITE, 215 | HDC_STATUS_WANTCLOSE, 216 | HDC_STATUS_CANCLOSE 217 | } half_duplex_channel_status; 218 | 219 | struct half_duplex_channel { 220 | size_t maxsize; 221 | size_t msglen; 222 | void *msg; 223 | 224 | int r_notifyfd; 225 | int w_notifyfd; 226 | half_duplex_channel_status status; 227 | }; 228 | 229 | // 3.4 pubsub 230 | typedef struct waitgroup dyco_waitgroup; 231 | struct waitgroup { 232 | int tot_size; 233 | int finished; 234 | dyco_htable cid_set; 235 | dyco_htable target_sublist_map; 236 | dyco_sublist *final_sublist; 237 | }; 238 | 239 | // 3.5 waitgroup 240 | typedef struct pubsub_channel dyco_pubsubchannel; 241 | typedef enum { 242 | PSC_STATUS_NOP, 243 | PSC_STATUS_EMPTY, 244 | PSC_STATUS_TRANS, 245 | PSC_STATUS_CLOSE 246 | } dyco_pubsub_channel_status; 247 | 248 | struct pubsub_channel { 249 | size_t maxsize; 250 | size_t msglen; 251 | void *msg; 252 | int pub_notifyfd; 253 | 254 | size_t sub_num; 255 | size_t ack_rem; 256 | dyco_sublist *sublist; 257 | dyco_pubsub_channel_status status; 258 | }; 259 | 260 | // 3.6 semaphore 261 | typedef struct semaphore dyco_semaphore; 262 | typedef struct notifylist dyco_semwait_queue; 263 | typedef struct notifylist dyco_semwait_node; 264 | 265 | struct semaphore { 266 | int semval; 267 | dyco_semwait_queue *wqueue; 268 | dyco_semwait_node *wtail; 269 | }; 270 | 271 | // ------ 4. Utils 272 | #define BIT(x) (1 << (x)) 273 | #define SETBIT(d, x) do {(d) |= BIT(x);} while(0) 274 | #define CLRBIT(d, x) do {(d) &= (~BIT(x));} while(0) 275 | #define TESTBIT(d, x) (((d) & BIT(x)) != 0) 276 | 277 | #define DYCO_ABORT() do { \ 278 | printf("[x] error occurs in %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__); \ 279 | exit(1); \ 280 | } while(0) 281 | #define DYCO_MUST(logic) if (!(logic)) { \ 282 | printf("[?] condition is not met in %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__); \ 283 | exit(1); \ 284 | } 285 | #define DYCO_MUSTNOT(logic) if ((logic)) { \ 286 | printf("[?] condition is not met in %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__); \ 287 | exit(1); \ 288 | } 289 | #define DYCO_WARNIF(logic, msg) if ((logic)) { \ 290 | printf("[!] warning in %s:%s:%d: %s\n", __FILE__, __FUNCTION__, __LINE__, msg); \ 291 | } 292 | 293 | #define DYCO_PRINTSTACK(co) do { \ 294 | char dummy; \ 295 | size_t size = (char*)(co->stack + co->stack_size) - &dummy; \ 296 | printf("[i] stack size is [%lu] in %s:%s:%d\n", size, __FILE__, __FUNCTION__, __LINE__); \ 297 | } while (0) 298 | extern pthread_key_t global_sched_key; 299 | 300 | static inline dyco_schedule *get_sched() 301 | { 302 | return (dyco_schedule*)pthread_getspecific(global_sched_key); 303 | } 304 | 305 | static inline uint64_t diff_usecs(uint64_t t1, uint64_t t2) 306 | { 307 | return t2 - t1; 308 | } 309 | 310 | static inline int tv_ms(struct timeval *tv) 311 | { 312 | return tv->tv_sec * 1000 + tv->tv_usec/1000; 313 | } 314 | 315 | static inline uint64_t usec_now() 316 | { 317 | struct timespec ts; 318 | clock_gettime(CLOCK_MONOTONIC, &ts); 319 | return ts.tv_sec * 1000000 + ts.tv_nsec/1000; 320 | } 321 | 322 | static inline int coroutine_sleep_cmp(dyco_coroutine *co1, dyco_coroutine *co2) 323 | { 324 | if (co1->sleep_usecs < co2->sleep_usecs) 325 | return -1; 326 | if (co1->sleep_usecs == co2->sleep_usecs) 327 | return 0; 328 | else 329 | return 1; 330 | } 331 | 332 | // ------ 5. Inner Primes 333 | // User DO NOT use them. Use User APIs is enough in most case. 334 | // 5.1 coroutine 335 | dyco_coroutine* newcoro(); 336 | void freecoro(dyco_coroutine *co); 337 | void savestk(dyco_coroutine *co); 338 | void loadstk(dyco_coroutine *co); 339 | int checkstk(dyco_coroutine *co); 340 | void coro_abort(void *arg); 341 | int resume(dyco_coroutine *co); 342 | void yield(dyco_coroutine *co); 343 | int waitev(int fd, unsigned int events, int timeout); 344 | 345 | // 5.2 scheduler 346 | void schedule_sched_sleep(dyco_coroutine *co, int msecs); 347 | void schedule_cancel_sleep(dyco_coroutine *co); 348 | void schedule_sched_wait(dyco_coroutine *co, int fd, unsigned int events); 349 | void schedule_sched_waitR(dyco_coroutine *co, int fd); 350 | void schedule_sched_waitW(dyco_coroutine *co, int fd); 351 | void schedule_sched_waitRW(dyco_coroutine *co, int fd); 352 | int schedule_cancel_wait(dyco_coroutine *co, int fd); 353 | int schedule_callexec(dyco_schedule *sched); 354 | void schedule_stop(dyco_schedule *sched); 355 | void schedule_abort(dyco_schedule *sched); 356 | 357 | // ------ 6. User APIs 358 | // 6.1 coroutine & coroutines pool 359 | int dyco_coroutine_create(proc_coroutine func, void *arg); 360 | int dyco_coroutine_create_urgent(proc_coroutine func, void *arg); 361 | void dyco_coroutine_sleep(uint32_t msecs); 362 | void dyco_coroutine_abort(); 363 | int dyco_coroutine_waitRead(int fd, int timeout); 364 | int dyco_coroutine_waitWrite(int fd, int timeout); 365 | int dyco_coroutine_waitRW(int fd, int timeout); 366 | 367 | int dyco_coroutine_coroID(); 368 | int dyco_coroutine_setStack(int cid, void *stackptr, size_t stacksize); 369 | int dyco_coroutine_getStack(int cid, void **stackptr, size_t *stacksize); 370 | int dyco_coroutine_checkStack(); 371 | 372 | int dyco_coroutine_setUdata(int cid, void *udata); 373 | int dyco_coroutine_getUdata(int cid, void **udata); 374 | int dyco_coroutine_getSchedCount(int cid); 375 | int dyco_coroutine_setUrgent(int cid); 376 | int dyco_coroutine_unsetUrgent(int cid); 377 | 378 | dyco_coropool* dyco_coropool_create(int totalsize, size_t stacksize); 379 | dyco_coropool* dyco_coropool_resize(dyco_coropool* cp, int newsize); 380 | int dyco_coropool_destroy(dyco_coropool** cp); 381 | int dyco_coropool_available(dyco_coropool* cp); 382 | int dyco_coropool_obtain(dyco_coropool* cp, proc_coroutine func, void *arg, int timeout); 383 | int dyco_coropool_obtain_urgent(dyco_coropool* cp, proc_coroutine func, void *arg, int timeout); 384 | 385 | // 6.2 scheduler 386 | int dyco_schedule_run(); 387 | int dyco_schedule_create(size_t stack_size, uint64_t loopwait_timeout); 388 | void dyco_schedule_free(dyco_schedule *sched); 389 | 390 | int dyco_schedule_schedID(); 391 | int dyco_schedule_setUdata(void *udata); 392 | int dyco_schedule_getUdata(void **udata); 393 | int dyco_schedule_getCoroCount(); 394 | 395 | // 6.3 scheduler call 396 | int dyco_schedcall_sigprocmask(int how, sigset_t *set, sigset_t *oset); 397 | void dyco_schedcall_stop(); 398 | void dyco_schedcall_abort(); 399 | 400 | // 6.4 poll/epoll 401 | int dyco_epoll_init(); 402 | void dyco_epoll_destroy(); 403 | int dyco_epoll_add(int fd, struct epoll_event *ev); 404 | int dyco_epoll_del(int fd, struct epoll_event *ev); 405 | int dyco_epoll_wait(struct epoll_event *events, int maxevents, int timeout); 406 | // int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout); 407 | // int poll(struct pollfd *fds, nfds_t nfds, int timeout); 408 | 409 | // 6.5 signal 410 | int dyco_signal_waitchild(const pid_t child, int *status, int timeout); 411 | int dyco_signal_init(sigset_t *mask); 412 | void dyco_signal_destroy(); 413 | int dyco_signal_wait(struct signalfd_siginfo *sinfo, int timeout); 414 | 415 | // 6.6 half duplex channel 416 | dyco_channel* dyco_channel_create(size_t size); 417 | void dyco_channel_destroy(dyco_channel **chan); 418 | ssize_t dyco_channel_send(dyco_channel *chan, void *buf, size_t size, int timeout); 419 | ssize_t dyco_channel_recv(dyco_channel *chan, void *buf, size_t maxsize, int timeout); 420 | 421 | // 6.7 publish-subscribe channel 422 | dyco_pubsubchannel* dyco_pubsub_create(size_t size); 423 | void dyco_pubsub_destroy(dyco_pubsubchannel **pschan); 424 | ssize_t dyco_pubsub_publish(dyco_pubsubchannel *pschan, void *buf, size_t size); 425 | ssize_t dyco_pubsub_subscribe(dyco_pubsubchannel *pschan, void *buf, size_t maxsize, int timeout); 426 | 427 | // 6.8 wait group 428 | dyco_waitgroup* dyco_waitgroup_create(int suggest_size); 429 | void dyco_waitgroup_destroy(dyco_waitgroup **group); 430 | int dyco_waitgroup_add(dyco_waitgroup* group, int cid); 431 | int dyco_waitgroup_done(dyco_waitgroup* group); 432 | int dyco_waitgroup_wait(dyco_waitgroup* group, int target, int timeout); 433 | 434 | // 6.9 semaphore 435 | dyco_semaphore* dyco_semaphore_create(size_t value); 436 | void dyco_semaphore_destroy(dyco_semaphore **sem); 437 | int dyco_semaphore_wait(dyco_semaphore *sem, int timeout); 438 | int dyco_semaphore_signal(dyco_semaphore *sem); 439 | 440 | // 6.10 socket 441 | int dyco_socket(int domain, int type, int protocol); 442 | int dyco_close(int fd); 443 | int dyco_accept(int fd, struct sockaddr *addr, socklen_t *len); 444 | int dyco_connect(int fd, struct sockaddr *name, socklen_t namelen); 445 | ssize_t dyco_send(int fd, const void *buf, size_t len, int flags); 446 | ssize_t dyco_recv(int fd, void *buf, size_t len, int flags); 447 | ssize_t dyco_sendto(int fd, const void *buf, size_t len, int flags, 448 | const struct sockaddr *dest_addr, socklen_t addrlen); 449 | ssize_t dyco_recvfrom(int fd, void *buf, size_t len, int flags, 450 | struct sockaddr *src_addr, socklen_t *addrlen); 451 | 452 | // 6.11 ssl 453 | #ifdef DYCO_SSL_OK 454 | #ifdef DYCO_SSL_ENABLE 455 | #include 456 | #include 457 | int dyco_SSL_accept(SSL *ssl); 458 | int dyco_SSL_connect(SSL *ssl); 459 | int dyco_SSL_read(SSL *ssl, void *buf, int num); 460 | int dyco_SSL_write(SSL *ssl, const void *buf, int num); 461 | #endif 462 | #endif 463 | 464 | // 6.12 asymmetric coroutine & asymmetric coroutines pool 465 | int dyco_coroutine_isasymmetric(int cid); 466 | int dyco_asymcoro_create(proc_coroutine func, void *arg); 467 | int dyco_asymcororesume(int cid); 468 | void dyco_asymcoroyield(); 469 | void dyco_asymcoro_free(int cid); 470 | int dyco_asymcoro_coroID(); 471 | int dyco_asymcoro_setStack(int cid, void *stackptr, size_t stacksize); 472 | int dyco_asymcoro_getStack(int cid, void **stackptr, size_t *stacksize); 473 | int dyco_asymcoro_setUdata(int cid, void *udata); 474 | int dyco_asymcoro_getUdata(int cid, void **udata); 475 | 476 | dyco_coropool* dyco_asymcpool_create(int totalsize, size_t stacksize); 477 | dyco_coropool* dyco_asymcpool_resize(dyco_coropool* cp, int newsize); 478 | int dyco_asymcpool_destroy(dyco_coropool** cp); 479 | int dyco_asymcpool_available(dyco_coropool* cp); 480 | int dyco_asymcpool_obtain(dyco_coropool* cp, proc_coroutine func, void *arg, int timeout); 481 | void dyco_asymcpool_return(int cid); 482 | 483 | // ------ 7. Hook Functions 484 | typedef int (*socket_t)(int domain, int type, int protocol); 485 | typedef int (*close_t)(int); 486 | typedef int (*accept_t)(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 487 | typedef int (*connect_t)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 488 | typedef ssize_t (*send_t)(int sockfd, const void *buf, size_t len, int flags); 489 | typedef ssize_t (*recv_t)(int sockfd, void *buf, size_t len, int flags); 490 | typedef ssize_t (*sendto_t)(int sockfd, const void *buf, size_t len, int flags, 491 | const struct sockaddr *dest_addr, socklen_t addrlen); 492 | typedef ssize_t (*recvfrom_t)(int sockfd, void *buf, size_t len, int flags, 493 | struct sockaddr *src_addr, socklen_t *addrlen); 494 | typedef int (*epoll_wait_t)(int epfd, struct epoll_event *events, 495 | int maxevents, int timeout); 496 | typedef int (*poll_t)(struct pollfd *fds, nfds_t nfds, int timeout); 497 | 498 | extern socket_t socket_f; 499 | extern close_t close_f; 500 | extern accept_t accept_f; 501 | extern connect_t connect_f; 502 | extern send_t send_f; 503 | extern sendto_t sendto_f; 504 | extern recv_t recv_f; 505 | extern recvfrom_t recvfrom_f; 506 | extern epoll_wait_t epoll_wait_f; 507 | extern poll_t poll_f; 508 | 509 | // ------ 8. Version 510 | static char* dyco_version() 511 | { 512 | return DYCO_VERSION; 513 | } 514 | 515 | #ifdef __cplusplus 516 | } 517 | #endif 518 | 519 | #endif 520 | -------------------------------------------------------------------------------- /include/dyco/dyco_htable.h: -------------------------------------------------------------------------------- 1 | #ifndef DYCO_HTABLE_H 2 | #define DYCO_HTABLE_H 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C"{ 8 | #endif 9 | 10 | #define DYCO_HTABLE_MAXWITDH 24 11 | #define DYCO_HTABLE_DEFAULTWITDH 16 12 | #define DYCO_HTABLE_MAXALPHA 2 13 | 14 | typedef struct dyco_hentry dyco_hentry; 15 | typedef struct dyco_htable dyco_htable; 16 | 17 | struct dyco_hentry 18 | { 19 | int id; 20 | void *data; 21 | dyco_hentry *next; 22 | }; 23 | 24 | struct dyco_htable 25 | { 26 | int width; 27 | int mask; 28 | int count; 29 | dyco_hentry *table; 30 | }; 31 | 32 | #define HTABLE_EMPTY(ht) ((ht)->count == 0) 33 | #define HTABLE_SIZE(ht) ((ht)->count) 34 | static dyco_htable* htable_create(int width); 35 | static int htable_init(dyco_htable *ht, int width); 36 | static void htable_clear(dyco_htable *ht); 37 | static void htable_clear_with_freecb(dyco_htable *ht, void (*freecb)(void*)); 38 | static int htable_insert(dyco_htable *htable, int id, void *data); 39 | static int htable_delete(dyco_htable *htable, int id, void **data); 40 | static void* htable_find(dyco_htable *htable, int id); 41 | static int htable_contains(dyco_htable *htable, int id); 42 | static int htable_resize(dyco_htable *htable, int width); 43 | static void htable_free(dyco_htable *htable); 44 | 45 | static dyco_htable* 46 | htable_create(int width) 47 | { 48 | dyco_htable *ht = (dyco_htable*)malloc(sizeof(dyco_htable)); 49 | if (ht == NULL) 50 | return NULL; 51 | htable_init(ht, width); 52 | return ht; 53 | } 54 | 55 | static int 56 | htable_init(dyco_htable *ht, int width) 57 | { 58 | if (width <= 0) 59 | ht->width = DYCO_HTABLE_DEFAULTWITDH; 60 | else { 61 | ht->width = width > DYCO_HTABLE_MAXWITDH ? DYCO_HTABLE_MAXWITDH : width; 62 | } 63 | 64 | int sz = (1 << ht->width); 65 | ht->mask = sz - 1; 66 | ht->count = 0; 67 | ht->table = (dyco_hentry*)calloc(sz, sizeof(dyco_hentry)); 68 | if (ht->table == NULL) { 69 | return -1; 70 | } 71 | int i; 72 | for (i = 0; i < sz; i++) { 73 | ht->table[i].id = -1; 74 | ht->table[i].data = NULL; 75 | ht->table[i].next = NULL; 76 | } 77 | return 0; 78 | } 79 | 80 | static void 81 | htable_clear(dyco_htable *ht) 82 | { 83 | if (ht->table == NULL) 84 | return; 85 | 86 | int i; 87 | dyco_hentry *pre, *ptr; 88 | for (i = 0; i <= ht->mask; i++) { 89 | if (ht->table[i].id == -1) { 90 | continue; 91 | } 92 | pre = ht->table[i].next; 93 | while (pre != NULL) { 94 | ptr = pre->next; 95 | free(pre); 96 | pre = ptr; 97 | } 98 | } 99 | free(ht->table); 100 | ht->count = 0; 101 | ht->mask = 0; 102 | ht->width = 0; 103 | return; 104 | } 105 | 106 | static void 107 | htable_clear_with_freecb(dyco_htable *ht, void (*freecb)(void*)) 108 | { 109 | if (ht->table == NULL) 110 | return; 111 | 112 | int i; 113 | dyco_hentry *pre, *ptr; 114 | for (i = 0; i <= ht->mask; i++) { 115 | if (ht->table[i].id == -1) { 116 | continue; 117 | } 118 | freecb(ht->table[i].data); 119 | pre = ht->table[i].next; 120 | while (pre != NULL) { 121 | ptr = pre->next; 122 | freecb(pre->data); 123 | free(pre); 124 | pre = ptr; 125 | } 126 | } 127 | free(ht->table); 128 | ht->count = 0; 129 | ht->mask = 0; 130 | ht->width = 0; 131 | return; 132 | } 133 | 134 | static int 135 | htable_insert(dyco_htable *htable, int id, void *data) 136 | { 137 | int idx = id & htable->mask; 138 | dyco_hentry *bucket = &htable->table[idx]; 139 | if (bucket->id == -1) { 140 | bucket->id = id; 141 | bucket->data = data; 142 | ++htable->count; 143 | if (htable->mask * DYCO_HTABLE_MAXALPHA == htable->count) { 144 | if (htable_resize(htable, htable->width + 1) < 0) { 145 | return -1; 146 | } 147 | } 148 | return 1; 149 | } 150 | dyco_hentry *ptr = bucket; 151 | while (ptr != NULL) { 152 | if (ptr->id == id) { 153 | ptr->data = data; 154 | return 0; 155 | } 156 | ptr = ptr->next; 157 | } 158 | dyco_hentry *newnode = (dyco_hentry*)malloc(sizeof(dyco_hentry)); 159 | if (newnode == NULL) { 160 | return -1; 161 | } 162 | newnode->id = id; 163 | newnode->data = data; 164 | newnode->next = bucket->next; 165 | bucket->next = newnode; 166 | ++htable->count; 167 | if (htable->mask * DYCO_HTABLE_MAXALPHA == htable->count) { 168 | if (htable_resize(htable, htable->width + 1) < 0) { 169 | return -1; 170 | } 171 | } 172 | return 1; 173 | } 174 | 175 | static int 176 | htable_delete(dyco_htable *htable, int id, void **data) 177 | { 178 | int idx = id & htable->mask; 179 | dyco_hentry *bucket = &htable->table[idx]; 180 | if (bucket->id == -1) { 181 | return -1; 182 | } 183 | dyco_hentry *ptr = bucket->next; 184 | if (bucket->id == id) { 185 | if (data != NULL) 186 | *data = bucket->data; 187 | if (ptr != NULL) { 188 | bucket->id = ptr->id; 189 | bucket->data = ptr->data; 190 | bucket->next = ptr->next; 191 | free(ptr); 192 | } else { 193 | bucket->id = -1; 194 | bucket->data = NULL; 195 | } 196 | --htable->count; 197 | return 0; 198 | } 199 | dyco_hentry *pre = bucket; 200 | while (ptr != NULL) { 201 | if (ptr->id == id) { 202 | if (data != NULL) 203 | *data = ptr->data; 204 | pre->next = ptr->next; 205 | free(ptr); 206 | --htable->count; 207 | return 0; 208 | } 209 | pre = ptr; 210 | ptr = ptr->next; 211 | } 212 | return -1; 213 | } 214 | 215 | static int 216 | htable_delete_with_freecb(dyco_htable *htable, int id, void (*freecb)(void*)) 217 | { 218 | int idx = id & htable->mask; 219 | dyco_hentry *bucket = &htable->table[idx]; 220 | if (bucket->id == -1) { 221 | return -1; 222 | } 223 | dyco_hentry *ptr = bucket->next; 224 | if (bucket->id == id) { 225 | if (bucket->data != NULL) 226 | freecb(bucket->data); 227 | if (ptr != NULL) { 228 | bucket->id = ptr->id; 229 | bucket->data = ptr->data; 230 | bucket->next = ptr->next; 231 | free(ptr); 232 | } else { 233 | bucket->id = -1; 234 | bucket->data = NULL; 235 | } 236 | --htable->count; 237 | return 0; 238 | } 239 | dyco_hentry *pre = bucket; 240 | while (ptr != NULL) { 241 | if (ptr->id == id) { 242 | pre->next = ptr->next; 243 | if (ptr->data != NULL) 244 | freecb(ptr->data); 245 | free(ptr); 246 | --htable->count; 247 | return 0; 248 | } 249 | pre = ptr; 250 | ptr = ptr->next; 251 | } 252 | return -1; 253 | } 254 | 255 | static void* 256 | htable_find(dyco_htable *htable, int id) 257 | { 258 | int idx = id & htable->mask; 259 | dyco_hentry *bucket = &htable->table[idx]; 260 | if (bucket->id == -1) 261 | return NULL; 262 | if (bucket->id == id) 263 | return bucket->data; 264 | 265 | dyco_hentry *ptr = bucket->next; 266 | while (ptr != NULL) { 267 | if (ptr->id == id) { 268 | return ptr->data; 269 | } 270 | ptr = ptr->next; 271 | } 272 | return NULL; 273 | } 274 | 275 | static int 276 | htable_contains(dyco_htable *htable, int id) 277 | { 278 | int idx = id & htable->mask; 279 | dyco_hentry *bucket = &htable->table[idx]; 280 | if (bucket->id == -1) 281 | return 0; 282 | if (bucket->id == id) 283 | return 1; 284 | 285 | dyco_hentry *ptr = bucket->next; 286 | while (ptr != NULL) { 287 | if (ptr->id == id) { 288 | return 1; 289 | } 290 | ptr = ptr->next; 291 | } 292 | return 0; 293 | } 294 | 295 | static int 296 | htable_resize(dyco_htable *htable, int width) 297 | { 298 | if ((width == htable->width) || (width > DYCO_HTABLE_MAXWITDH)) 299 | return -1; 300 | int newsize = (1 << width); 301 | int newmask = newsize - 1; 302 | dyco_hentry* newtable = (dyco_hentry*)calloc(newsize, sizeof(dyco_hentry)); 303 | if (newtable == NULL) { 304 | return -1; 305 | } 306 | 307 | int i; 308 | for (i = 0; i < newsize; i++) { 309 | newtable->id = -1; 310 | newtable->data = NULL; 311 | newtable->next = NULL; 312 | } 313 | 314 | int oldmask = htable->mask; 315 | dyco_hentry* oldtable = htable->table; 316 | dyco_hentry *newnode, *next, *ptr; 317 | int newidx; 318 | for (i = 0; i <= oldmask; i++) { 319 | if (oldtable[i].id == -1) { 320 | continue; 321 | } 322 | // first node 323 | newidx = oldtable[i].id & newmask; 324 | if (newtable[newidx].id == -1) { 325 | newtable[newidx].id = oldtable[i].id; 326 | newtable[newidx].data = oldtable[i].data; 327 | } else { 328 | newnode = (dyco_hentry*)malloc(sizeof(dyco_hentry)); 329 | if (newnode == NULL) 330 | return -1; 331 | newnode->id = oldtable[i].id; 332 | newnode->data = oldtable[i].data; 333 | newnode->next = newtable[newidx].next; 334 | newtable[newidx].next = newnode; 335 | } 336 | // other node 337 | ptr = oldtable[i].next; 338 | while (ptr != NULL) { 339 | next = ptr->next; 340 | newidx = ptr->id & newmask; 341 | if (newtable[newidx].id == -1) { 342 | newtable[newidx].id = ptr->id; 343 | newtable[newidx].data = ptr->data; 344 | free(ptr); 345 | } else { 346 | ptr->next = newtable[newidx].next; 347 | newtable[newidx].next = ptr; 348 | } 349 | ptr = next; 350 | } 351 | } 352 | free(oldtable); 353 | htable->mask = newmask; 354 | htable->width = width; 355 | htable->table = newtable; 356 | return 0; 357 | } 358 | 359 | static void 360 | htable_free(dyco_htable *htable) 361 | { 362 | if (htable == NULL) 363 | return; 364 | 365 | htable_clear(htable); 366 | free(htable); 367 | return; 368 | } 369 | 370 | #ifdef __cplusplus 371 | } 372 | #endif 373 | 374 | #endif -------------------------------------------------------------------------------- /include/dyco/dyco_ucontext.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2005-2006 Russ Cox, MIT; see COPYRIGHT */ 2 | 3 | #ifndef DYCO_UCONTEXT_H 4 | #define DYCO_UCONTEXT_H 5 | 6 | #if defined(__sun__) 7 | # define __EXTENSIONS__ 1 /* SunOS */ 8 | # if defined(__SunOS5_6__) || defined(__SunOS5_7__) || defined(__SunOS5_8__) 9 | /* NOT USING #define __MAKECONTEXT_V2_SOURCE 1 / * SunOS */ 10 | # else 11 | # define __MAKECONTEXT_V2_SOURCE 1 12 | # endif 13 | #endif 14 | 15 | #define USE_UCONTEXT 1 16 | 17 | #if defined(__OpenBSD__) || defined(__mips__) 18 | #undef USE_UCONTEXT 19 | #define USE_UCONTEXT 0 20 | #endif 21 | 22 | #if defined(__APPLE__) 23 | #include 24 | #if defined(MAC_OS_X_VERSION_10_5) 25 | #undef USE_UCONTEXT 26 | #define USE_UCONTEXT 0 27 | #endif 28 | #endif 29 | 30 | // is this OK? For all other platform we use ucontext.h? 31 | #if USE_UCONTEXT 32 | #include 33 | #endif 34 | 35 | // Or try this? Only for the platforms that I tested 36 | // #if USE_UCONTEXT 37 | // # if defined(__linux__) && defined(__aarch64__) 38 | // # include 39 | // # endif 40 | // # if defined(__linux__) && defined(__x86_64__) 41 | // # include 42 | // # endif 43 | // #endif 44 | 45 | #if defined(__FreeBSD__) && __FreeBSD__ < 5 46 | extern int getmcontext(mcontext_t*); 47 | extern void setmcontext(const mcontext_t*); 48 | #define setcontext(u) setmcontext(&(u)->uc_mcontext) 49 | #define getcontext(u) getmcontext(&(u)->uc_mcontext) 50 | extern int swapcontext(ucontext_t*, const ucontext_t*); 51 | extern void makecontext(ucontext_t*, void(*)(), int, ...); 52 | #endif 53 | 54 | #if defined(__APPLE__) 55 | # define mcontext libthread_mcontext 56 | # define mcontext_t libthread_mcontext_t 57 | # define ucontext libthread_ucontext 58 | # define ucontext_t libthread_ucontext_t 59 | # if defined(__i386__) 60 | # include "uctx_386.h" 61 | # elif defined(__x86_64__) 62 | # include "uctx_amd64.h" 63 | # else 64 | # include "uctx_power.h" 65 | # endif 66 | #endif 67 | 68 | #if defined(__OpenBSD__) 69 | # define mcontext libthread_mcontext 70 | # define mcontext_t libthread_mcontext_t 71 | # define ucontext libthread_ucontext 72 | # define ucontext_t libthread_ucontext_t 73 | # if defined __i386__ 74 | # include "uctx_386.h" 75 | # else 76 | # include "uctx_power.h" 77 | # endif 78 | extern pid_t rfork_thread(int, void*, int(*)(void*), void*); 79 | #endif 80 | 81 | #if defined(__arm__) 82 | int getmcontext(mcontext_t*); 83 | void setmcontext(const mcontext_t*); 84 | #define setcontext(u) setmcontext(&(u)->uc_mcontext) 85 | #define getcontext(u) getmcontext(&(u)->uc_mcontext) 86 | #endif 87 | 88 | #if defined(__mips__) 89 | #include "uctx_mips.h" 90 | int getmcontext(mcontext_t*); 91 | void setmcontext(const mcontext_t*); 92 | #define setcontext(u) setmcontext(&(u)->uc_mcontext) 93 | #define getcontext(u) getmcontext(&(u)->uc_mcontext) 94 | #endif 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /include/dyco/uctx_386.h: -------------------------------------------------------------------------------- 1 | #ifndef UCTX_386_H 2 | #define UCTX_386_H 3 | 4 | #define setcontext(u) setmcontext(&(u)->uc_mcontext) 5 | #define getcontext(u) getmcontext(&(u)->uc_mcontext) 6 | typedef struct mcontext mcontext_t; 7 | typedef struct ucontext ucontext_t; 8 | 9 | extern int swapcontext(ucontext_t*, const ucontext_t*); 10 | extern void makecontext(ucontext_t*, void(*)(), int, ...); 11 | extern int getmcontext(mcontext_t*); 12 | extern void setmcontext(const mcontext_t*); 13 | 14 | /*- 15 | * Copyright (c) 1999 Marcel Moolenaar 16 | * All rights reserved. 17 | * 18 | * Redistribution and use in source and binary forms, with or without 19 | * modification, are permitted provided that the following conditions 20 | * are met: 21 | * 1. Redistributions of source code must retain the above copyright 22 | * notice, this list of conditions and the following disclaimer 23 | * in this position and unchanged. 24 | * 2. Redistributions in binary form must reproduce the above copyright 25 | * notice, this list of conditions and the following disclaimer in the 26 | * documentation and/or other materials provided with the distribution. 27 | * 3. The name of the author may not be used to endorse or promote products 28 | * derived from this software without specific prior written permission. 29 | * 30 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 31 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 32 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 33 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 34 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 35 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 39 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 | * 41 | * $FreeBSD: src/sys/sys/ucontext.h,v 1.4 1999/10/11 20:33:17 luoqi Exp $ 42 | */ 43 | 44 | /* #include */ 45 | 46 | /*- 47 | * Copyright (c) 1999 Marcel Moolenaar 48 | * All rights reserved. 49 | * 50 | * Redistribution and use in source and binary forms, with or without 51 | * modification, are permitted provided that the following conditions 52 | * are met: 53 | * 1. Redistributions of source code must retain the above copyright 54 | * notice, this list of conditions and the following disclaimer 55 | * in this position and unchanged. 56 | * 2. Redistributions in binary form must reproduce the above copyright 57 | * notice, this list of conditions and the following disclaimer in the 58 | * documentation and/or other materials provided with the distribution. 59 | * 3. The name of the author may not be used to endorse or promote products 60 | * derived from this software without specific prior written permission. 61 | * 62 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 63 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 64 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 65 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 66 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 67 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 68 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 69 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 70 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 71 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 72 | * 73 | * $FreeBSD: src/sys/i386/include/ucontext.h,v 1.4 1999/10/11 20:33:09 luoqi Exp $ 74 | */ 75 | 76 | struct mcontext { 77 | /* 78 | * The first 20 fields must match the definition of 79 | * sigcontext. So that we can support sigcontext 80 | * and ucontext_t at the same time. 81 | */ 82 | int mc_onstack; /* XXX - sigcontext compat. */ 83 | int mc_gs; 84 | int mc_fs; 85 | int mc_es; 86 | int mc_ds; 87 | int mc_edi; 88 | int mc_esi; 89 | int mc_ebp; 90 | int mc_isp; 91 | int mc_ebx; 92 | int mc_edx; 93 | int mc_ecx; 94 | int mc_eax; 95 | int mc_trapno; 96 | int mc_err; 97 | int mc_eip; 98 | int mc_cs; 99 | int mc_eflags; 100 | int mc_esp; /* machine state */ 101 | int mc_ss; 102 | 103 | int mc_fpregs[28]; /* env87 + fpacc87 + u_long */ 104 | int __spare__[17]; 105 | }; 106 | #include 107 | struct ucontext { 108 | /* 109 | * Keep the order of the first two fields. Also, 110 | * keep them the first two fields in the structure. 111 | * This way we can have a union with struct 112 | * sigcontext and ucontext_t. This allows us to 113 | * support them both at the same time. 114 | * note: the union is not defined, though. 115 | */ 116 | sigset_t uc_sigmask; 117 | mcontext_t uc_mcontext; 118 | 119 | struct __ucontext *uc_link; 120 | stack_t uc_stack; 121 | int __spare__[8]; 122 | }; 123 | 124 | #endif 125 | -------------------------------------------------------------------------------- /include/dyco/uctx_amd64.h: -------------------------------------------------------------------------------- 1 | #ifndef UCTX_386_H 2 | #define UCTX_386_H 3 | 4 | #define setcontext(u) setmcontext(&(u)->uc_mcontext) 5 | #define getcontext(u) getmcontext(&(u)->uc_mcontext) 6 | typedef struct mcontext mcontext_t; 7 | typedef struct ucontext ucontext_t; 8 | 9 | extern int swapcontext(ucontext_t*, const ucontext_t*); 10 | extern void makecontext(ucontext_t*, void(*)(), int, ...); 11 | extern int getmcontext(mcontext_t*); 12 | extern void setmcontext(const mcontext_t*); 13 | 14 | /*- 15 | * Copyright (c) 1999 Marcel Moolenaar 16 | * All rights reserved. 17 | * 18 | * Redistribution and use in source and binary forms, with or without 19 | * modification, are permitted provided that the following conditions 20 | * are met: 21 | * 1. Redistributions of source code must retain the above copyright 22 | * notice, this list of conditions and the following disclaimer 23 | * in this position and unchanged. 24 | * 2. Redistributions in binary form must reproduce the above copyright 25 | * notice, this list of conditions and the following disclaimer in the 26 | * documentation and/or other materials provided with the distribution. 27 | * 3. The name of the author may not be used to endorse or promote products 28 | * derived from this software without specific prior written permission. 29 | * 30 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 31 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 32 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 33 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 34 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 35 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 39 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 | * 41 | * $FreeBSD: src/sys/sys/ucontext.h,v 1.4 1999/10/11 20:33:17 luoqi Exp $ 42 | */ 43 | 44 | /* #include */ 45 | 46 | /*- 47 | * Copyright (c) 1999 Marcel Moolenaar 48 | * All rights reserved. 49 | * 50 | * Redistribution and use in source and binary forms, with or without 51 | * modification, are permitted provided that the following conditions 52 | * are met: 53 | * 1. Redistributions of source code must retain the above copyright 54 | * notice, this list of conditions and the following disclaimer 55 | * in this position and unchanged. 56 | * 2. Redistributions in binary form must reproduce the above copyright 57 | * notice, this list of conditions and the following disclaimer in the 58 | * documentation and/or other materials provided with the distribution. 59 | * 3. The name of the author may not be used to endorse or promote products 60 | * derived from this software without specific prior written permission. 61 | * 62 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 63 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 64 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 65 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 66 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 67 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 68 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 69 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 70 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 71 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 72 | * 73 | * $FreeBSD: src/sys/i386/include/ucontext.h,v 1.4 1999/10/11 20:33:09 luoqi Exp $ 74 | */ 75 | 76 | struct mcontext { 77 | /* 78 | * The first 20 fields must match the definition of 79 | * sigcontext. So that we can support sigcontext 80 | * and ucontext_t at the same time. 81 | */ 82 | long mc_onstack; /* XXX - sigcontext compat. */ 83 | long mc_rdi; /* machine state (struct trapframe) */ 84 | long mc_rsi; 85 | long mc_rdx; 86 | long mc_rcx; 87 | long mc_r8; 88 | long mc_r9; 89 | long mc_rax; 90 | long mc_rbx; 91 | long mc_rbp; 92 | long mc_r10; 93 | long mc_r11; 94 | long mc_r12; 95 | long mc_r13; 96 | long mc_r14; 97 | long mc_r15; 98 | long mc_trapno; 99 | long mc_addr; 100 | long mc_flags; 101 | long mc_err; 102 | long mc_rip; 103 | long mc_cs; 104 | long mc_rflags; 105 | long mc_rsp; 106 | long mc_ss; 107 | 108 | long mc_len; /* sizeof(mcontext_t) */ 109 | #define _MC_FPFMT_NODEV 0x10000 /* device not present or configured */ 110 | #define _MC_FPFMT_XMM 0x10002 111 | long mc_fpformat; 112 | #define _MC_FPOWNED_NONE 0x20000 /* FP state not used */ 113 | #define _MC_FPOWNED_FPU 0x20001 /* FP state came from FPU */ 114 | #define _MC_FPOWNED_PCB 0x20002 /* FP state came from PCB */ 115 | long mc_ownedfp; 116 | /* 117 | * See for the internals of mc_fpstate[]. 118 | */ 119 | long mc_fpstate[64]; 120 | long mc_spare[8]; 121 | }; 122 | #include 123 | struct ucontext { 124 | /* 125 | * Keep the order of the first two fields. Also, 126 | * keep them the first two fields in the structure. 127 | * This way we can have a union with struct 128 | * sigcontext and ucontext_t. This allows us to 129 | * support them both at the same time. 130 | * note: the union is not defined, though. 131 | */ 132 | sigset_t uc_sigmask; 133 | mcontext_t uc_mcontext; 134 | 135 | struct __ucontext *uc_link; 136 | stack_t uc_stack; 137 | int __spare__[8]; 138 | }; 139 | 140 | #endif 141 | -------------------------------------------------------------------------------- /include/dyco/uctx_mips.h: -------------------------------------------------------------------------------- 1 | #ifndef UCTX_MIPS_H 2 | #define UCTX_MIPS_H 3 | 4 | typedef struct mcontext mcontext_t; 5 | typedef struct ucontext ucontext_t; 6 | 7 | extern int swapcontext(ucontext_t*, const ucontext_t*); 8 | extern void makecontext(ucontext_t*, void(*)(), int, ...); 9 | 10 | /* 11 | * Copyright (c) 1992, 1993 12 | * The Regents of the University of California. All rights reserved. 13 | * 14 | * This code is derived from software contributed to Berkeley by 15 | * Ralph Campbell. 16 | * 17 | * Redistribution and use in source and binary forms, with or without 18 | * modification, are permitted provided that the following conditions 19 | * are met: 20 | * 1. Redistributions of source code must retain the above copyright 21 | * notice, this list of conditions and the following disclaimer. 22 | * 2. Redistributions in binary form must reproduce the above copyright 23 | * notice, this list of conditions and the following disclaimer in the 24 | * documentation and/or other materials provided with the distribution. 25 | * 4. Neither the name of the University nor the names of its contributors 26 | * may be used to endorse or promote products derived from this software 27 | * without specific prior written permission. 28 | * 29 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 | * SUCH DAMAGE. 40 | * 41 | * @(#)ucontext.h 8.1 (Berkeley) 6/10/93 42 | * JNPR: ucontext.h,v 1.2 2007/08/09 11:23:32 katta 43 | * $FreeBSD: src/sys/mips/include/ucontext.h,v 1.2 2010/01/10 19:50:24 imp Exp $ 44 | */ 45 | 46 | struct mcontext { 47 | /* 48 | * These fields must match the corresponding fields in struct 49 | * sigcontext which follow 'sc_mask'. That way we can support 50 | * struct sigcontext and ucontext_t at the same time. 51 | */ 52 | int mc_onstack; /* sigstack state to restore */ 53 | int mc_pc; /* pc at time of signal */ 54 | int mc_regs[32]; /* processor regs 0 to 31 */ 55 | int sr; /* status register */ 56 | int mullo, mulhi; /* mullo and mulhi registers... */ 57 | int mc_fpused; /* fp has been used */ 58 | int mc_fpregs[33]; /* fp regs 0 to 31 and csr */ 59 | int mc_fpc_eir; /* fp exception instruction reg */ 60 | void *mc_tls; /* pointer to TLS area */ 61 | int __spare__[8]; /* XXX reserved */ 62 | }; 63 | #include 64 | struct ucontext { 65 | /* 66 | * Keep the order of the first two fields. Also, 67 | * keep them the first two fields in the structure. 68 | * This way we can have a union with struct 69 | * sigcontext and ucontext_t. This allows us to 70 | * support them both at the same time. 71 | * note: the union is not defined, though. 72 | */ 73 | sigset_t uc_sigmask; 74 | mcontext_t uc_mcontext; 75 | 76 | struct __ucontext *uc_link; 77 | stack_t uc_stack; 78 | int uc_flags; 79 | int __spare__[4]; 80 | }; 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /include/dyco/uctx_power.h: -------------------------------------------------------------------------------- 1 | #ifndef UCTX_POWER_H 2 | #define UCTX_POWER_H 3 | 4 | #define setcontext(u) _setmcontext(&(u)->mc) 5 | #define getcontext(u) _getmcontext(&(u)->mc) 6 | typedef struct mcontext mcontext_t; 7 | typedef struct ucontext ucontext_t; 8 | 9 | typedef unsigned long ulong; 10 | typedef unsigned int uint; 11 | struct mcontext 12 | { 13 | ulong pc; /* lr */ 14 | ulong cr; /* mfcr */ 15 | ulong ctr; /* mfcr */ 16 | ulong xer; /* mfcr */ 17 | ulong sp; /* callee saved: r1 */ 18 | ulong toc; /* callee saved: r2 */ 19 | ulong r3; /* first arg to function, return register: r3 */ 20 | ulong gpr[19]; /* callee saved: r13-r31 */ 21 | /* 22 | // XXX: currently do not save vector registers or floating-point state 23 | // ulong pad; 24 | // uvlong fpr[18]; / * callee saved: f14-f31 * / 25 | // ulong vr[4*12]; / * callee saved: v20-v31, 256-bits each * / 26 | */ 27 | }; 28 | #include 29 | struct ucontext 30 | { 31 | struct { 32 | void *ss_sp; 33 | uint ss_size; 34 | } uc_stack; 35 | sigset_t uc_sigmask; 36 | mcontext_t mc; 37 | }; 38 | 39 | void makecontext(ucontext_t*, void(*)(void), int, ...); 40 | int swapcontext(ucontext_t*, const ucontext_t*); 41 | int _getmcontext(mcontext_t*); 42 | void _setmcontext(const mcontext_t*); 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project( 2 | 'dyco', 3 | 'c', 4 | version: 'v2.1.1', 5 | license : 'GPLv3', 6 | default_options: [] 7 | ) 8 | project_description = 'a dynamic coroutine framework for C' 9 | 10 | header_dir = include_directories('include') 11 | 12 | project_headers = [ 13 | 'include/dyco/dyco_coroutine.h', 14 | 'include/dyco/dyco_htable.h', 15 | 'include/dyco/dyco_ucontext.h', 16 | 'include/dyco/sys_queue.h', 17 | 'include/dyco/sys_tree.h', 18 | 'include/dyco/uctx_amd64.h', 19 | 'include/dyco/uctx_mips.h', 20 | 'include/dyco/uctx_power.h', 21 | 'include/dyco/uctx_386.h' 22 | ] 23 | 24 | project_source_files = [ 25 | 'src/dyco_channel.c', 26 | 'src/dyco_epoll.c', 27 | 'src/dyco_schedcall.c', 28 | 'src/dyco_signal.c', 29 | 'src/dyco_waitgroup.c', 30 | 'src/dyco_coropool.c', 31 | 'src/dyco_hook.c', 32 | 'src/dyco_schedule.c', 33 | 'src/dyco_socket.c', 34 | 'src/uctx_context.c', 35 | 'src/dyco_coroutine.c', 36 | 'src/dyco_asymcoro.c', 37 | 'src/dyco_pubsub.c', 38 | 'src/dyco_semaphore.c', 39 | 'src/dyco_ssl.c', 40 | 'src/uctx_asm.S' 41 | ] 42 | 43 | build_args = [ 44 | '-O3', 45 | '-lpthread', 46 | '-Wall', 47 | '-Wno-unused-but-set-variable', 48 | '-Wno-unused-variable', 49 | '-Wno-unused-function' 50 | ] 51 | 52 | build_args += [ 53 | '-DPROJECT_NAME=' + meson.project_name(), 54 | '-DPROJECT_VERSION=' + meson.project_version(), 55 | ] 56 | 57 | project_dep = [ 58 | ] 59 | 60 | crypto_dep = dependency('libcrypto', required : false) 61 | ssl_dep = dependency('libssl', required : false) 62 | hiredis_dep = dependency('hiredis', required : false) 63 | 64 | if crypto_dep.found() and ssl_dep.found() 65 | build_args += [ 66 | '-D DYCO_SSL_OK' 67 | ] 68 | project_dep += [crypto_dep, ssl_dep] 69 | subdir('cert') 70 | endif 71 | # # Only make public interfaces visible 72 | # if target_machine.system() == 'windows' or target_machine.system() == 'cygwin' 73 | # build_args += '-DMYLIB_PUBLIC="__declspec(dllexport)"' 74 | # else 75 | # build_args += '-DMYLIB_PUBLIC=__attribute__((visibility("default")))' 76 | # endif 77 | 78 | libdyco = shared_library( 79 | meson.project_name(), 80 | project_source_files, 81 | dependencies: project_dep, 82 | install : true, 83 | c_args : build_args, 84 | include_directories : header_dir, 85 | ) 86 | 87 | # Make this library usable as a Meson subproject. 88 | libdyco_dep = declare_dependency( 89 | include_directories: header_dir, 90 | link_with : libdyco 91 | ) 92 | set_variable(meson.project_name() + '_dep', libdyco_dep) 93 | 94 | # Make this library usable from the system's 95 | # package manager. 96 | install_headers(project_headers, subdir : meson.project_name()) 97 | 98 | pkg_mod = import('pkgconfig') 99 | pkg_mod.generate( 100 | name : meson.project_name(), 101 | filebase : meson.project_name(), 102 | description : project_description, 103 | libraries : libdyco, 104 | ) 105 | 106 | subdir('example') -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | CUR_SOURCE = ${wildcard *.c} 2 | 3 | CUR_OBJS = ${patsubst %.c, %.o, $(CUR_SOURCE)} 4 | 5 | CUR_ASM_SOURCE = ${wildcard *.S} 6 | 7 | CUR_ASM_OBJS = ${patsubst %.S, %.o, $(CUR_ASM_SOURCE)} 8 | 9 | all : $(CUR_OBJS) $(CUR_ASM_OBJS) 10 | 11 | $(CUR_OBJS) : %.o : %.c 12 | $(CC) -c $^ -o $(OBJS_DIR)/$@ $(FLAG) 13 | $(CC) -c $^ -o $(LIB_DIR)/$@ -fPIC $(FLAG) 14 | 15 | $(CUR_ASM_OBJS) : %.o : %.S 16 | $(CC) -c $^ -o $(OBJS_DIR)/$@ $(FLAG) 17 | $(CC) -c $^ -o $(LIB_DIR)/$@ -fPIC $(FLAG) 18 | 19 | ECHO : 20 | @echo $(SUB_DIR) 21 | -------------------------------------------------------------------------------- /src/dyco_asymcoro.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | int 4 | dyco_coroutine_isasymmetric(int cid) 5 | { 6 | dyco_schedule *sched = get_sched(); 7 | if (sched == NULL) { 8 | return -2; 9 | } 10 | dyco_coroutine *co = htable_find(&sched->cid_co_map, cid); 11 | if (co == NULL) { 12 | return -1; 13 | } 14 | 15 | return TESTBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC); 16 | } 17 | 18 | static void 19 | execute(void *c) { 20 | dyco_coroutine *co = (dyco_coroutine*)c; 21 | SETBIT(co->status, COROUTINE_STATUS_RUNNING); 22 | co->func(co->arg); 23 | SETBIT(co->status, COROUTINE_STATUS_EXITED); 24 | dyco_asymcoroyield(); 25 | } 26 | 27 | static void 28 | init_coro(dyco_coroutine *co) 29 | { 30 | getcontext(&co->ctx); 31 | if (TESTBIT(co->status, COROUTINE_FLAGS_OWNSTACK)) { 32 | co->ctx.uc_stack.ss_sp = co->stack; 33 | co->ctx.uc_stack.ss_size = co->stack_size; 34 | } else { 35 | co->ctx.uc_stack.ss_sp = co->sched->stack; 36 | co->ctx.uc_stack.ss_size = co->sched->stack_size; 37 | } 38 | 39 | makecontext(&co->ctx, (void (*)(void)) execute, 1, (void*)co); 40 | CLRBIT(co->status, COROUTINE_STATUS_NEW); 41 | return; 42 | } 43 | 44 | int 45 | dyco_asymcoro_create(proc_coroutine func, void *arg) 46 | { 47 | dyco_coroutine *co = newcoro(); 48 | if (co == NULL) { 49 | printf("Failed to allocate memory for new coroutine\n"); 50 | return -2; 51 | } 52 | 53 | co->func = func; 54 | co->arg = arg; 55 | SETBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC); 56 | 57 | dyco_schedule *sched = get_sched(); 58 | co->sched = sched; 59 | // co->cid = sched->_cid_gen++; 60 | sched->_cid_gen = (sched->_cid_gen + 1) & 0xffffff; 61 | co->cid = ((sched->sched_id & 0xff) << 24) | sched->_cid_gen; 62 | int ret = htable_insert(&sched->cid_co_map, co->cid, co); 63 | assert(ret >= 0); 64 | ++sched->coro_count; 65 | return co->cid; 66 | 67 | return 0; 68 | } 69 | 70 | 71 | int 72 | dyco_asymcororesume(int cid) 73 | { 74 | dyco_schedule *sched = get_sched(); 75 | if (sched == NULL) { 76 | return -1; 77 | } 78 | dyco_coroutine *co_prev = sched->curr_thread; 79 | dyco_coroutine *co_next = htable_find(&sched->cid_co_map, cid); 80 | if ((co_next == NULL) || (!TESTBIT(co_next->status, COROUTINE_FLAGS_ASYMMETRIC))) { 81 | return -1; 82 | } 83 | if (TESTBIT(co_next->status, COROUTINE_STATUS_EXITED)) { 84 | return 0; 85 | } 86 | 87 | if (co_prev != NULL && !TESTBIT(co_next->status, COROUTINE_FLAGS_OWNSTACK)) { 88 | dyco_asymcoro_setStack(cid, NULL, DYCO_MAX_STACKSIZE); 89 | } 90 | 91 | if (TESTBIT(co_next->status, COROUTINE_STATUS_NEW)) { 92 | init_coro(co_next); 93 | } else { 94 | loadstk(co_next); 95 | } 96 | 97 | ++co_next->sched_count; 98 | 99 | sched->curr_thread = co_next; 100 | SETBIT(co_next->status, COROUTINE_STATUS_RUNNING); 101 | swapcontext(&co_next->ret, &co_next->ctx); 102 | sched->curr_thread = co_prev; 103 | 104 | if (TESTBIT(co_next->status, COROUTINE_STATUS_EXITED)) { 105 | return 0; 106 | } 107 | return cid; 108 | } 109 | 110 | 111 | void 112 | dyco_asymcoroyield() 113 | { 114 | dyco_schedule *sched = get_sched(); 115 | if (sched == NULL) { 116 | return; 117 | } 118 | dyco_coroutine *co = sched->curr_thread; 119 | assert(co != NULL); 120 | 121 | if (TESTBIT(co->status, COROUTINE_STATUS_EXITED) == 0) { 122 | savestk(co); 123 | } 124 | CLRBIT(co->status, COROUTINE_STATUS_RUNNING); 125 | swapcontext(&co->ctx, &co->ret); 126 | SETBIT(co->status, COROUTINE_STATUS_RUNNING); 127 | } 128 | 129 | 130 | void dyco_asymcoro_free(int cid) 131 | { 132 | dyco_schedule *sched = get_sched(); 133 | if (sched == NULL) { 134 | return; 135 | } 136 | dyco_coroutine *co = htable_find(&sched->cid_co_map, cid); 137 | if ((co == NULL) || (!TESTBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC))) { 138 | assert(0); 139 | return; 140 | } 141 | 142 | --co->sched->coro_count; 143 | htable_delete(&co->sched->cid_co_map, co->cid, NULL); 144 | 145 | if (TESTBIT(co->status, COROUTINE_FLAGS_ALLOCSTACKMEM)) { 146 | free(co->stack); 147 | co->stack = NULL; 148 | } 149 | if (co) { 150 | free(co); 151 | } 152 | return; 153 | } 154 | 155 | 156 | int dyco_asymcoro_coroID() 157 | { 158 | return dyco_coroutine_coroID(); 159 | } 160 | 161 | 162 | int dyco_asymcoro_setStack(int cid, void *stackptr, size_t stacksize) 163 | { 164 | return dyco_coroutine_setStack(cid, stackptr, stacksize); 165 | } 166 | 167 | 168 | int dyco_asymcoro_getStack(int cid, void **stackptr, size_t *stacksize) 169 | { 170 | return dyco_coroutine_getStack(cid, stackptr, stacksize); 171 | } 172 | 173 | 174 | int dyco_asymcoro_setUdata(int cid, void *udata) 175 | { 176 | return dyco_coroutine_setUdata(cid, udata); 177 | } 178 | 179 | 180 | int dyco_asymcoro_getUdata(int cid, void **udata) 181 | { 182 | return dyco_coroutine_getUdata(cid, udata); 183 | } 184 | 185 | -------------------------------------------------------------------------------- /src/dyco_channel.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | static void 4 | hdc_notify(dyco_channel* chan, int fd) 5 | { 6 | eventfd_write(fd, (eventfd_t)(chan->status)); 7 | return; 8 | } 9 | 10 | static half_duplex_channel_status 11 | hdc_wait(dyco_channel* chan, int fd, int timeout) 12 | { 13 | if (timeout == 0) { 14 | return chan->status; 15 | } 16 | 17 | dyco_schedule *sched = get_sched(); 18 | if (sched == NULL) { 19 | return chan->status; 20 | } 21 | dyco_coroutine *co = sched->curr_thread; 22 | if (co == NULL) { 23 | return chan->status; 24 | } 25 | DYCO_MUSTNOT(TESTBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC)); 26 | 27 | schedule_sched_waitR(co, fd); 28 | schedule_sched_sleep(co, timeout); 29 | yield(co); 30 | schedule_cancel_sleep(co); 31 | schedule_cancel_wait(co, fd); 32 | 33 | eventfd_t count; 34 | int ret; 35 | ret = eventfd_read(fd, &count); 36 | if (ret == 0) { 37 | return (half_duplex_channel_status)(count); 38 | } 39 | else { 40 | return HDC_STATUS_NOP; 41 | } 42 | 43 | } 44 | 45 | 46 | dyco_channel* 47 | dyco_channel_create(size_t size) 48 | { 49 | dyco_channel *chan = (dyco_channel*)malloc(sizeof(dyco_channel)); 50 | if (chan == NULL) 51 | return NULL; 52 | chan->r_notifyfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); 53 | DYCO_MUSTNOT(chan->r_notifyfd == -1); 54 | 55 | chan->w_notifyfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); 56 | DYCO_MUSTNOT(chan->w_notifyfd == -1); 57 | 58 | chan->maxsize = size > 0 ? size : DYCO_DEFAULT_CHANNELSIZE; 59 | chan->msg = malloc(chan->maxsize); 60 | if (chan->msg == NULL) { 61 | close(chan->r_notifyfd); 62 | close(chan->w_notifyfd); 63 | free(chan); 64 | return NULL; 65 | } 66 | chan->msglen = 0; 67 | chan->status = HDC_STATUS_EMPTY; 68 | return chan; 69 | } 70 | 71 | 72 | void 73 | dyco_channel_destroy(dyco_channel **chan) 74 | { 75 | dyco_channel *channel = *chan; 76 | if ((channel == NULL) || (channel->status = HDC_STATUS_WANTCLOSE)) { 77 | return; 78 | } 79 | 80 | if (channel->status == HDC_STATUS_WANTREAD) { 81 | channel->status = HDC_STATUS_WANTCLOSE; 82 | hdc_notify(channel, channel->r_notifyfd); 83 | hdc_wait(channel, channel->w_notifyfd, -1); 84 | } 85 | else if (channel->status == HDC_STATUS_WANTWRITE) { 86 | channel->status = HDC_STATUS_WANTCLOSE; 87 | hdc_notify(channel, channel->w_notifyfd); 88 | hdc_wait(channel, channel->r_notifyfd, -1); 89 | } 90 | 91 | close(channel->r_notifyfd); 92 | close(channel->w_notifyfd); 93 | free(channel->msg); 94 | free(channel); 95 | *chan = NULL; 96 | return; 97 | } 98 | 99 | 100 | ssize_t 101 | dyco_channel_send(dyco_channel *channel, void *buf, size_t size, int timeout) 102 | { 103 | if ((channel == NULL) || (size > channel->maxsize) || (size == 0)) 104 | return -2; 105 | 106 | int ret = -2; 107 | switch (channel->status) { 108 | case HDC_STATUS_EMPTY: 109 | channel->msglen = size; 110 | memcpy(channel->msg, buf, size); 111 | 112 | channel->status = HDC_STATUS_FULL; 113 | ret = size; 114 | break; 115 | 116 | case HDC_STATUS_FULL: 117 | channel->status = HDC_STATUS_WANTWRITE; 118 | 119 | hdc_wait(channel, channel->w_notifyfd, timeout); 120 | 121 | switch(channel->status) { 122 | case HDC_STATUS_EMPTY: 123 | channel->msglen = size; 124 | memcpy(channel->msg, buf, size); 125 | channel->status = HDC_STATUS_FULL; 126 | ret = size; 127 | break; 128 | case HDC_STATUS_FULL: 129 | DYCO_WARNIF(1, "channel is full."); 130 | break; 131 | case HDC_STATUS_WANTREAD: 132 | channel->msglen = size; 133 | memcpy(channel->msg, buf, size); 134 | channel->status = HDC_STATUS_FULL; 135 | hdc_notify(channel, channel->r_notifyfd); 136 | ret = size; 137 | break; 138 | case HDC_STATUS_WANTWRITE: 139 | channel->status = HDC_STATUS_FULL; 140 | ret = 0; 141 | break; 142 | case HDC_STATUS_WANTCLOSE: 143 | channel->status = HDC_STATUS_CANCLOSE; 144 | hdc_notify(channel, channel->r_notifyfd); 145 | default: 146 | ret = -1; 147 | break; 148 | } 149 | break; 150 | 151 | case HDC_STATUS_WANTREAD: 152 | channel->msglen = size; 153 | memcpy(channel->msg, buf, size); 154 | 155 | channel->status = HDC_STATUS_FULL; 156 | hdc_notify(channel, channel->r_notifyfd); 157 | 158 | ret = size; 159 | break; 160 | 161 | case HDC_STATUS_WANTWRITE: 162 | break; 163 | 164 | case HDC_STATUS_WANTCLOSE: 165 | ret = -1; 166 | break; 167 | 168 | default: break; 169 | } 170 | return ret; 171 | } 172 | 173 | 174 | ssize_t 175 | dyco_channel_recv(dyco_channel *channel, void *buf, size_t maxsize, int timeout) 176 | { 177 | if ((channel == NULL) || (maxsize < channel->maxsize)) 178 | return -2; 179 | 180 | int ret = -2; 181 | switch (channel->status) { 182 | case HDC_STATUS_EMPTY: 183 | channel->status = HDC_STATUS_WANTREAD; 184 | 185 | hdc_wait(channel, channel->r_notifyfd, timeout); 186 | 187 | switch(channel->status) { 188 | case HDC_STATUS_EMPTY: 189 | DYCO_WARNIF(1, "channel is empty."); 190 | break; 191 | case HDC_STATUS_FULL: 192 | ret = channel->msglen; 193 | memcpy(buf, channel->msg, ret); 194 | channel->status = HDC_STATUS_EMPTY; 195 | break; 196 | case HDC_STATUS_WANTREAD: 197 | channel->status = HDC_STATUS_EMPTY; 198 | ret = 0; 199 | break; 200 | case HDC_STATUS_WANTWRITE: 201 | ret = channel->msglen; 202 | memcpy(buf, channel->msg, ret); 203 | channel->status = HDC_STATUS_EMPTY; 204 | hdc_notify(channel, channel->w_notifyfd); 205 | break; 206 | case HDC_STATUS_WANTCLOSE: 207 | channel->status = HDC_STATUS_CANCLOSE; 208 | hdc_notify(channel, channel->w_notifyfd); 209 | default: 210 | ret = -1; 211 | break; 212 | } 213 | break; 214 | 215 | case HDC_STATUS_FULL: 216 | ret = channel->msglen; 217 | memcpy(buf, channel->msg, ret); 218 | 219 | channel->status = HDC_STATUS_EMPTY; 220 | break; 221 | 222 | case HDC_STATUS_WANTREAD: 223 | break; 224 | 225 | case HDC_STATUS_WANTWRITE: 226 | ret = channel->msglen; 227 | memcpy(buf, channel->msg, ret); 228 | 229 | channel->status = HDC_STATUS_EMPTY; 230 | hdc_notify(channel, channel->w_notifyfd); 231 | break; 232 | 233 | case HDC_STATUS_WANTCLOSE: 234 | ret = -1; 235 | break; 236 | 237 | default: break; 238 | } 239 | return ret; 240 | } 241 | -------------------------------------------------------------------------------- /src/dyco_coropool.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | #define dyco_coropool_available(cp) ((cp)->totalsize - (cp)->activenum) 4 | 5 | dyco_coroutine* 6 | get_coro_by_cid(int cid) 7 | { 8 | dyco_schedule *sched = get_sched(); 9 | assert(sched != NULL); 10 | return htable_find(&sched->cid_co_map, cid); 11 | } 12 | 13 | int 14 | coro_setstack(dyco_coroutine *co, void *stackptr, size_t stacksize) 15 | { 16 | if ((co == NULL) || (!TESTBIT(co->status, COROUTINE_STATUS_NEW))) { 17 | return -1; 18 | } 19 | if (stacksize == 0) { 20 | co->stack = NULL; 21 | co->stack_size = 0; 22 | CLRBIT(co->status, COROUTINE_FLAGS_OWNSTACK); 23 | return 0; 24 | } 25 | if (stackptr == NULL) { 26 | int page_size = getpagesize(); 27 | co->stack_size = stacksize + stacksize % page_size; 28 | int ret = posix_memalign(&co->stack, page_size, co->stack_size); 29 | assert(ret == 0); 30 | SETBIT(co->status, COROUTINE_FLAGS_OWNSTACK); 31 | SETBIT(co->status, COROUTINE_FLAGS_ALLOCSTACKMEM); 32 | return 1; 33 | } 34 | co->stack = stackptr; 35 | co->stack_size = stacksize; 36 | SETBIT(co->status, COROUTINE_FLAGS_OWNSTACK); 37 | return 1; 38 | } 39 | 40 | static void 41 | cp_notify(int fd) 42 | { 43 | DYCO_MUST(eventfd_write(fd, 1) == 0); 44 | return; 45 | } 46 | 47 | static int 48 | cp_wait(dyco_coropool* cp, int timeout) 49 | { 50 | int remain = dyco_coropool_available(cp); 51 | if (remain > 0 || timeout == 0) { 52 | return remain; 53 | } 54 | 55 | dyco_schedule *sched = get_sched(); 56 | DYCO_MUSTNOT(sched == NULL); 57 | 58 | dyco_coroutine *co = sched->curr_thread; 59 | DYCO_MUSTNOT(co == NULL); 60 | DYCO_MUSTNOT(TESTBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC)); 61 | 62 | int notifyfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); 63 | DYCO_MUSTNOT(notifyfd == -1); 64 | 65 | dyco_sublist *notify = (dyco_sublist*)malloc(sizeof(dyco_sublist)); 66 | if (notify == NULL) 67 | return 0; 68 | notify->notifyfd = notifyfd; 69 | notify->next = NULL; 70 | if (cp->sublist == NULL) cp->sublist = notify; 71 | else { 72 | dyco_sublist *ptr = cp->sublist; 73 | while (ptr->next != NULL) ptr = ptr->next; 74 | ptr->next = notify; 75 | } 76 | 77 | schedule_sched_waitR(co, notifyfd); 78 | schedule_sched_sleep(co, timeout); 79 | yield(co); 80 | schedule_cancel_sleep(co); 81 | schedule_cancel_wait(co, notifyfd); 82 | 83 | eventfd_t count; 84 | int ret; 85 | ret = eventfd_read(notifyfd, &count); 86 | 87 | // timeout 88 | if (ret < 0) { 89 | if (cp->sublist == notify) { 90 | cp->sublist = notify->next; 91 | } else { 92 | dyco_sublist *ptr = cp->sublist; 93 | while (ptr->next != NULL) { 94 | if (ptr->next == notify) { 95 | ptr->next = notify->next; 96 | break; 97 | } 98 | ptr = ptr->next; 99 | } 100 | } 101 | } 102 | 103 | close(notifyfd); 104 | free(notify); 105 | return dyco_coropool_available(cp); 106 | } 107 | 108 | 109 | dyco_coropool* 110 | cp_create(int totalsize, size_t stacksize, int isasymmetric) 111 | { 112 | if (totalsize <= 0) return NULL; 113 | dyco_coropool *cp = (dyco_coropool*)malloc(sizeof(dyco_coropool)); 114 | if (cp == NULL) 115 | return NULL; 116 | SLIST_INIT(&cp->freelist); 117 | 118 | int i, cid; 119 | dyco_coroutine *cur; 120 | for (i = 0; i < totalsize; ++i) { 121 | cur = newcoro(); 122 | if (isasymmetric != 0) 123 | SETBIT(cur->status, COROUTINE_FLAGS_ASYMMETRIC); 124 | 125 | if (isasymmetric != 0 || stacksize > 0) 126 | coro_setstack(cur, NULL, stacksize); 127 | 128 | SLIST_INSERT_HEAD(&cp->freelist, cur, cpool_next); 129 | SETBIT(cur->status, COROUTINE_FLAGS_INCOROPOOL); 130 | cur->cpool = cp; 131 | } 132 | 133 | cp->totalsize = totalsize; 134 | cp->activenum = 0; 135 | cp->stacksize = stacksize; 136 | cp->sublist = NULL; 137 | 138 | return cp; 139 | } 140 | 141 | 142 | dyco_coropool* 143 | cp_resize(dyco_coropool* cp, int newsize, int isasymmetric) 144 | { 145 | if (cp == NULL || newsize == cp->totalsize) 146 | return cp; 147 | 148 | int i, cid, n; 149 | dyco_coroutine *cur; 150 | if (cp->totalsize < newsize) { 151 | // increase coros 152 | for (i = cp->totalsize; i < newsize; ++i) { 153 | cur = newcoro(); 154 | if (isasymmetric != 0) 155 | SETBIT(cur->status, COROUTINE_FLAGS_ASYMMETRIC); 156 | 157 | if (isasymmetric != 0 || cp->stacksize > 0) 158 | coro_setstack(cur, NULL, cp->stacksize ); 159 | 160 | SLIST_INSERT_HEAD(&cp->freelist, cur, cpool_next); 161 | SETBIT(cur->status, COROUTINE_FLAGS_INCOROPOOL); 162 | cur->cpool = cp; 163 | 164 | if (cp->sublist != NULL) { 165 | // notify 166 | dyco_sublist *head = cp->sublist; 167 | cp_notify(head->notifyfd); 168 | cp->sublist = head->next; 169 | } 170 | } 171 | cp->totalsize = newsize; 172 | } 173 | else 174 | { 175 | // decrease coros 176 | n = newsize >= cp->activenum ? cp->totalsize - newsize : dyco_coropool_available(cp); 177 | for (i = 0; i < n; ++i) { 178 | cur = SLIST_FIRST(&cp->freelist); 179 | SLIST_REMOVE_HEAD(&cp->freelist, cpool_next); 180 | if (isasymmetric != 0) 181 | freecoro(cur); 182 | else 183 | dyco_asymcoro_free(cur->cid); 184 | } 185 | cp->totalsize = newsize; 186 | } 187 | return cp; 188 | } 189 | 190 | 191 | int 192 | cp_destroy(dyco_coropool** coropool, int isasymmetric) 193 | { 194 | dyco_coropool* cp = *coropool; 195 | if (cp == NULL) { 196 | return 0; 197 | } 198 | 199 | if (cp->activenum != 0) return -1; 200 | int i; 201 | dyco_coroutine *cur; 202 | for (i = 0; i < cp->totalsize; ++i) { 203 | cur = SLIST_FIRST(&cp->freelist); 204 | SLIST_REMOVE_HEAD(&cp->freelist, cpool_next); 205 | if (isasymmetric != 0) 206 | freecoro(cur); 207 | else 208 | dyco_asymcoro_free(cur->cid); 209 | } 210 | free(cp); 211 | return 0; 212 | } 213 | 214 | int 215 | cp_obtain(dyco_coropool* cp, proc_coroutine func, void *arg, int timeout, int isasymmetric, int isurgent) 216 | { 217 | DYCO_MUST(func != NULL); 218 | 219 | dyco_schedule *sched = get_sched(); 220 | assert(sched != NULL); 221 | 222 | int ret = cp_wait(cp, timeout); 223 | if (ret <= 0) { 224 | return ret; 225 | } 226 | 227 | dyco_coroutine *co = SLIST_FIRST(&cp->freelist); 228 | SLIST_REMOVE_HEAD(&cp->freelist, cpool_next); 229 | 230 | ++cp->activenum; 231 | 232 | co->func = func; 233 | co->arg = arg; 234 | 235 | uint32_t newstatus = BIT(COROUTINE_STATUS_NEW) | BIT(COROUTINE_STATUS_READY) | BIT(COROUTINE_FLAGS_INCOROPOOL); 236 | if (TESTBIT(co->status, COROUTINE_FLAGS_OWNSTACK)) 237 | SETBIT(newstatus, COROUTINE_FLAGS_OWNSTACK); 238 | if (TESTBIT(co->status, COROUTINE_FLAGS_ALLOCSTACKMEM)) 239 | SETBIT(newstatus, COROUTINE_FLAGS_ALLOCSTACKMEM); 240 | if (isasymmetric != 0) 241 | SETBIT(newstatus, COROUTINE_FLAGS_ASYMMETRIC); 242 | co->status = newstatus; 243 | 244 | co->sched_count = 0; 245 | co->sleep_usecs = 0; 246 | co->udata = NULL; 247 | co->epollfd = -1; 248 | co->sigfd = -1; 249 | 250 | co->sched = sched; 251 | // co->cid = sched->_cid_gen++; 252 | sched->_cid_gen = (sched->_cid_gen + 1) & 0xffffff; 253 | co->cid = ((sched->sched_id & 0xff) << 24) | sched->_cid_gen; 254 | ret = htable_insert(&sched->cid_co_map, co->cid, co); 255 | assert(ret >= 0); 256 | ++sched->coro_count; 257 | 258 | if (isasymmetric == 0) { 259 | if (isurgent) { 260 | SETBIT(co->status, COROUTINE_FLAGS_URGENT); 261 | TAILQ_INSERT_TAIL(&sched->urgent_ready, co, ready_next); 262 | } else { 263 | TAILQ_INSERT_TAIL(&sched->ready, co, ready_next); 264 | } 265 | 266 | if (sched->status == SCHEDULE_STATUS_DONE) { 267 | sched->status = SCHEDULE_STATUS_READY; 268 | } 269 | } 270 | 271 | return co->cid; 272 | } 273 | 274 | 275 | void 276 | cp_return(dyco_coroutine *co, int isasymmetric) 277 | { 278 | if (co == NULL) { 279 | return; 280 | } 281 | dyco_coropool* cp = co->cpool; 282 | if (cp == NULL) { 283 | return; 284 | } 285 | 286 | --co->sched->coro_count; 287 | htable_delete(&co->sched->cid_co_map, co->cid, NULL); 288 | 289 | if (TESTBIT(co->status, COROUTINE_FLAGS_IOMULTIPLEXING)) { 290 | schedule_cancel_wait(co, co->epollfd); 291 | DYCO_MUST(epoll_ctl(co->sched->epollfd, EPOLL_CTL_DEL, co->epollfd, NULL) == 0); 292 | close(co->epollfd); 293 | } 294 | if (TESTBIT(co->status, COROUTINE_FLAGS_WAITSIGNAL)) { 295 | sigprocmask(SIG_SETMASK, &co->old_sigmask, NULL); 296 | close(co->sigfd); 297 | } 298 | CLRBIT(co->status, COROUTINE_FLAGS_URGENT); 299 | 300 | SLIST_INSERT_HEAD(&cp->freelist, co, cpool_next); 301 | --cp->activenum; 302 | if (cp->sublist != NULL) { 303 | dyco_sublist *head = cp->sublist; 304 | cp_notify(head->notifyfd); 305 | cp->sublist = head->next; 306 | } 307 | return; 308 | } 309 | 310 | 311 | dyco_coropool* 312 | dyco_coropool_create(int totalsize, size_t stacksize) 313 | { 314 | return cp_create(totalsize, stacksize, 0); 315 | } 316 | 317 | 318 | dyco_coropool* 319 | dyco_coropool_resize(dyco_coropool* cp, int newsize) 320 | { 321 | return cp_resize(cp, newsize, 0); 322 | } 323 | 324 | 325 | int 326 | dyco_coropool_destroy(dyco_coropool** cp) 327 | { 328 | return cp_destroy(cp, 0); 329 | } 330 | 331 | int 332 | dyco_coropool_obtain(dyco_coropool* cp, proc_coroutine func, void *arg, int timeout) 333 | { 334 | return cp_obtain(cp, func, arg, timeout, 0, 0); 335 | } 336 | 337 | int 338 | dyco_coropool_obtain_urgent(dyco_coropool* cp, proc_coroutine func, void *arg, int timeout) 339 | { 340 | return cp_obtain(cp, func, arg, timeout, 0, 1); 341 | } 342 | 343 | 344 | 345 | void 346 | dyco_coropool_return(dyco_coroutine *co) 347 | { 348 | cp_return(co, 0); 349 | } 350 | 351 | dyco_coropool* 352 | dyco_asymcpool_create(int totalsize, size_t stacksize) 353 | { 354 | return cp_create(totalsize, stacksize, 1); 355 | } 356 | 357 | 358 | dyco_coropool* 359 | dyco_asymcpool_resize(dyco_coropool* cp, int newsize) 360 | { 361 | return cp_resize(cp, newsize, 1); 362 | } 363 | 364 | 365 | int 366 | dyco_asymcpool_destroy(dyco_coropool** cp) 367 | { 368 | return cp_destroy(cp, 1); 369 | } 370 | 371 | 372 | int 373 | dyco_asymcpool_available(dyco_coropool* cp) 374 | { 375 | return dyco_coropool_available(cp); 376 | } 377 | 378 | 379 | int 380 | dyco_asymcpool_obtain(dyco_coropool* cp, proc_coroutine func, void *arg, int timeout) 381 | { 382 | return cp_obtain(cp, func, arg, timeout, 1, 0); 383 | } 384 | 385 | void 386 | dyco_asymcpool_return(int cid) 387 | { 388 | dyco_coroutine *co = get_coro_by_cid(cid); 389 | if (co != NULL) 390 | cp_return(co, 1); 391 | } 392 | -------------------------------------------------------------------------------- /src/dyco_coroutine.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | pthread_key_t global_sched_key; 4 | static pthread_once_t sched_key_once = PTHREAD_ONCE_INIT; 5 | 6 | extern void dyco_coropool_return(dyco_coroutine *co); 7 | 8 | static void 9 | sched_key_destructor(void *data) 10 | { 11 | free(data); 12 | } 13 | 14 | static void 15 | sched_key_creator(void) 16 | { 17 | int ret; 18 | ret = pthread_key_create(&global_sched_key, sched_key_destructor); 19 | assert(ret == 0); 20 | ret = pthread_setspecific(global_sched_key, NULL); 21 | assert(ret == 0); 22 | return; 23 | } 24 | 25 | static void 26 | execute(void *c) 27 | { 28 | dyco_coroutine *co = (dyco_coroutine*)c; 29 | SETBIT(co->status, COROUTINE_STATUS_RUNNING); 30 | co->func(co->arg); 31 | SETBIT(co->status, COROUTINE_STATUS_EXITED); 32 | yield(co); 33 | } 34 | 35 | static void 36 | init_coro(dyco_coroutine *co) 37 | { 38 | 39 | getcontext(&co->ctx); 40 | if (TESTBIT(co->status, COROUTINE_FLAGS_OWNSTACK)) { 41 | co->ctx.uc_stack.ss_sp = co->stack; 42 | co->ctx.uc_stack.ss_size = co->stack_size; 43 | } else { 44 | co->ctx.uc_stack.ss_sp = co->sched->stack; 45 | co->ctx.uc_stack.ss_size = co->sched->stack_size; 46 | } 47 | 48 | makecontext(&co->ctx, (void (*)(void)) execute, 1, (void*)co); 49 | 50 | CLRBIT(co->status, COROUTINE_STATUS_NEW); 51 | return; 52 | } 53 | 54 | void 55 | savestk(dyco_coroutine *co) 56 | { 57 | if (TESTBIT(co->status, COROUTINE_FLAGS_OWNSTACK)) 58 | return; 59 | 60 | char* top = co->sched->stack + co->sched->stack_size; 61 | char dummy = 0; 62 | int cursize = top - &dummy; 63 | assert(cursize <= DYCO_MAX_STACKSIZE); 64 | if (co->stack_size < cursize) { 65 | co->stack = realloc(co->stack, cursize); 66 | assert(co->stack != NULL); 67 | } 68 | co->stack_size = cursize; 69 | memcpy(co->stack, &dummy, co->stack_size); 70 | SETBIT(co->status, COROUTINE_FLAGS_ALLOCSTACKMEM); 71 | return; 72 | } 73 | 74 | int 75 | checkstk(dyco_coroutine *co) 76 | { 77 | int total_size = co->sched->stack_size; 78 | char* top = co->sched->stack + co->sched->stack_size; 79 | int cur_size = 0; 80 | if (TESTBIT(co->status, COROUTINE_FLAGS_OWNSTACK)) { 81 | top = co->stack + co->stack_size; 82 | total_size = co->stack_size; 83 | } 84 | char dummy = 0; 85 | cur_size = top - &dummy; 86 | // printf("stacksize=%d, cosize=%d, totalsize=%d, top=%p, dummy=%p, used=%d\n", co->sched->stack_size, co->stack_size, total_size, top, &dummy, cur_size); 87 | if (total_size < cur_size) { // already overflow. KILL 88 | // printf("[FATAL] coroutine[%d] running stack overflow! (%d/%d)\n", co->cid, cur_size, total_size); 89 | SETBIT(co->status, COROUTINE_STATUS_KILLED); 90 | CLRBIT(co->status, COROUTINE_STATUS_RUNNING); 91 | swapcontext(&co->ctx, &co->sched->ctx); 92 | } else if ((total_size - (total_size >> 3)) < cur_size) { 93 | // printf("[WARN] coroutine[%d] running stack almost overflow. (%d/%d)\n", co->cid, cur_size, total_size); 94 | return 1; 95 | } 96 | return 0; 97 | } 98 | 99 | void 100 | loadstk(dyco_coroutine *co) 101 | { 102 | if (TESTBIT(co->status, COROUTINE_FLAGS_OWNSTACK)) 103 | return; 104 | 105 | memcpy(co->sched->stack + co->sched->stack_size - co->stack_size, co->stack, co->stack_size); 106 | return; 107 | } 108 | 109 | void 110 | yield(dyco_coroutine *co) 111 | { 112 | checkstk(co); // auto check stack usage 113 | if (TESTBIT(co->status, COROUTINE_STATUS_EXITED) == 0) { 114 | savestk(co); 115 | } 116 | CLRBIT(co->status, COROUTINE_STATUS_RUNNING); 117 | swapcontext(&co->ctx, &co->sched->ctx); 118 | SETBIT(co->status, COROUTINE_STATUS_RUNNING); 119 | } 120 | 121 | int 122 | resume(dyco_coroutine *co) 123 | { 124 | if (TESTBIT(co->status, COROUTINE_STATUS_NEW)) { 125 | init_coro(co); 126 | } 127 | else { 128 | loadstk(co); 129 | } 130 | 131 | dyco_schedule *sched = co->sched; 132 | ++co->sched_count; 133 | 134 | sched->curr_thread = co; 135 | swapcontext(&sched->ctx, &co->ctx); 136 | while (TESTBIT(co->status, COROUTINE_STATUS_SCHEDCALL)) { 137 | if (schedule_callexec(sched)) { 138 | swapcontext(&sched->ctx, &co->ctx); 139 | } else { 140 | return 1; 141 | } 142 | } 143 | sched->curr_thread = NULL; 144 | 145 | if (TESTBIT(co->status, COROUTINE_STATUS_KILLED)) { 146 | schedule_cancel_sleep(co); 147 | htable_delete_with_freecb(&sched->cid_co_map, co->cid, coro_abort); 148 | return -1; 149 | } 150 | 151 | if (TESTBIT(co->status, COROUTINE_STATUS_EXITED)) { 152 | schedule_cancel_sleep(co); 153 | if (TESTBIT(co->status, COROUTINE_FLAGS_INCOROPOOL)) 154 | dyco_coropool_return(co); 155 | else 156 | freecoro(co); 157 | 158 | return -1; 159 | } 160 | return 0; 161 | } 162 | 163 | int 164 | waitev(int fd, unsigned int events, int timeout) 165 | { 166 | // events: uint32 epoll event 167 | // timeout: Specifying a negative value in timeout means an infinite timeout. Specifying a timeout of zero causes dyco_poll_inner() to return immediately 168 | 169 | // fast return 170 | struct pollfd pfd; 171 | pfd.fd = fd; 172 | pfd.events = (short)(events & 0xffff); 173 | 174 | int ret = poll_f(&pfd, 1, 0); 175 | if (ret > 0 || timeout == 0) 176 | return ret; 177 | 178 | dyco_schedule *sched = get_sched(); 179 | DYCO_MUST(sched != NULL); 180 | dyco_coroutine *co = sched->curr_thread; 181 | DYCO_MUST(co != NULL); 182 | DYCO_MUSTNOT(TESTBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC)); 183 | 184 | assert(!TESTBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC)); 185 | 186 | schedule_sched_wait(co, fd, events); 187 | schedule_sched_sleep(co, timeout); 188 | yield(co); 189 | schedule_cancel_sleep(co); 190 | schedule_cancel_wait(co, fd); 191 | 192 | 193 | return poll_f(&pfd, 1, 0); 194 | } 195 | 196 | int 197 | dyco_coroutine_create(proc_coroutine func, void *arg) 198 | { 199 | dyco_coroutine *co = newcoro(); 200 | if (co == NULL) { 201 | printf("Failed to allocate memory for new coroutine\n"); 202 | return -2; 203 | } 204 | 205 | co->func = func; 206 | co->arg = arg; 207 | 208 | dyco_schedule *sched = get_sched(); 209 | co->sched = sched; 210 | // co->cid = sched->_cid_gen++; 211 | sched->_cid_gen = (sched->_cid_gen + 1) & 0xffffff; 212 | co->cid = ((sched->sched_id & 0xff) << 24) | sched->_cid_gen; 213 | 214 | int ret = htable_insert(&sched->cid_co_map, co->cid, co); 215 | DYCO_MUST(ret >= 0); 216 | ++sched->coro_count; 217 | 218 | TAILQ_INSERT_TAIL(&sched->ready, co, ready_next); 219 | 220 | if (sched->status == SCHEDULE_STATUS_DONE) { 221 | sched->status = SCHEDULE_STATUS_READY; 222 | } 223 | return co->cid; 224 | } 225 | 226 | int 227 | dyco_coroutine_create_urgent(proc_coroutine func, void *arg) 228 | { 229 | dyco_coroutine *co = newcoro(); 230 | if (co == NULL) { 231 | printf("Failed to allocate memory for new coroutine\n"); 232 | return -2; 233 | } 234 | 235 | co->func = func; 236 | co->arg = arg; 237 | 238 | dyco_schedule *sched = get_sched(); 239 | co->sched = sched; 240 | // co->cid = sched->_cid_gen++; 241 | sched->_cid_gen = (sched->_cid_gen + 1) & 0xffffff; 242 | co->cid = ((sched->sched_id & 0xff) << 24) | sched->_cid_gen; 243 | 244 | int ret = htable_insert(&sched->cid_co_map, co->cid, co); 245 | DYCO_MUST(ret >= 0); 246 | ++sched->coro_count; 247 | 248 | SETBIT(co->status, COROUTINE_FLAGS_URGENT); 249 | TAILQ_INSERT_TAIL(&sched->urgent_ready, co, ready_next); 250 | 251 | if (sched->status == SCHEDULE_STATUS_DONE) { 252 | sched->status = SCHEDULE_STATUS_READY; 253 | } 254 | return co->cid; 255 | } 256 | 257 | dyco_coroutine* 258 | newcoro() 259 | { 260 | int ret = pthread_once(&sched_key_once, sched_key_creator); 261 | DYCO_MUST(ret == 0); 262 | dyco_schedule *sched = get_sched(); 263 | 264 | if (sched == NULL) { 265 | dyco_schedule_create(0, 0); 266 | 267 | sched = get_sched(); 268 | if (sched == NULL) { 269 | printf("Failed to create scheduler\n"); 270 | return NULL; 271 | } 272 | } 273 | 274 | dyco_coroutine *co = calloc(1, sizeof(dyco_coroutine)); 275 | if (co == NULL) { 276 | printf("Failed to allocate memory for new coroutine\n"); 277 | return NULL; 278 | } 279 | 280 | co->stack = NULL; 281 | co->stack_size = 0; 282 | 283 | co->status = BIT(COROUTINE_STATUS_NEW) | BIT(COROUTINE_STATUS_READY); 284 | co->sched_count = 0; 285 | co->sleep_usecs = 0; 286 | 287 | co->cpool = NULL; 288 | 289 | co->udata = NULL; 290 | 291 | co->epollfd = -1; 292 | co->sigfd = -1; 293 | 294 | return co; 295 | } 296 | void 297 | freecoro(dyco_coroutine *co) { 298 | if (co == NULL) 299 | return; 300 | 301 | --co->sched->coro_count; 302 | htable_delete(&co->sched->cid_co_map, co->cid, NULL); 303 | 304 | if (TESTBIT(co->status, COROUTINE_FLAGS_IOMULTIPLEXING)) { 305 | schedule_cancel_wait(co, co->epollfd); 306 | DYCO_MUST(epoll_ctl(co->sched->epollfd, EPOLL_CTL_DEL, co->epollfd, NULL) == 0); 307 | close(co->epollfd); 308 | } 309 | if (TESTBIT(co->status, COROUTINE_FLAGS_WAITSIGNAL)) { 310 | sigprocmask(SIG_SETMASK, &co->old_sigmask, NULL); 311 | close(co->sigfd); 312 | } 313 | if (TESTBIT(co->status, COROUTINE_FLAGS_ALLOCSTACKMEM)) { 314 | free(co->stack); 315 | co->stack = NULL; 316 | } 317 | if (co) { 318 | free(co); 319 | } 320 | return; 321 | } 322 | 323 | void 324 | dyco_coroutine_sleep(uint32_t msecs) { 325 | dyco_schedule *sched = get_sched(); 326 | DYCO_MUST(sched != NULL); 327 | dyco_coroutine *co = sched->curr_thread; 328 | DYCO_MUST(co != NULL); 329 | DYCO_MUSTNOT(TESTBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC)); 330 | 331 | assert(!TESTBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC)); 332 | 333 | if (msecs == 0) { 334 | SETBIT(co->status, COROUTINE_STATUS_READY); 335 | if (TESTBIT(co->status, COROUTINE_FLAGS_URGENT)) 336 | TAILQ_INSERT_TAIL(&sched->urgent_ready, co, ready_next); 337 | else 338 | TAILQ_INSERT_TAIL(&sched->ready, co, ready_next); 339 | // printf("insert to ready queue\n"); 340 | } else { 341 | schedule_sched_sleep(co, msecs); 342 | } 343 | // printf("yed\n"); 344 | yield(co); 345 | } 346 | 347 | void 348 | dyco_coroutine_abort() { 349 | dyco_schedule *sched = get_sched(); 350 | DYCO_MUST(sched != NULL); 351 | dyco_coroutine *co = sched->curr_thread; 352 | DYCO_MUST(co != NULL); 353 | SETBIT(co->status, COROUTINE_STATUS_KILLED); 354 | CLRBIT(co->status, COROUTINE_STATUS_RUNNING); 355 | swapcontext(&co->ctx, &co->sched->ctx); 356 | } 357 | 358 | int 359 | dyco_coroutine_waitRead(int fd, int timeout) 360 | { 361 | return waitev(fd, EPOLLIN | EPOLLERR | EPOLLHUP, timeout); 362 | } 363 | 364 | 365 | int 366 | dyco_coroutine_waitWrite(int fd, int timeout) 367 | { 368 | return waitev(fd, EPOLLOUT | EPOLLERR | EPOLLHUP, timeout); 369 | } 370 | 371 | int 372 | dyco_coroutine_waitRW(int fd, int timeout) 373 | { 374 | return waitev(fd, EPOLLOUT | EPOLLIN | EPOLLERR | EPOLLHUP, timeout); 375 | } 376 | 377 | 378 | int 379 | dyco_coroutine_setStack(int cid, void *stackptr, size_t stacksize) 380 | { 381 | dyco_schedule *sched = get_sched(); 382 | if (sched == NULL) { 383 | return -1; 384 | } 385 | dyco_coroutine *co = htable_find(&sched->cid_co_map, cid); 386 | if ((co == NULL) || (!TESTBIT(co->status, COROUTINE_STATUS_NEW))) { 387 | return -1; 388 | } 389 | if (stacksize == 0) { 390 | co->stack = NULL; 391 | co->stack_size = 0; 392 | CLRBIT(co->status, COROUTINE_FLAGS_OWNSTACK); 393 | return 0; 394 | } 395 | if (stackptr == NULL) { 396 | int page_size = getpagesize(); 397 | co->stack_size = stacksize + stacksize % page_size; 398 | int ret = posix_memalign(&co->stack, page_size, co->stack_size); 399 | assert(ret == 0); 400 | SETBIT(co->status, COROUTINE_FLAGS_OWNSTACK); 401 | SETBIT(co->status, COROUTINE_FLAGS_ALLOCSTACKMEM); 402 | return 1; 403 | } 404 | co->stack = stackptr; 405 | co->stack_size = stacksize; 406 | SETBIT(co->status, COROUTINE_FLAGS_OWNSTACK); 407 | return 1; 408 | } 409 | 410 | int 411 | dyco_coroutine_getStack(int cid, void **stackptr, size_t *stacksize) 412 | { 413 | dyco_schedule *sched = get_sched(); 414 | if (sched == NULL) { 415 | return -1; 416 | } 417 | dyco_coroutine *co = htable_find(&sched->cid_co_map, cid); 418 | if (co == NULL) { 419 | return -1; 420 | } 421 | if (stackptr != NULL) 422 | *stackptr = co->stack; 423 | if (stacksize != NULL) 424 | *stacksize = co->stack_size; 425 | return TESTBIT(co->status, COROUTINE_FLAGS_OWNSTACK); 426 | } 427 | 428 | int 429 | dyco_coroutine_checkStack() 430 | { 431 | dyco_schedule *sched = get_sched(); 432 | DYCO_MUST(sched != NULL); 433 | dyco_coroutine *co = sched->curr_thread; 434 | DYCO_MUST(co != NULL); 435 | return checkstk(co); 436 | } 437 | 438 | int 439 | dyco_coroutine_coroID() 440 | { 441 | dyco_schedule *sched = get_sched(); 442 | if ((sched == NULL) || (sched->curr_thread == NULL)) { 443 | return -1; 444 | } 445 | return sched->curr_thread->cid; 446 | } 447 | 448 | int 449 | dyco_coroutine_setUdata(int cid, void *udata) 450 | { 451 | dyco_schedule *sched = get_sched(); 452 | if (sched == NULL) { 453 | return -1; 454 | } 455 | dyco_coroutine *co = htable_find(&sched->cid_co_map, cid); 456 | if (co == NULL) { 457 | return -1; 458 | } 459 | co->udata = udata; 460 | return 0; 461 | } 462 | 463 | int 464 | dyco_coroutine_getUdata(int cid, void **udata) 465 | { 466 | dyco_schedule *sched = get_sched(); 467 | if (sched == NULL) { 468 | return -1; 469 | } 470 | dyco_coroutine *co = htable_find(&sched->cid_co_map, cid); 471 | if (co == NULL) { 472 | return -1; 473 | } 474 | *udata = co->udata; 475 | return 0; 476 | } 477 | 478 | int 479 | dyco_coroutine_setUrgent(int cid) 480 | { 481 | dyco_schedule *sched = get_sched(); 482 | if (sched == NULL) { 483 | return -1; 484 | } 485 | dyco_coroutine *co = htable_find(&sched->cid_co_map, cid); 486 | if (co == NULL) { 487 | return -1; 488 | } 489 | SETBIT(co->status, COROUTINE_FLAGS_URGENT); 490 | return 0; 491 | } 492 | 493 | 494 | int 495 | dyco_coroutine_unsetUrgent(int cid) 496 | { 497 | dyco_schedule *sched = get_sched(); 498 | if (sched == NULL) { 499 | return -1; 500 | } 501 | dyco_coroutine *co = htable_find(&sched->cid_co_map, cid); 502 | if (co == NULL) { 503 | return -1; 504 | } 505 | CLRBIT(co->status, COROUTINE_FLAGS_URGENT); 506 | return 0; 507 | } 508 | 509 | int 510 | dyco_coroutine_getSchedCount(int cid) 511 | { 512 | dyco_schedule *sched = get_sched(); 513 | if (sched == NULL) { 514 | return -1; 515 | } 516 | dyco_coroutine *co = htable_find(&sched->cid_co_map, cid); 517 | if (co == NULL) { 518 | return -1; 519 | } 520 | return co->sched_count; 521 | } 522 | 523 | -------------------------------------------------------------------------------- /src/dyco_epoll.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | int 4 | dyco_epoll_init() 5 | { 6 | dyco_schedule *sched = get_sched(); 7 | if (sched == NULL) { 8 | perror("ERROR: dyco_epoll_* can only be called inside coroutine functions!"); 9 | return -1; 10 | } 11 | dyco_coroutine *co = sched->curr_thread; 12 | if (co == NULL) { 13 | perror("ERROR: dyco_epoll_* can only be called inside coroutine functions!"); 14 | return -1; 15 | } 16 | 17 | if (TESTBIT(co->status, COROUTINE_FLAGS_IOMULTIPLEXING)) { 18 | perror("ERROR: dyco_epoll_init can only be called once in one coroutine function! You can use normal epollfd and add it by dyco_epoll_ctl"); 19 | return -1; 20 | } 21 | co->epollfd = epoll_create(1024); 22 | DYCO_MUSTNOT(co->epollfd == -1); 23 | SETBIT(co->status, COROUTINE_FLAGS_IOMULTIPLEXING); 24 | 25 | return 0; 26 | } 27 | 28 | int 29 | dyco_epoll_wait(struct epoll_event *events, int maxevents, int timeout) 30 | { 31 | dyco_schedule *sched = get_sched(); 32 | if (sched == NULL) { 33 | perror("ERROR: dyco_epoll_* can only be called inside coroutine functions!"); 34 | return -1; 35 | } 36 | dyco_coroutine *co = sched->curr_thread; 37 | if (co == NULL) { 38 | perror("ERROR: dyco_epoll_* can only be called inside coroutine functions!"); 39 | return -1; 40 | } 41 | assert(!TESTBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC)); 42 | if (!TESTBIT(co->status, COROUTINE_FLAGS_IOMULTIPLEXING)) { 43 | perror("ERROR: 4dyco_epoll_init haven't been called!"); 44 | DYCO_ABORT(); 45 | return -1; 46 | } 47 | 48 | // fast return 49 | if (timeout == 0) { 50 | return epoll_wait_f(co->epollfd, events, maxevents, 0); 51 | } 52 | 53 | schedule_sched_waitR(co, co->epollfd); 54 | schedule_sched_sleep(co, timeout); 55 | yield(co); 56 | schedule_cancel_sleep(co); 57 | schedule_cancel_wait(co, co->epollfd); 58 | 59 | return epoll_wait_f(co->epollfd, events, maxevents, 0); 60 | } 61 | 62 | int 63 | dyco_epoll_add(int fd, struct epoll_event *ev) 64 | { 65 | dyco_schedule *sched = get_sched(); 66 | if (sched == NULL) { 67 | perror("ERROR: dyco_epoll_* can only be called inside coroutine functions!"); 68 | return -1; 69 | } 70 | dyco_coroutine *co = sched->curr_thread; 71 | if (co == NULL) { 72 | perror("ERROR: dyco_epoll_* can only be called inside coroutine functions!"); 73 | return -1; 74 | } 75 | if (!TESTBIT(co->status, COROUTINE_FLAGS_IOMULTIPLEXING)) { 76 | perror("ERROR: 3dyco_epoll_init haven't been called!"); 77 | return -1; 78 | } 79 | DYCO_MUST(epoll_ctl(co->epollfd, EPOLL_CTL_ADD, fd, ev) == 0); 80 | return 0; 81 | } 82 | 83 | int 84 | dyco_epoll_del(int fd, struct epoll_event *ev) 85 | { 86 | dyco_schedule *sched = get_sched(); 87 | if (sched == NULL) { 88 | perror("ERROR: dyco_epoll_* can only be called inside coroutine functions!"); 89 | return -1; 90 | } 91 | dyco_coroutine *co = sched->curr_thread; 92 | if (co == NULL) { 93 | perror("ERROR: dyco_epoll_* can only be called inside coroutine functions!"); 94 | return -1; 95 | } 96 | if (!TESTBIT(co->status, COROUTINE_FLAGS_IOMULTIPLEXING)) { 97 | perror("ERROR: 2dyco_epoll_init haven't been called!"); 98 | return -1; 99 | } 100 | DYCO_MUST(epoll_ctl(co->epollfd, EPOLL_CTL_DEL, fd, ev) == 0); 101 | 102 | return 0; 103 | } 104 | 105 | void 106 | dyco_epoll_destroy() 107 | { 108 | dyco_schedule *sched = get_sched(); 109 | if (sched == NULL) { 110 | perror("ERROR: dyco_epoll_* can only be called inside coroutine functions!"); 111 | return; 112 | } 113 | dyco_coroutine *co = sched->curr_thread; 114 | if (co == NULL) { 115 | perror("ERROR: dyco_epoll_* can only be called inside coroutine functions!"); 116 | return; 117 | } 118 | if (!TESTBIT(co->status, COROUTINE_FLAGS_IOMULTIPLEXING)) { 119 | perror("ERROR: 1dyco_epoll_init haven't been called!"); 120 | return; 121 | } 122 | 123 | 124 | CLRBIT(co->status, COROUTINE_FLAGS_IOMULTIPLEXING); 125 | close(co->epollfd); 126 | 127 | return; 128 | } 129 | 130 | #ifdef COROUTINE_HOOK 131 | 132 | int 133 | epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) 134 | { 135 | if (timeout == 0) { 136 | return epoll_wait_f(epfd, events, timeout, 0); 137 | } 138 | 139 | dyco_schedule *sched = get_sched(); 140 | if (sched == NULL) { 141 | return -1; 142 | } 143 | dyco_coroutine *co = sched->curr_thread; 144 | if (co == NULL) { 145 | return -1; 146 | } 147 | assert(!TESTBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC)); 148 | 149 | schedule_sched_waitR(co, epfd); 150 | schedule_sched_sleep(co, timeout); 151 | yield(co); 152 | schedule_cancel_sleep(co); 153 | schedule_cancel_wait(co, epfd); 154 | 155 | return epoll_wait_f(epfd, events, maxevents, 0); 156 | } 157 | 158 | int 159 | poll(struct pollfd *fds, nfds_t nfds, int timeout) 160 | { 161 | if (timeout == 0) { 162 | return poll_f(fds, nfds, 0); 163 | } 164 | 165 | dyco_schedule *sched = get_sched(); 166 | if (sched == NULL) { 167 | return -1; 168 | } 169 | dyco_coroutine *co = sched->curr_thread; 170 | if (co == NULL) { 171 | return -1; 172 | } 173 | assert(!TESTBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC)); 174 | 175 | struct epoll_event ev; 176 | 177 | int epfd = epoll_create(nfds); 178 | DYCO_MUSTNOT(epfd == -1); 179 | 180 | int i, ret; 181 | for (i = 0; i < nfds; i++) { 182 | ev.events = fds[i].events; 183 | ev.data.fd = fds[i].fd; 184 | DYCO_MUST(epoll_ctl(epfd, EPOLL_CTL_ADD, fds[i].fd, &ev) == 0); 185 | } 186 | 187 | schedule_sched_waitR(co, epfd); 188 | schedule_sched_sleep(co, timeout); 189 | yield(co); 190 | schedule_cancel_sleep(co); 191 | schedule_cancel_wait(co, epfd); 192 | 193 | for (i = 0; i < nfds; i++) { 194 | DYCO_MUST(epoll_ctl(epfd, EPOLL_CTL_DEL, fds[i].fd, NULL) == 0); 195 | } 196 | 197 | return poll_f(fds, nfds, timeout); 198 | } 199 | 200 | #endif 201 | -------------------------------------------------------------------------------- /src/dyco_hook.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | // socket handle 4 | socket_t socket_f; 5 | close_t close_f; 6 | accept_t accept_f; 7 | connect_t connect_f; 8 | recv_t recv_f; 9 | recvfrom_t recvfrom_f; 10 | send_t send_f; 11 | sendto_t sendto_f; 12 | // IO multiplexing wait handle 13 | epoll_wait_t epoll_wait_f; 14 | poll_t poll_f; 15 | 16 | __attribute__((constructor)) static void dyco_inithook() 17 | { 18 | #ifdef COROUTINE_HOOK 19 | // socket handle 20 | socket_f = (socket_t)dlsym(RTLD_NEXT, "socket"); 21 | close_f = (close_t)dlsym(RTLD_NEXT, "close"); 22 | accept_f = (accept_t)dlsym(RTLD_NEXT, "accept"); 23 | connect_f = (connect_t)dlsym(RTLD_NEXT, "connect"); 24 | recv_f = (recv_t)dlsym(RTLD_NEXT, "recv"); 25 | recvfrom_f = (recvfrom_t)dlsym(RTLD_NEXT, "recvfrom"); 26 | send_f = (send_t)dlsym(RTLD_NEXT, "send"); 27 | sendto_f = (sendto_t)dlsym(RTLD_NEXT, "sendto"); 28 | // IO multiplexing wait handle 29 | epoll_wait_f = (epoll_wait_t)dlsym(RTLD_NEXT, "epoll_wait"); 30 | poll_f = (poll_t)dlsym(RTLD_NEXT, "poll"); 31 | #else 32 | // socket handle 33 | socket_f = socket; 34 | close_f = close; 35 | accept_f = accept; 36 | connect_f = connect; 37 | recv_f = recv; 38 | recvfrom_f = recvfrom; 39 | send_f = send; 40 | sendto_f = sendto; 41 | // IO multiplexing wait handle 42 | epoll_wait_f = epoll_wait; 43 | poll_f = poll; 44 | #endif 45 | } 46 | -------------------------------------------------------------------------------- /src/dyco_pubsub.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | static void 4 | psc_subnotify(dyco_pubsubchannel* pschan) 5 | { 6 | dyco_sublist *ptr = pschan->sublist; 7 | while (ptr != NULL) { 8 | eventfd_write(ptr->notifyfd, (eventfd_t)(pschan->status)); 9 | ptr = ptr->next; 10 | } 11 | pschan->ack_rem = pschan->sub_num; 12 | return; 13 | } 14 | 15 | static void 16 | psc_pubnotify(dyco_pubsubchannel* pschan) 17 | { 18 | DYCO_MUST(eventfd_write(pschan->pub_notifyfd, (eventfd_t)(pschan->status)) == 0); 19 | return; 20 | } 21 | 22 | static dyco_pubsub_channel_status 23 | psc_subwait(dyco_pubsubchannel* pschan, int timeout) 24 | { 25 | if (timeout == 0) { 26 | return pschan->status; 27 | } 28 | 29 | dyco_schedule *sched = get_sched(); 30 | if (sched == NULL) { 31 | return pschan->status; 32 | } 33 | dyco_coroutine *co = sched->curr_thread; 34 | if (co == NULL) { 35 | return pschan->status; 36 | } 37 | assert(!TESTBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC)); 38 | 39 | int notifyfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); 40 | DYCO_MUSTNOT(notifyfd == -1); 41 | 42 | dyco_sublist *sublist = pschan->sublist; 43 | dyco_sublist *subnode = (dyco_sublist*)malloc(sizeof(dyco_sublist)); 44 | DYCO_MUSTNOT(subnode == NULL); 45 | subnode->notifyfd = notifyfd; 46 | subnode->next = sublist; 47 | pschan->sublist = subnode; 48 | pschan->sub_num++; 49 | 50 | schedule_sched_waitR(co, notifyfd); 51 | schedule_sched_sleep(co, timeout); 52 | yield(co); 53 | schedule_cancel_sleep(co); 54 | schedule_cancel_wait(co, notifyfd); 55 | 56 | eventfd_t count; 57 | int ret; 58 | ret = eventfd_read(notifyfd, &count); 59 | 60 | pschan->sub_num--; 61 | dyco_sublist *pre = pschan->sublist; 62 | dyco_sublist *ptr = pre->next; 63 | if (pre->notifyfd == notifyfd) { 64 | pschan->sublist = ptr; 65 | close(pre->notifyfd); 66 | free(pre); 67 | } else { 68 | while (ptr != NULL) { 69 | if (ptr->notifyfd == notifyfd) { 70 | pre->next = ptr->next; 71 | close(ptr->notifyfd); 72 | free(ptr); 73 | break; 74 | } 75 | pre = ptr; 76 | ptr = ptr->next; 77 | } 78 | } 79 | 80 | if (ret == 0) { 81 | if (--(pschan->ack_rem) == 0) 82 | // psc_pubnotify(pschan); 83 | return PSC_STATUS_EMPTY; 84 | 85 | return (dyco_pubsub_channel_status)(count); 86 | } else { 87 | return PSC_STATUS_NOP; 88 | } 89 | } 90 | 91 | static dyco_pubsub_channel_status 92 | psc_pubwait(dyco_pubsubchannel* pschan, int timeout) 93 | { 94 | if (timeout == 0) { 95 | return pschan->status; 96 | } 97 | 98 | dyco_schedule *sched = get_sched(); 99 | if (sched == NULL) { 100 | return pschan->status; 101 | } 102 | dyco_coroutine *co = sched->curr_thread; 103 | if (co == NULL) { 104 | return pschan->status; 105 | } 106 | assert(!TESTBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC)); 107 | 108 | pschan->pub_notifyfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); 109 | DYCO_MUSTNOT(pschan->pub_notifyfd == -1); 110 | 111 | schedule_sched_waitR(co, pschan->pub_notifyfd); 112 | schedule_sched_sleep(co, timeout); 113 | yield(co); 114 | schedule_cancel_sleep(co); 115 | schedule_cancel_wait(co, pschan->pub_notifyfd); 116 | 117 | eventfd_t count; 118 | int ret; 119 | ret = eventfd_read(pschan->pub_notifyfd, &count); 120 | 121 | close(pschan->pub_notifyfd); 122 | if (ret == 0) 123 | return (dyco_pubsub_channel_status)(count); 124 | else 125 | return PSC_STATUS_NOP; 126 | } 127 | 128 | dyco_pubsubchannel* dyco_pubsub_create(size_t size) 129 | { 130 | dyco_pubsubchannel* pschan = (dyco_pubsubchannel*)malloc(sizeof(dyco_pubsubchannel)); 131 | if (pschan == NULL) 132 | return NULL; 133 | pschan->maxsize = size > 0 ? size : DYCO_DEFAULT_CHANNELSIZE; 134 | pschan->msg = malloc(pschan->maxsize); 135 | if (pschan->msg == NULL) { 136 | free(pschan); 137 | return NULL; 138 | } 139 | pschan->msglen = 0; 140 | pschan->pub_notifyfd = -1; 141 | pschan->sub_num = 0; 142 | pschan->ack_rem = 0; 143 | pschan->sublist = NULL; 144 | pschan->status = PSC_STATUS_EMPTY; 145 | return pschan; 146 | } 147 | 148 | 149 | void dyco_pubsub_destroy(dyco_pubsubchannel **ps_chan) 150 | { 151 | dyco_pubsubchannel *pschan = *ps_chan; 152 | if (pschan == NULL) 153 | return; 154 | if (pschan->sub_num != 0) { 155 | pschan->status = PSC_STATUS_CLOSE; 156 | psc_subnotify(pschan); 157 | psc_pubwait(pschan, -1); 158 | } 159 | free(pschan->msg); 160 | free(pschan); 161 | *ps_chan = NULL; 162 | return; 163 | } 164 | 165 | 166 | ssize_t dyco_pubsub_publish(dyco_pubsubchannel *ps_chan, void *buf, size_t size) 167 | { 168 | if ((ps_chan == NULL) || (ps_chan->status != PSC_STATUS_EMPTY) || (size > ps_chan->maxsize) || (size == 0)) 169 | return -2; 170 | 171 | if (ps_chan->sub_num == 0) 172 | return 0; 173 | 174 | ps_chan->msglen = size; 175 | memcpy(ps_chan->msg, buf, size); 176 | ps_chan->status = PSC_STATUS_TRANS; 177 | psc_subnotify(ps_chan); 178 | psc_pubwait(ps_chan, -1); 179 | ps_chan->status = PSC_STATUS_EMPTY; 180 | return size; 181 | } 182 | 183 | 184 | ssize_t dyco_pubsub_subscribe(dyco_pubsubchannel *ps_chan, void *buf, size_t maxsize, int timeout) 185 | { 186 | if ((ps_chan == NULL) || (maxsize < ps_chan->maxsize)) 187 | return -2; 188 | 189 | int ret = -2; 190 | dyco_pubsub_channel_status status; 191 | switch (ps_chan->status) { 192 | case PSC_STATUS_EMPTY: 193 | case PSC_STATUS_TRANS: 194 | status = psc_subwait(ps_chan, timeout); 195 | switch (status) { 196 | case PSC_STATUS_EMPTY: 197 | ret = ps_chan->msglen; 198 | memcpy(buf, ps_chan->msg, ret); 199 | psc_pubnotify(ps_chan); 200 | break; 201 | case PSC_STATUS_TRANS: 202 | ret = ps_chan->msglen; 203 | memcpy(buf, ps_chan->msg, ret); 204 | break; 205 | case PSC_STATUS_CLOSE: 206 | ret = -1; 207 | break; 208 | default: 209 | break; 210 | } 211 | break; 212 | case PSC_STATUS_CLOSE: 213 | ret = -1; 214 | break; 215 | default: 216 | ret = -1; 217 | break; 218 | } 219 | return ret; 220 | } 221 | -------------------------------------------------------------------------------- /src/dyco_schedcall.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | extern void savestk(dyco_coroutine *co); 3 | 4 | typedef struct { 5 | int __how; 6 | sigset_t *__set; 7 | sigset_t *__oset; 8 | } sigprocmask_args; 9 | 10 | int schedule_callexec(dyco_schedule *sched) 11 | { 12 | int shouldresume = 1; 13 | sigprocmask_args *sargs; 14 | dyco_schedcall *call = &sched->schedcall; 15 | switch (call->callnum) { 16 | case CALLNUM_SIGPROCMASK: 17 | sargs = call->arg; 18 | call->ret = sigprocmask(sargs->__how, sargs->__set, sargs->__oset); 19 | shouldresume = 1; 20 | break; 21 | case CALLNUM_SCHED_STOP: 22 | schedule_stop(sched); 23 | call->ret = 0; 24 | shouldresume = 0; 25 | break; 26 | case CALLNUM_SCHED_ABORT: 27 | schedule_abort(sched); 28 | call->ret = 0; 29 | shouldresume = 0; 30 | break; 31 | default: 32 | call->ret = -1; 33 | shouldresume = 1; 34 | break; 35 | } 36 | return shouldresume; 37 | } 38 | 39 | int dyco_schedcall_sigprocmask(int how, sigset_t *set, sigset_t *oset) 40 | { 41 | dyco_schedule *sched = get_sched(); 42 | if (sched == NULL) { 43 | perror("schedcall can only be used when scheduler is running.\n"); 44 | return -1; 45 | } 46 | dyco_coroutine *co = sched->curr_thread; 47 | if (co == NULL) { 48 | perror("schedcall can only be used when scheduler is running.\n"); 49 | return -1; 50 | } 51 | 52 | DYCO_MUST(sigprocmask(SIG_BLOCK, set, NULL) == 0); 53 | 54 | sigprocmask_args args = {how, set, oset}; 55 | sched->schedcall.callnum = CALLNUM_SIGPROCMASK; 56 | sched->schedcall.arg = &args; 57 | 58 | CLRBIT(co->status, COROUTINE_STATUS_RUNNING); 59 | SETBIT(co->status, COROUTINE_STATUS_SCHEDCALL); 60 | 61 | swapcontext(&co->ctx, &co->sched->ctx); 62 | 63 | CLRBIT(co->status, COROUTINE_STATUS_SCHEDCALL); 64 | SETBIT(co->status, COROUTINE_STATUS_RUNNING); 65 | 66 | return sched->schedcall.ret; 67 | } 68 | 69 | 70 | void dyco_schedcall_stop() 71 | { 72 | dyco_schedule *sched = get_sched(); 73 | if (sched == NULL) { 74 | perror("schedcall can only be used when scheduler is running.\n"); 75 | return; 76 | } 77 | dyco_coroutine *co = sched->curr_thread; 78 | if (co == NULL) { 79 | perror("schedcall can only be used when scheduler is running.\n"); 80 | return; 81 | } 82 | 83 | sched->schedcall.callnum = CALLNUM_SCHED_STOP; 84 | 85 | CLRBIT(co->status, COROUTINE_STATUS_RUNNING); 86 | SETBIT(co->status, COROUTINE_STATUS_SCHEDCALL); 87 | SETBIT(co->status, COROUTINE_STATUS_READY); 88 | 89 | if (TESTBIT(co->status, COROUTINE_FLAGS_URGENT)) 90 | TAILQ_INSERT_TAIL(&sched->urgent_ready, co, ready_next); 91 | else 92 | TAILQ_INSERT_TAIL(&sched->ready, co, ready_next); 93 | 94 | savestk(co); 95 | swapcontext(&co->ctx, &co->sched->ctx); 96 | SETBIT(co->status, COROUTINE_STATUS_RUNNING); 97 | CLRBIT(co->status, COROUTINE_STATUS_SCHEDCALL); 98 | 99 | return; 100 | } 101 | 102 | 103 | void dyco_schedcall_abort() 104 | { 105 | dyco_schedule *sched = get_sched(); 106 | if (sched == NULL) { 107 | perror("schedcall can only be used when scheduler is running.\n"); 108 | return; 109 | } 110 | dyco_coroutine *co = sched->curr_thread; 111 | if (co == NULL) { 112 | perror("schedcall can only be used when scheduler is running.\n"); 113 | return; 114 | } 115 | 116 | sched->schedcall.callnum = CALLNUM_SCHED_ABORT; 117 | 118 | CLRBIT(co->status, COROUTINE_STATUS_RUNNING); 119 | SETBIT(co->status, COROUTINE_STATUS_SCHEDCALL); 120 | swapcontext(&co->ctx, &co->sched->ctx); 121 | CLRBIT(co->status, COROUTINE_STATUS_SCHEDCALL); 122 | SETBIT(co->status, COROUTINE_STATUS_RUNNING); 123 | 124 | return; 125 | } 126 | -------------------------------------------------------------------------------- /src/dyco_schedule.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | atomic_uint sched_id_gen; 4 | 5 | RB_GENERATE(dyco_coroutine_rbtree_sleep, dyco_coroutine, sleep_node, coroutine_sleep_cmp); 6 | 7 | #define SCHEDULE_ISDONE(sched) (HTABLE_EMPTY(&sched->fd_co_map) && \ 8 | RB_EMPTY(&sched->sleeping) && \ 9 | TAILQ_EMPTY(&sched->ready) && \ 10 | TAILQ_EMPTY(&sched->urgent_ready)) 11 | 12 | extern void dyco_coropool_return(dyco_coroutine *co); 13 | 14 | static dyco_coroutine* 15 | schedule_get_expired(dyco_schedule *sched) 16 | { 17 | uint64_t tdiff_usecs = diff_usecs(sched->birth, usec_now()); 18 | dyco_coroutine *co = RB_MIN(dyco_coroutine_rbtree_sleep, &sched->sleeping); 19 | 20 | if (co == NULL) 21 | return NULL; 22 | if (co->sleep_usecs <= tdiff_usecs) 23 | { 24 | RB_REMOVE(dyco_coroutine_rbtree_sleep, &co->sched->sleeping, co); 25 | CLRBIT(co->status, COROUTINE_STATUS_SLEEPING); 26 | SETBIT(co->status, COROUTINE_FLAGS_EXPIRED); 27 | return co; 28 | } 29 | return NULL; 30 | } 31 | 32 | static uint64_t 33 | schedule_min_timeout(dyco_schedule *sched) 34 | { 35 | dyco_coroutine *co = RB_MIN(dyco_coroutine_rbtree_sleep, &sched->sleeping); 36 | if (!co) 37 | return sched->loopwait_timeout; 38 | 39 | uint64_t now_relative_usecs = diff_usecs(sched->birth, usec_now()); 40 | return co->sleep_usecs > now_relative_usecs ? co->sleep_usecs - now_relative_usecs : 0; 41 | } 42 | 43 | static int 44 | schedule_epoll_wait(dyco_schedule *sched) 45 | { 46 | if (HTABLE_EMPTY(&sched->fd_co_map) && RB_EMPTY(&sched->sleeping)) return 0; 47 | 48 | if (!TAILQ_EMPTY(&sched->ready) || !TAILQ_EMPTY(&sched->urgent_ready)) 49 | return epoll_wait_f(sched->epollfd, sched->eventlist, DYCO_MAX_EVENTS, 0); 50 | // return 0; 51 | 52 | uint64_t timeout = schedule_min_timeout(sched); 53 | if (timeout == 0) 54 | return epoll_wait_f(sched->epollfd, sched->eventlist, DYCO_MAX_EVENTS, 0); 55 | 56 | int nready = -1; 57 | while (1) 58 | { 59 | nready = epoll_wait_f(sched->epollfd, sched->eventlist, DYCO_MAX_EVENTS, timeout/1000); 60 | if (nready == -1) 61 | { 62 | if (errno == EINTR) 63 | continue; 64 | else 65 | DYCO_ABORT(); 66 | } 67 | break; 68 | } 69 | return nready; 70 | } 71 | 72 | dyco_coroutine* 73 | schedule_get_waitco(dyco_schedule *sched, int fd) 74 | { 75 | 76 | return (dyco_coroutine*)htable_find(&sched->fd_co_map, fd); 77 | } 78 | 79 | void 80 | dyco_schedule_free(dyco_schedule *sched) 81 | { 82 | if (sched->epollfd > 0) 83 | { 84 | close(sched->epollfd); 85 | } 86 | if (sched->stack != NULL) 87 | { 88 | free(sched->stack); 89 | } 90 | htable_clear(&sched->fd_co_map); 91 | htable_clear(&sched->cid_co_map); 92 | 93 | free(sched); 94 | 95 | int ret = pthread_setspecific(global_sched_key, NULL); 96 | assert(ret == 0); 97 | } 98 | 99 | int 100 | dyco_schedule_create(size_t stack_size, uint64_t loopwait_timeout) 101 | { 102 | dyco_schedule *sched = (dyco_schedule *)calloc(1, sizeof(dyco_schedule)); 103 | if (sched == NULL) 104 | { 105 | printf("Failed to initialize scheduler\n"); 106 | return -1; 107 | } 108 | int ret = pthread_setspecific(global_sched_key, sched); 109 | assert(ret == 0); 110 | 111 | sched->epollfd = epoll_create(1024); 112 | DYCO_MUSTNOT(sched->epollfd == -1); 113 | 114 | int sched_stack_size = stack_size ? stack_size : DYCO_MAX_STACKSIZE; 115 | sched->stack_size = sched_stack_size; 116 | int page_size = getpagesize(); 117 | ret = posix_memalign(&sched->stack, page_size, sched->stack_size); 118 | assert(ret == 0); 119 | 120 | pthread_t tid = pthread_self(); 121 | sched->sched_id = ++sched_id_gen; 122 | sched->loopwait_timeout = loopwait_timeout ? loopwait_timeout : DYCO_DEFAULT_TIMEOUT; 123 | sched->birth = usec_now(); 124 | sched->coro_count = 0; 125 | // sched->_cid_gen = (sched->sched_id % 0xf0) * 1000000; 126 | sched->_cid_gen = 0; 127 | // sched->_cid_gen 128 | sched->status = SCHEDULE_STATUS_READY; 129 | sched->curr_thread = NULL; 130 | 131 | sched->udata = NULL; 132 | 133 | TAILQ_INIT(&sched->urgent_ready); 134 | TAILQ_INIT(&sched->ready); 135 | RB_INIT(&sched->sleeping); 136 | 137 | htable_init(&sched->fd_co_map, 0); 138 | htable_init(&sched->cid_co_map, 0); 139 | 140 | return sched->sched_id; 141 | } 142 | 143 | void schedule_sched_sleep(dyco_coroutine *co, int msecs) 144 | { 145 | dyco_coroutine *co_tmp = RB_FIND(dyco_coroutine_rbtree_sleep, &co->sched->sleeping, co); 146 | if (co_tmp != NULL) 147 | { 148 | RB_REMOVE(dyco_coroutine_rbtree_sleep, &co->sched->sleeping, co_tmp); 149 | } 150 | 151 | if (msecs <= 0) return; 152 | uint64_t usecs = msecs * 1000u; 153 | 154 | co->sleep_usecs = diff_usecs(co->sched->birth, usec_now()) + usecs; 155 | while (msecs) 156 | { 157 | co_tmp = RB_INSERT(dyco_coroutine_rbtree_sleep, &co->sched->sleeping, co); 158 | if (co_tmp) 159 | { 160 | co->sleep_usecs++; 161 | continue; 162 | } 163 | SETBIT(co->status, COROUTINE_STATUS_SLEEPING); 164 | CLRBIT(co->status, COROUTINE_FLAGS_EXPIRED); 165 | break; 166 | } 167 | 168 | return; 169 | } 170 | 171 | void 172 | schedule_cancel_sleep(dyco_coroutine *co) 173 | { 174 | if (TESTBIT(co->status, COROUTINE_STATUS_SLEEPING)) 175 | { 176 | RB_REMOVE(dyco_coroutine_rbtree_sleep, &co->sched->sleeping, co); 177 | CLRBIT(co->status, COROUTINE_STATUS_SLEEPING); 178 | } 179 | 180 | return; 181 | } 182 | 183 | int 184 | schedule_cancel_wait(dyco_coroutine *co, int fd) 185 | { 186 | if (TESTBIT(co->status, COROUTINE_FLAGS_WAITING)) { 187 | 188 | htable_delete(&co->sched->fd_co_map, fd, NULL); 189 | CLRBIT(co->status, COROUTINE_FLAGS_WAITING); 190 | DYCO_MUST(epoll_ctl(co->sched->epollfd, EPOLL_CTL_DEL, fd, NULL) == 0); 191 | return 0; 192 | } 193 | return 1; 194 | } 195 | 196 | 197 | void 198 | schedule_sched_wait(dyco_coroutine *co, int fd, unsigned int events) 199 | { 200 | struct epoll_event ev; 201 | ev.data.fd = fd; 202 | ev.events = events; 203 | DYCO_MUST(epoll_ctl(co->sched->epollfd, EPOLL_CTL_ADD, fd, &ev) == 0); 204 | 205 | int ret = htable_insert(&co->sched->fd_co_map, fd, co); 206 | assert(ret >= 0); 207 | SETBIT(co->status, COROUTINE_FLAGS_WAITING); 208 | return; 209 | } 210 | 211 | void 212 | schedule_sched_waitR(dyco_coroutine *co, int fd) 213 | { 214 | schedule_sched_wait(co, fd, EPOLLIN | EPOLLHUP | EPOLLERR); 215 | return; 216 | } 217 | 218 | void 219 | schedule_sched_waitW(dyco_coroutine *co, int fd) 220 | { 221 | schedule_sched_wait(co, fd, EPOLLOUT | EPOLLHUP | EPOLLERR); 222 | return; 223 | } 224 | 225 | void 226 | schedule_sched_waitRW(dyco_coroutine *co, int fd) 227 | { 228 | schedule_sched_wait(co, fd, EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLERR); 229 | return; 230 | } 231 | 232 | void 233 | schedule_stop(dyco_schedule *sched) 234 | { 235 | sched->status = SCHEDULE_STATUS_STOPPED; 236 | sched->curr_thread = NULL; 237 | return; 238 | } 239 | 240 | 241 | void 242 | coro_abort(void *arg) 243 | { 244 | dyco_coroutine *co = arg; 245 | if (TESTBIT(co->status, COROUTINE_FLAGS_INCOROPOOL)) { 246 | if (TESTBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC)) 247 | dyco_asymcpool_return(co->cid); 248 | else 249 | dyco_coropool_return(co); 250 | } else { 251 | if (TESTBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC)) 252 | dyco_asymcoro_free(co->cid); 253 | else 254 | freecoro(co); 255 | } 256 | return; 257 | } 258 | void 259 | schedule_abort(dyco_schedule *sched) // map! 260 | { 261 | htable_clear_with_freecb(&sched->cid_co_map, coro_abort); 262 | sched->curr_thread = NULL; 263 | assert(sched->coro_count == 0); 264 | sched->status = SCHEDULE_STATUS_ABORTED; 265 | } 266 | 267 | int 268 | dyco_schedule_run() 269 | { 270 | dyco_schedule *sched = get_sched(); 271 | if (sched == NULL) 272 | return -2; 273 | 274 | DYCO_MUSTNOT(sched->status == SCHEDULE_STATUS_RUNNING); 275 | 276 | int idx, nready; 277 | dyco_coroutine *expired; 278 | dyco_coroutine *last_co_ready; 279 | 280 | if (sched->status == SCHEDULE_STATUS_ABORTED) { 281 | return -2; 282 | } 283 | else if (sched->status == SCHEDULE_STATUS_DONE) { 284 | return 0; 285 | } 286 | sched->status = SCHEDULE_STATUS_RUNNING; 287 | 288 | while (!SCHEDULE_ISDONE(sched)) 289 | { 290 | // A. probing timing coroutines 291 | expired = NULL; 292 | while ((expired = schedule_get_expired(sched)) != NULL) 293 | { 294 | SETBIT(expired->status, COROUTINE_STATUS_READY); 295 | if (TESTBIT(expired->status, COROUTINE_FLAGS_URGENT)) 296 | TAILQ_INSERT_TAIL(&sched->urgent_ready, expired, ready_next); 297 | else 298 | TAILQ_INSERT_TAIL(&sched->ready, expired, ready_next); 299 | } 300 | 301 | // B. processing urgent ready coroutines 302 | last_co_ready = TAILQ_LAST(&sched->urgent_ready, dyco_coroutine_queue); 303 | idx = 0; 304 | while (!TAILQ_EMPTY(&sched->urgent_ready)) 305 | { 306 | dyco_coroutine *co = TAILQ_FIRST(&sched->urgent_ready); 307 | TAILQ_REMOVE(&sched->urgent_ready, co, ready_next); 308 | CLRBIT(co->status, COROUTINE_STATUS_READY); 309 | resume(co); 310 | if (sched->status == SCHEDULE_STATUS_STOPPED) 311 | return 1; 312 | else if (sched->status == SCHEDULE_STATUS_ABORTED) 313 | return -1; 314 | 315 | if (co == last_co_ready) 316 | break; 317 | if (++idx == DYCO_URGENT_MAXEXEC) 318 | break; 319 | } 320 | 321 | // C. processing some of the ready coroutines 322 | last_co_ready = TAILQ_LAST(&sched->ready, dyco_coroutine_queue); 323 | idx = 0; 324 | while (!TAILQ_EMPTY(&sched->ready)) 325 | { 326 | dyco_coroutine *co = TAILQ_FIRST(&sched->ready); 327 | TAILQ_REMOVE(&sched->ready, co, ready_next); 328 | CLRBIT(co->status, COROUTINE_STATUS_READY); 329 | resume(co); 330 | if (sched->status == SCHEDULE_STATUS_STOPPED) 331 | return 1; 332 | else if (sched->status == SCHEDULE_STATUS_ABORTED) 333 | return -1; 334 | 335 | if (co == last_co_ready) 336 | break; 337 | if (++idx == DYCO_URGENT_MAXWAIT) 338 | break; 339 | } 340 | 341 | // D. probing event-driven coroutines 342 | nready = schedule_epoll_wait(sched); 343 | if (nready == 0) 344 | continue; 345 | 346 | idx = 0; 347 | #ifdef DYCO_RANDOM_WAITFD 348 | int idxarray[DYCO_MAX_EVENTS]; 349 | int ridx = 0, tmp = 0; 350 | while (idx < nready) { 351 | idxarray[idx] = idx; 352 | ++idx; 353 | } 354 | idx = nready - 1; 355 | while (idx > 2) { 356 | ridx = rand() % idx; 357 | tmp = idxarray[idx]; 358 | idxarray[idx] = idxarray[ridx]; 359 | idxarray[ridx] = tmp; 360 | --idx; 361 | } 362 | #endif 363 | while (idx < nready) 364 | { 365 | #ifdef DYCO_RANDOM_WAITFD 366 | struct epoll_event *ev = sched->eventlist + idxarray[idx]; 367 | #else 368 | struct epoll_event *ev = sched->eventlist + idx; 369 | #endif 370 | 371 | int fd = ev->data.fd; 372 | 373 | dyco_coroutine *co = schedule_get_waitco(sched, fd); 374 | if (co != NULL) 375 | { 376 | SETBIT(co->status, COROUTINE_STATUS_READY); 377 | if (TESTBIT(co->status, COROUTINE_FLAGS_URGENT)) 378 | TAILQ_INSERT_TAIL(&sched->urgent_ready, co, ready_next); 379 | else 380 | TAILQ_INSERT_TAIL(&sched->ready, co, ready_next); 381 | 382 | schedule_cancel_wait(co, fd); 383 | } 384 | ++idx; 385 | } 386 | 387 | } 388 | sched->status = SCHEDULE_STATUS_DONE; 389 | return 0; 390 | } 391 | 392 | int 393 | dyco_schedule_schedID() 394 | { 395 | dyco_schedule *sched = get_sched(); 396 | if (sched == NULL) { 397 | return -1; 398 | } 399 | return (int)sched->sched_id; 400 | } 401 | 402 | int 403 | dyco_schedule_setUdata(void *udata) 404 | { 405 | dyco_schedule *sched = get_sched(); 406 | if (sched == NULL) { 407 | return -1; 408 | } 409 | sched->udata = udata; 410 | return 0; 411 | } 412 | 413 | 414 | int 415 | dyco_schedule_getUdata(void **udata) 416 | { 417 | dyco_schedule *sched = get_sched(); 418 | if (sched == NULL) { 419 | return -1; 420 | } 421 | *udata = sched->udata; 422 | return 0; 423 | } 424 | 425 | 426 | int 427 | dyco_schedule_getCoroCount() 428 | { 429 | dyco_schedule *sched = get_sched(); 430 | if (sched == NULL) { 431 | return -1; 432 | } 433 | return sched->coro_count; 434 | } 435 | -------------------------------------------------------------------------------- /src/dyco_semaphore.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | #define DYCO_SEM_VALUE_MAX 0x7fffffff 4 | 5 | void sem_notify(int fd, eventfd_t data) 6 | { 7 | DYCO_MUST(eventfd_write(fd, data) == 0); 8 | } 9 | 10 | dyco_semaphore* dyco_semaphore_create(size_t value) 11 | { 12 | if (value > DYCO_SEM_VALUE_MAX) return NULL; 13 | dyco_semaphore *sem = (dyco_semaphore*)malloc(sizeof(dyco_semaphore)); 14 | if (sem == NULL) 15 | return NULL; 16 | sem->semval = value; 17 | sem->wqueue = NULL; 18 | sem->wtail = NULL; 19 | return sem; 20 | } 21 | 22 | 23 | void dyco_semaphore_destroy(dyco_semaphore **__sem) 24 | { 25 | dyco_semaphore* sem = *__sem; 26 | if (sem == NULL) return; 27 | dyco_semwait_queue *pre = sem->wqueue; 28 | dyco_semwait_queue *ptr; 29 | while (pre != NULL) 30 | { 31 | ptr = pre->next; 32 | sem_notify(pre->notifyfd, 64); 33 | pre = ptr; 34 | } 35 | free(sem); 36 | *__sem = NULL; 37 | return; 38 | } 39 | 40 | 41 | int dyco_semaphore_wait(dyco_semaphore *sem, int timeout) 42 | { 43 | if (sem == NULL) 44 | return -1; 45 | if (sem->semval > 0) { 46 | --sem->semval; 47 | return 0; 48 | } 49 | 50 | if (timeout == 0) { 51 | if (sem->semval > 0) { 52 | --sem->semval; 53 | return 0; 54 | } else { 55 | return -1; 56 | } 57 | } 58 | 59 | dyco_schedule *sched = get_sched(); 60 | if (sched == NULL) { 61 | return -1; 62 | } 63 | dyco_coroutine *co = sched->curr_thread; 64 | if (co == NULL) { 65 | return -1; 66 | } 67 | assert(!TESTBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC)); 68 | 69 | int notifyfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); 70 | DYCO_MUSTNOT(notifyfd == -1); 71 | 72 | dyco_semwait_node *wnode = (dyco_semwait_node*)malloc(sizeof(dyco_semwait_node)); 73 | if (wnode == NULL) { 74 | return -1; 75 | } 76 | wnode->notifyfd = notifyfd; 77 | wnode->next = NULL; 78 | 79 | if (sem->wqueue == NULL) { 80 | sem->wqueue = wnode; 81 | sem->wtail = wnode; 82 | } else { 83 | sem->wtail->next = wnode; 84 | sem->wtail = wnode; 85 | } 86 | 87 | 88 | schedule_sched_waitR(co, notifyfd); 89 | schedule_sched_sleep(co, timeout); 90 | yield(co); 91 | schedule_cancel_sleep(co); 92 | schedule_cancel_wait(co, notifyfd); 93 | 94 | eventfd_t count; 95 | int ret; 96 | ret = eventfd_read(notifyfd, &count); 97 | close(notifyfd); 98 | return ret == 0 && count == 1? 0 : -1; 99 | } 100 | 101 | 102 | int dyco_semaphore_signal(dyco_semaphore *sem) 103 | { 104 | if (sem == NULL) 105 | return -1; 106 | 107 | if (sem->semval == DYCO_SEM_VALUE_MAX) { 108 | return -1; 109 | } 110 | 111 | if (sem->wqueue == NULL) { 112 | ++sem->semval; 113 | return 0; 114 | } 115 | 116 | dyco_schedule *sched = get_sched(); 117 | if (sched == NULL) { 118 | return -1; 119 | } 120 | dyco_coroutine *co = sched->curr_thread; 121 | if (co == NULL) { 122 | return -1; 123 | } 124 | 125 | dyco_semwait_node *head = sem->wqueue; 126 | if (sem->wtail == sem->wqueue) { 127 | sem->wqueue = NULL; 128 | sem->wtail = NULL; 129 | } else { 130 | sem->wqueue = head->next; 131 | } 132 | 133 | sem_notify(head->notifyfd, 1); 134 | free(head); 135 | return 0; 136 | } 137 | -------------------------------------------------------------------------------- /src/dyco_signal.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | int dyco_signal_waitchild(const pid_t child, int *status, int timeout) 4 | { 5 | int ret = waitpid(child, status, WNOHANG | WUNTRACED); 6 | if (timeout == 0 || ret > 0) { 7 | return ret; 8 | } 9 | 10 | dyco_schedule *sched = get_sched(); 11 | if (sched == NULL) { 12 | return -1; 13 | } 14 | dyco_coroutine *co = sched->curr_thread; 15 | if (co == NULL) { 16 | return -1; 17 | } 18 | DYCO_MUSTNOT(TESTBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC)); 19 | 20 | sigset_t sigmask; 21 | DYCO_MUST(sigemptyset(&sigmask) == 0); 22 | DYCO_MUST(sigaddset(&sigmask, SIGCHLD) == 0); 23 | dyco_schedcall_sigprocmask(SIG_BLOCK, &sigmask, &co->old_sigmask); 24 | int sigfd = signalfd(-1, &sigmask, SFD_NONBLOCK); 25 | DYCO_MUSTNOT(sigfd == -1); 26 | 27 | schedule_sched_waitR(co, sigfd); 28 | schedule_sched_sleep(co, timeout); 29 | yield(co); 30 | schedule_cancel_sleep(co); 31 | schedule_cancel_wait(co, sigfd); 32 | 33 | close(sigfd); 34 | return waitpid(child, status, WNOHANG | WUNTRACED); 35 | } 36 | 37 | 38 | int dyco_signal_init(sigset_t *mask) 39 | { 40 | dyco_schedule *sched = get_sched(); 41 | if (sched == NULL) { 42 | return -1; 43 | } 44 | dyco_coroutine *co = sched->curr_thread; 45 | if (co == NULL) { 46 | return -1; 47 | } 48 | 49 | if (TESTBIT(co->status, COROUTINE_FLAGS_WAITSIGNAL)) { 50 | return -1; 51 | } 52 | dyco_schedcall_sigprocmask(SIG_BLOCK, mask, &co->old_sigmask); 53 | int sigfd = signalfd(-1, mask, SFD_NONBLOCK); 54 | DYCO_MUSTNOT(sigfd == -1); 55 | 56 | co->sigfd = sigfd; 57 | SETBIT(co->status, COROUTINE_FLAGS_WAITSIGNAL); 58 | 59 | return 0; 60 | } 61 | 62 | 63 | void dyco_signal_destroy() 64 | { 65 | dyco_schedule *sched = get_sched(); 66 | if (sched == NULL) { 67 | return; 68 | } 69 | dyco_coroutine *co = sched->curr_thread; 70 | if (co == NULL) { 71 | return; 72 | } 73 | if (!TESTBIT(co->status, COROUTINE_FLAGS_WAITSIGNAL)) { 74 | return; 75 | } 76 | 77 | CLRBIT(co->status, COROUTINE_FLAGS_WAITSIGNAL); 78 | close(co->sigfd); 79 | 80 | dyco_schedcall_sigprocmask(SIG_SETMASK, &co->old_sigmask, NULL); 81 | 82 | return; 83 | } 84 | 85 | 86 | int dyco_signal_wait(struct signalfd_siginfo *sinfo, int timeout) 87 | { 88 | dyco_schedule *sched = get_sched(); 89 | if (sched == NULL) { 90 | return -1; 91 | } 92 | dyco_coroutine *co = sched->curr_thread; 93 | if (co == NULL) { 94 | return -1; 95 | } 96 | assert(!TESTBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC)); 97 | if (!TESTBIT(co->status, COROUTINE_FLAGS_WAITSIGNAL)) { 98 | return -1; 99 | } 100 | 101 | int ret; 102 | ret = read(co->sigfd, sinfo, sizeof(struct signalfd_siginfo)); 103 | if (timeout == 0 || ret > 0) { 104 | return ret; 105 | } 106 | 107 | schedule_sched_waitR(co, co->sigfd); 108 | schedule_sched_sleep(co, timeout); 109 | yield(co); 110 | schedule_cancel_sleep(co); 111 | schedule_cancel_wait(co, co->sigfd); 112 | 113 | return read(co->sigfd, sinfo, sizeof(struct signalfd_siginfo)); 114 | } 115 | -------------------------------------------------------------------------------- /src/dyco_socket.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | #include 3 | 4 | #define TIMEOUT_DEFAULT 3000 5 | #define TIMEOUT_INFINIT -1 6 | #define TIMEOUT_NONE 0 7 | 8 | int 9 | dyco_socket(int domain, int type, int protocol) 10 | { 11 | int fd = socket_f(domain, type, protocol); 12 | if (fd == -1) { 13 | // printf("Failed to create a new socket\n"); 14 | return -1; 15 | } 16 | int ret = fcntl(fd, F_SETFL, O_NONBLOCK); 17 | if (ret == -1) { 18 | close(ret); 19 | return -1; 20 | } 21 | int reuse = 1; 22 | ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)); 23 | DYCO_MUST(ret == 0); 24 | return fd; 25 | } 26 | 27 | int 28 | dyco_accept(int fd, struct sockaddr *addr, socklen_t *len) 29 | { 30 | int sockfd = -1; 31 | int timeout = TIMEOUT_INFINIT; 32 | 33 | while (1) 34 | { 35 | waitev(fd, EPOLLIN | EPOLLERR | EPOLLHUP, timeout); 36 | 37 | sockfd = accept_f(fd, addr, len); 38 | if (sockfd < 0) 39 | { 40 | if (errno == EAGAIN) 41 | { 42 | continue; 43 | } 44 | 45 | DYCO_WARNIF(errno == ECONNABORTED, "ECONNABORTED"); 46 | DYCO_WARNIF(errno == EMFILE, "EMFILE"); 47 | DYCO_WARNIF(errno == ENFILE, "ENFILE"); 48 | return -1; 49 | } 50 | else 51 | { 52 | break; 53 | } 54 | } 55 | 56 | int ret = fcntl(sockfd, F_SETFL, O_NONBLOCK); 57 | if (ret == -1) 58 | { 59 | close(sockfd); 60 | return -1; 61 | } 62 | int reuse = 1; 63 | ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)); 64 | DYCO_MUST(ret == 0); 65 | 66 | return sockfd; 67 | } 68 | 69 | int 70 | dyco_connect(int fd, struct sockaddr *name, socklen_t namelen) 71 | { 72 | 73 | int ret = 0; 74 | int timeout = TIMEOUT_DEFAULT; 75 | 76 | while (1) 77 | { 78 | waitev(fd, EPOLLOUT | EPOLLERR | EPOLLHUP, timeout); 79 | 80 | ret = connect_f(fd, name, namelen); 81 | if (ret == 0) 82 | break; 83 | 84 | if (ret == -1 && (errno == EAGAIN || 85 | errno == EWOULDBLOCK || 86 | errno == EINPROGRESS)) 87 | { 88 | continue; 89 | } 90 | else 91 | { 92 | break; 93 | } 94 | } 95 | 96 | return ret; 97 | } 98 | 99 | ssize_t 100 | dyco_recv(int fd, void *buf, size_t len, int flags) 101 | { 102 | int timeout = TIMEOUT_DEFAULT; 103 | 104 | waitev(fd, EPOLLIN | EPOLLERR | EPOLLHUP, timeout); 105 | 106 | int ret = recv_f(fd, buf, len, flags); 107 | 108 | return ret; 109 | } 110 | 111 | ssize_t 112 | dyco_recvfrom(int fd, void *buf, size_t len, int flags, 113 | struct sockaddr *src_addr, socklen_t *addrlen) 114 | { 115 | int timeout = TIMEOUT_DEFAULT; 116 | 117 | waitev(fd, EPOLLIN | EPOLLERR | EPOLLHUP, timeout); 118 | 119 | int ret = recvfrom_f(fd, buf, len, flags, src_addr, addrlen); 120 | return ret; 121 | } 122 | 123 | ssize_t 124 | dyco_send(int fd, const void *buf, size_t len, int flags) 125 | { 126 | int timeout = TIMEOUT_INFINIT; 127 | int sent = 0; 128 | 129 | int ret = send_f(fd, ((char *)buf) + sent, len - sent, flags); 130 | if (ret == 0) 131 | return ret; 132 | if (ret > 0) 133 | sent += ret; 134 | 135 | while (sent < len) 136 | { 137 | waitev(fd, EPOLLOUT | EPOLLERR | EPOLLHUP, timeout); 138 | 139 | ret = send_f(fd, ((char *)buf) + sent, len - sent, flags); 140 | if (ret <= 0) 141 | { 142 | if (errno == EAGAIN) 143 | continue; 144 | else if (errno == ECONNRESET) 145 | { 146 | return ret; 147 | } 148 | else { 149 | // printf("send() errno : %d, ret : %d\n", errno, ret); 150 | break; 151 | } 152 | } 153 | sent += ret; 154 | } 155 | 156 | if (ret <= 0 && sent == 0) 157 | return ret; 158 | 159 | return sent; 160 | } 161 | 162 | ssize_t 163 | dyco_sendto(int fd, const void *buf, size_t len, int flags, 164 | const struct sockaddr *dest_addr, socklen_t addrlen) 165 | { 166 | int timeout = TIMEOUT_INFINIT; 167 | int sent = 0; 168 | 169 | int ret = sendto_f(fd, ((char *)buf) + sent, len - sent, flags, dest_addr, addrlen); 170 | if (ret == 0) 171 | return ret; 172 | if (ret > 0) 173 | sent += ret; 174 | 175 | while (sent < len) 176 | { 177 | waitev(fd, EPOLLOUT | EPOLLERR | EPOLLHUP, timeout); 178 | 179 | ret = sendto_f(fd, ((char *)buf) + sent, len - sent, flags, dest_addr, addrlen); 180 | if (ret <= 0) 181 | { 182 | if (errno == EAGAIN) 183 | continue; 184 | else if (errno == ECONNRESET) 185 | { 186 | return ret; 187 | } 188 | else { 189 | // printf("sendto() errno : %d, ret : %d\n", errno, ret); 190 | break; 191 | } 192 | } 193 | sent += ret; 194 | } 195 | 196 | if (ret <= 0 && sent == 0) 197 | return ret; 198 | 199 | return sent; 200 | } 201 | 202 | int 203 | dyco_close(int fd) 204 | { 205 | return close(fd); 206 | } 207 | 208 | #ifdef COROUTINE_HOOK 209 | 210 | int 211 | socket(int domain, int type, int protocol) 212 | { 213 | int fd = socket_f(domain, type, protocol); 214 | if (fd == -1) 215 | { 216 | // printf("Failed to create a new socket\n"); 217 | return -1; 218 | } 219 | int ret = fcntl(fd, F_SETFL, O_NONBLOCK); 220 | if (ret == -1) 221 | { 222 | close(ret); 223 | return -1; 224 | } 225 | int reuse = 1; 226 | ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)); 227 | DYCO_MUST(ret == 0); 228 | return fd; 229 | } 230 | 231 | 232 | int 233 | accept(int fd, struct sockaddr *addr, socklen_t *len) 234 | { 235 | int sockfd = -1; 236 | int timeout = TIMEOUT_INFINIT; 237 | 238 | while (1) 239 | { 240 | waitev(fd, EPOLLIN | EPOLLERR | EPOLLHUP, timeout); 241 | 242 | sockfd = accept_f(fd, addr, len); 243 | if (sockfd < 0) 244 | { 245 | if (errno == EAGAIN) 246 | { 247 | continue; 248 | } 249 | DYCO_WARNIF(errno == ECONNABORTED, "ECONNABORTED"); 250 | DYCO_WARNIF(errno == EMFILE, "EMFILE"); 251 | DYCO_WARNIF(errno == ENFILE, "ENFILE"); 252 | return -1; 253 | } 254 | else 255 | { 256 | break; 257 | } 258 | } 259 | 260 | int ret = fcntl(sockfd, F_SETFL, O_NONBLOCK); 261 | if (ret == -1) 262 | { 263 | close(sockfd); 264 | return -1; 265 | } 266 | int reuse = 1; 267 | ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)); 268 | DYCO_MUST(ret == 0); 269 | 270 | return sockfd; 271 | } 272 | 273 | 274 | int 275 | connect(int fd, const struct sockaddr *addr, socklen_t addrlen) 276 | { 277 | int ret = 0; 278 | int timeout = TIMEOUT_DEFAULT; 279 | 280 | while (1) 281 | { 282 | waitev(fd, EPOLLOUT | EPOLLERR | EPOLLHUP, timeout); 283 | 284 | ret = connect_f(fd, addr, addrlen); 285 | if (ret == 0) 286 | break; 287 | 288 | if (ret == -1 && (errno == EAGAIN || 289 | errno == EWOULDBLOCK || 290 | errno == EINPROGRESS)) 291 | { 292 | continue; 293 | } 294 | else 295 | { 296 | break; 297 | } 298 | } 299 | 300 | return ret; 301 | } 302 | 303 | ssize_t 304 | recv(int fd, void *buf, size_t len, int flags) 305 | { 306 | int timeout = TIMEOUT_DEFAULT; 307 | 308 | waitev(fd, EPOLLIN | EPOLLERR | EPOLLHUP, timeout); 309 | 310 | int ret = recv_f(fd, buf, len, flags); 311 | 312 | return ret; 313 | } 314 | 315 | ssize_t 316 | recvfrom(int fd, void *buf, size_t len, int flags, 317 | struct sockaddr *src_addr, socklen_t *addrlen) 318 | { 319 | int timeout = TIMEOUT_DEFAULT; 320 | 321 | waitev(fd, EPOLLIN | EPOLLERR | EPOLLHUP, timeout); 322 | 323 | int ret = recvfrom_f(fd, buf, len, flags, src_addr, addrlen); 324 | return ret; 325 | } 326 | 327 | ssize_t 328 | send(int fd, const void *buf, size_t len, int flags) 329 | { 330 | int timeout = TIMEOUT_INFINIT; 331 | int sent = 0; 332 | 333 | int ret = send_f(fd, ((char *)buf) + sent, len - sent, flags); 334 | if (ret == 0) 335 | return ret; 336 | if (ret > 0) 337 | sent += ret; 338 | 339 | while (sent < len) 340 | { 341 | waitev(fd, EPOLLOUT | EPOLLERR | EPOLLHUP, timeout); 342 | 343 | ret = send_f(fd, ((char *)buf) + sent, len - sent, flags); 344 | if (ret <= 0) 345 | { 346 | if (errno == EAGAIN) 347 | continue; 348 | else if (errno == ECONNRESET) 349 | { 350 | return ret; 351 | } 352 | else { 353 | // printf("send() errno : %d, ret : %d\n", errno, ret); 354 | break; 355 | } 356 | } 357 | sent += ret; 358 | } 359 | 360 | if (ret <= 0 && sent == 0) 361 | return ret; 362 | 363 | return sent; 364 | } 365 | 366 | ssize_t 367 | sendto(int fd, const void *buf, size_t len, int flags, 368 | const struct sockaddr *dest_addr, socklen_t addrlen) 369 | { 370 | int timeout = TIMEOUT_INFINIT; 371 | int sent = 0; 372 | 373 | int ret = sendto_f(fd, ((char *)buf) + sent, len - sent, flags, dest_addr, addrlen); 374 | if (ret == 0) 375 | return ret; 376 | if (ret > 0) 377 | sent += ret; 378 | 379 | while (sent < len) 380 | { 381 | waitev(fd, EPOLLOUT | EPOLLERR | EPOLLHUP, timeout); 382 | 383 | ret = sendto_f(fd, ((char *)buf) + sent, len - sent, flags, dest_addr, addrlen); 384 | if (ret <= 0) 385 | { 386 | if (errno == EAGAIN) 387 | continue; 388 | else if (errno == ECONNRESET) 389 | { 390 | return ret; 391 | } 392 | else { 393 | // printf("sendto() errno : %d, ret : %d\n", errno, ret); 394 | break; 395 | } 396 | } 397 | sent += ret; 398 | } 399 | 400 | if (ret <= 0 && sent == 0) 401 | return ret; 402 | 403 | return sent; 404 | } 405 | 406 | 407 | int 408 | close(int fd) 409 | { 410 | return close_f(fd); 411 | } 412 | 413 | 414 | #endif 415 | -------------------------------------------------------------------------------- /src/dyco_ssl.c: -------------------------------------------------------------------------------- 1 | #include "dyco/dyco_coroutine.h" 2 | 3 | #ifdef DYCO_SSL_OK 4 | #ifdef DYCO_SSL_ENABLE 5 | 6 | #define SSL_TIMEOUT_DEFAULT 1000 7 | 8 | int 9 | dyco_SSL_accept(SSL *ssl) 10 | { 11 | int ret, err; 12 | int fd = SSL_get_fd(ssl); 13 | SSL_set_accept_state(ssl); 14 | 15 | label: 16 | if (dyco_coroutine_waitRW(fd, SSL_TIMEOUT_DEFAULT) <= 0) { 17 | return -1; 18 | } 19 | ret = SSL_accept(ssl); 20 | if(ret != 1) 21 | { 22 | err = SSL_get_error(ssl, ret); 23 | if ((err == SSL_ERROR_WANT_WRITE) || (err == SSL_ERROR_WANT_READ)) 24 | goto label; 25 | else 26 | return ret; 27 | } 28 | return 1; 29 | } 30 | 31 | 32 | int 33 | dyco_SSL_connect(SSL *ssl) 34 | { 35 | int ret, err; 36 | int fd = SSL_get_fd(ssl); 37 | SSL_set_connect_state(ssl); 38 | 39 | label: 40 | if (dyco_coroutine_waitRW(fd, SSL_TIMEOUT_DEFAULT) <= 0) { 41 | return -1; 42 | } 43 | ret = SSL_connect(ssl); 44 | if(ret == -1) 45 | { 46 | err = SSL_get_error(ssl, ret); 47 | if ((err == SSL_ERROR_WANT_WRITE) || (err == SSL_ERROR_WANT_READ)) 48 | goto label; 49 | else 50 | return -1; 51 | } 52 | return 1; 53 | } 54 | 55 | 56 | int 57 | dyco_SSL_read(SSL *ssl, void *buf, int num) 58 | { 59 | int ret, err; 60 | int fd = SSL_get_fd(ssl); 61 | 62 | label: 63 | if (dyco_coroutine_waitRead(fd, -1) <= 0) { 64 | return -1; 65 | } 66 | ret = SSL_read(ssl, buf, num); 67 | err = SSL_get_error(ssl, ret); 68 | if(err == SSL_ERROR_NONE) 69 | { 70 | return num; 71 | } 72 | else if (err == SSL_ERROR_WANT_READ) 73 | { 74 | goto label; 75 | } 76 | 77 | return ret; 78 | } 79 | 80 | 81 | int 82 | dyco_SSL_write(SSL *ssl, const void *buf, int num) 83 | { 84 | int ret, err; 85 | int fd = SSL_get_fd(ssl); 86 | 87 | label: 88 | if (dyco_coroutine_waitWrite(fd, SSL_TIMEOUT_DEFAULT) <= 0) { 89 | return -1; 90 | } 91 | ret = SSL_write(ssl, buf, num); 92 | err = SSL_get_error(ssl, ret); 93 | if(err == SSL_ERROR_NONE) 94 | { 95 | return num; 96 | } 97 | else if (err == SSL_ERROR_WANT_WRITE) 98 | { 99 | goto label; 100 | } 101 | 102 | return ret; 103 | } 104 | 105 | #endif 106 | #endif 107 | -------------------------------------------------------------------------------- /src/dyco_waitgroup.c: -------------------------------------------------------------------------------- 1 | #ifndef DYCO_WAITGROUP_H 2 | #define DYCO_WAITGROUP_H 3 | 4 | #include "dyco/dyco_coroutine.h" 5 | 6 | static void 7 | wg_notify(int notifyfd, int finished_num) 8 | { 9 | DYCO_MUST(eventfd_write(notifyfd, (eventfd_t)finished_num) == 0); 10 | return; 11 | } 12 | 13 | void 14 | wgsublist_free(void *head) 15 | { 16 | dyco_sublist *ptr = head; 17 | dyco_sublist *next; 18 | while (ptr != NULL) { 19 | next = ptr->next; 20 | close(ptr->notifyfd); 21 | free(ptr); 22 | ptr = next; 23 | } 24 | return; 25 | } 26 | 27 | dyco_waitgroup* 28 | dyco_waitgroup_create(int suggest_size) 29 | { 30 | dyco_waitgroup *wg = (dyco_waitgroup*)malloc(sizeof(dyco_waitgroup)); 31 | if (wg == NULL) 32 | return NULL; 33 | wg->tot_size = 0; 34 | wg->finished = 0; 35 | 36 | int width = 1; 37 | if (suggest_size <= 0) { 38 | width = DYCO_HTABLE_DEFAULTWITDH; 39 | } 40 | else if (suggest_size > 65536) { 41 | width = DYCO_HTABLE_MAXWITDH; 42 | } 43 | else { 44 | while ((suggest_size >> width) != 0) ++width; 45 | } 46 | htable_init(&wg->cid_set, width); 47 | htable_init(&wg->target_sublist_map, width); 48 | wg->final_sublist = NULL; 49 | return wg; 50 | } 51 | 52 | 53 | void 54 | dyco_waitgroup_destroy(dyco_waitgroup** group) 55 | { 56 | dyco_waitgroup *wg = *group; 57 | if (wg == NULL) { 58 | return; 59 | } 60 | wgsublist_free(wg->final_sublist); 61 | htable_clear_with_freecb(&wg->target_sublist_map, wgsublist_free); 62 | htable_clear(&wg->cid_set); 63 | free(wg); 64 | *group = NULL; 65 | return; 66 | } 67 | 68 | 69 | int 70 | dyco_waitgroup_add(dyco_waitgroup* group, int cid) 71 | { 72 | if (group == NULL) 73 | return -1; 74 | int ret = htable_insert(&group->cid_set, cid, NULL); 75 | if (ret != 1) 76 | return 0; 77 | ++(group->tot_size); 78 | return 1; 79 | } 80 | 81 | 82 | int 83 | dyco_waitgroup_done(dyco_waitgroup* group) 84 | { 85 | if (group == NULL) 86 | return -1; 87 | 88 | dyco_schedule *sched = get_sched(); 89 | if (sched == NULL) { 90 | return -1; 91 | } 92 | dyco_coroutine *co = sched->curr_thread; 93 | if (co == NULL) { 94 | return -1; 95 | } 96 | int ret = htable_contains(&group->cid_set, co->cid); 97 | if (ret != 1) { 98 | return 0; 99 | } 100 | 101 | ++(group->finished); 102 | // notify target subscribe list 103 | dyco_sublist *tslist = htable_find(&group->target_sublist_map, group->finished); 104 | if (tslist != NULL) { 105 | dyco_sublist *ptr = tslist; 106 | while (ptr != NULL) { 107 | wg_notify(ptr->notifyfd, group->finished); 108 | ptr = ptr->next; 109 | } 110 | } 111 | 112 | // notify finnal list 113 | if (group->finished == group->tot_size) { 114 | dyco_sublist *ptr = group->final_sublist; 115 | while (ptr != NULL) { 116 | wg_notify(ptr->notifyfd, group->finished); 117 | ptr = ptr->next; 118 | } 119 | } 120 | 121 | return 1; 122 | } 123 | 124 | 125 | int 126 | dyco_waitgroup_wait(dyco_waitgroup* group, int target, int timeout) 127 | { 128 | if (group == NULL) { 129 | return -1; 130 | } 131 | 132 | if (timeout == 0) { 133 | return group->finished; 134 | } 135 | 136 | dyco_schedule *sched = get_sched(); 137 | if (sched == NULL) { 138 | return -1; 139 | } 140 | dyco_coroutine *co = sched->curr_thread; 141 | if (co == NULL) { 142 | return -1; 143 | } 144 | assert(!TESTBIT(co->status, COROUTINE_FLAGS_ASYMMETRIC)); 145 | 146 | eventfd_t count; 147 | int ret; 148 | 149 | if (target <= 0) { 150 | // wait until all tasks finishes 151 | if (group->finished == group->tot_size) 152 | return group->finished; 153 | 154 | int notifyfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); 155 | DYCO_MUSTNOT(notifyfd == -1); 156 | 157 | dyco_sublist* sub = (dyco_sublist*)malloc(sizeof(dyco_sublist)); 158 | if (sub == NULL) { 159 | close(notifyfd); 160 | return -1; 161 | } 162 | sub->notifyfd = notifyfd; 163 | sub->next = NULL; 164 | 165 | if (group->final_sublist == NULL) { 166 | group->final_sublist = sub; 167 | } else { 168 | sub->next = group->final_sublist->next; 169 | group->final_sublist->next = sub; 170 | } 171 | 172 | schedule_sched_waitR(co, notifyfd); 173 | schedule_sched_sleep(co, timeout); 174 | yield(co); 175 | schedule_cancel_sleep(co); 176 | schedule_cancel_wait(co, notifyfd); 177 | 178 | ret = eventfd_read(notifyfd, &count); 179 | 180 | dyco_sublist* pre = group->final_sublist; 181 | dyco_sublist* ptr = pre->next; 182 | if (pre->notifyfd == notifyfd) { 183 | group->final_sublist = ptr; 184 | close(pre->notifyfd); 185 | free(pre); 186 | } else { 187 | while (ptr != NULL) { 188 | if (ptr->notifyfd == notifyfd) { 189 | pre->next = ptr->next; 190 | close(ptr->notifyfd); 191 | free(ptr); 192 | break; 193 | } 194 | pre = ptr; 195 | ptr = ptr->next; 196 | } 197 | } 198 | } else { 199 | // wait until target tasks finishes 200 | if (group->finished >= target) 201 | return target; 202 | 203 | int notifyfd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); 204 | DYCO_MUSTNOT(notifyfd == -1); 205 | 206 | dyco_sublist* sub = (dyco_sublist*)malloc(sizeof(dyco_sublist)); 207 | if (sub == NULL) { 208 | close(notifyfd); 209 | return -1; 210 | } 211 | 212 | sub->notifyfd = notifyfd; 213 | sub->next = NULL; 214 | 215 | dyco_sublist* sublist = htable_find(&group->target_sublist_map, target); 216 | sub->next = sublist; 217 | htable_insert(&group->target_sublist_map, target, sub); 218 | 219 | schedule_sched_waitR(co, notifyfd); 220 | schedule_sched_sleep(co, timeout); 221 | yield(co); 222 | schedule_cancel_sleep(co); 223 | schedule_cancel_wait(co, notifyfd); 224 | 225 | ret = eventfd_read(notifyfd, &count); 226 | 227 | dyco_sublist* pre = htable_find(&group->target_sublist_map, target); 228 | dyco_sublist* ptr = pre->next; 229 | if (pre->notifyfd == notifyfd) { 230 | if (ptr != NULL) 231 | htable_insert(&group->target_sublist_map, target, ptr); 232 | else 233 | htable_delete(&group->target_sublist_map, target, NULL); 234 | close(pre->notifyfd); 235 | free(pre); 236 | } else { 237 | while (ptr != NULL) { 238 | if (ptr->notifyfd == notifyfd) { 239 | pre->next = ptr->next; 240 | close(ptr->notifyfd); 241 | free(ptr); 242 | break; 243 | } 244 | pre = ptr; 245 | ptr = ptr->next; 246 | } 247 | } 248 | } 249 | if (ret == 0) 250 | return (int)(count); 251 | else 252 | return -1; 253 | } 254 | 255 | #endif -------------------------------------------------------------------------------- /src/uctx_asm.S: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2005-2006 Russ Cox, MIT; see COPYRIGHT */ 2 | 3 | #if defined(__FreeBSD__) && defined(__i386__) && __FreeBSD__ < 5 4 | #define NEEDX86CONTEXT 1 5 | #define SET setmcontext 6 | #define GET getmcontext 7 | #endif 8 | 9 | #if defined(__OpenBSD__) && defined(__i386__) 10 | #define NEEDX86CONTEXT 1 11 | #define SET setmcontext 12 | #define GET getmcontext 13 | #endif 14 | 15 | #if defined(__APPLE__) 16 | #if defined(__i386__) 17 | #define NEEDX86CONTEXT 1 18 | #define SET _setmcontext 19 | #define GET _getmcontext 20 | #elif defined(__x86_64__) 21 | #define NEEDAMD64CONTEXT 1 22 | #define SET _setmcontext 23 | #define GET _getmcontext 24 | #else 25 | #define NEEDPOWERCONTEXT 1 26 | #define SET __setmcontext 27 | #define GET __getmcontext 28 | #endif 29 | #endif 30 | 31 | #if defined(__linux__) && defined(__arm__) 32 | #define NEEDARMCONTEXT 1 33 | #define SET setmcontext 34 | #define GET getmcontext 35 | #endif 36 | 37 | #if defined(__linux__) && defined(__mips__) 38 | #define NEEDMIPSCONTEXT 1 39 | #define SET setmcontext 40 | #define GET getmcontext 41 | #endif 42 | 43 | #ifdef NEEDX86CONTEXT 44 | .globl SET 45 | SET: 46 | movl 4(%esp), %eax 47 | 48 | movl 8(%eax), %fs 49 | movl 12(%eax), %es 50 | movl 16(%eax), %ds 51 | movl 76(%eax), %ss 52 | movl 20(%eax), %edi 53 | movl 24(%eax), %esi 54 | movl 28(%eax), %ebp 55 | movl 36(%eax), %ebx 56 | movl 40(%eax), %edx 57 | movl 44(%eax), %ecx 58 | 59 | movl 72(%eax), %esp 60 | pushl 60(%eax) /* new %eip */ 61 | movl 48(%eax), %eax 62 | ret 63 | 64 | .globl GET 65 | GET: 66 | movl 4(%esp), %eax 67 | 68 | movl %fs, 8(%eax) 69 | movl %es, 12(%eax) 70 | movl %ds, 16(%eax) 71 | movl %ss, 76(%eax) 72 | movl %edi, 20(%eax) 73 | movl %esi, 24(%eax) 74 | movl %ebp, 28(%eax) 75 | movl %ebx, 36(%eax) 76 | movl %edx, 40(%eax) 77 | movl %ecx, 44(%eax) 78 | 79 | movl $1, 48(%eax) /* %eax */ 80 | movl (%esp), %ecx /* %eip */ 81 | movl %ecx, 60(%eax) 82 | leal 4(%esp), %ecx /* %esp */ 83 | movl %ecx, 72(%eax) 84 | 85 | movl 44(%eax), %ecx /* restore %ecx */ 86 | movl $0, %eax 87 | ret 88 | #endif 89 | 90 | #ifdef NEEDAMD64CONTEXT 91 | .globl SET 92 | SET: 93 | movq 16(%rdi), %rsi 94 | movq 24(%rdi), %rdx 95 | movq 32(%rdi), %rcx 96 | movq 40(%rdi), %r8 97 | movq 48(%rdi), %r9 98 | movq 56(%rdi), %rax 99 | movq 64(%rdi), %rbx 100 | movq 72(%rdi), %rbp 101 | movq 80(%rdi), %r10 102 | movq 88(%rdi), %r11 103 | movq 96(%rdi), %r12 104 | movq 104(%rdi), %r13 105 | movq 112(%rdi), %r14 106 | movq 120(%rdi), %r15 107 | movq 184(%rdi), %rsp 108 | pushq 160(%rdi) /* new %eip */ 109 | movq 8(%rdi), %rdi 110 | ret 111 | 112 | .globl GET 113 | GET: 114 | movq %rdi, 8(%rdi) 115 | movq %rsi, 16(%rdi) 116 | movq %rdx, 24(%rdi) 117 | movq %rcx, 32(%rdi) 118 | movq %r8, 40(%rdi) 119 | movq %r9, 48(%rdi) 120 | movq $1, 56(%rdi) /* %rax */ 121 | movq %rbx, 64(%rdi) 122 | movq %rbp, 72(%rdi) 123 | movq %r10, 80(%rdi) 124 | movq %r11, 88(%rdi) 125 | movq %r12, 96(%rdi) 126 | movq %r13, 104(%rdi) 127 | movq %r14, 112(%rdi) 128 | movq %r15, 120(%rdi) 129 | 130 | movq (%rsp), %rcx /* %rip */ 131 | movq %rcx, 160(%rdi) 132 | leaq 8(%rsp), %rcx /* %rsp */ 133 | movq %rcx, 184(%rdi) 134 | 135 | movq 32(%rdi), %rcx /* restore %rcx */ 136 | movq $0, %rax 137 | ret 138 | #endif 139 | 140 | #ifdef NEEDPOWERCONTEXT 141 | /* get FPR and VR use flags with sc 0x7FF3 */ 142 | /* get vsave with mfspr reg, 256 */ 143 | 144 | .text 145 | .align 2 146 | 147 | .globl GET 148 | GET: /* xxx: instruction scheduling */ 149 | mflr r0 150 | mfcr r5 151 | mfctr r6 152 | mfxer r7 153 | stw r0, 0*4(r3) 154 | stw r5, 1*4(r3) 155 | stw r6, 2*4(r3) 156 | stw r7, 3*4(r3) 157 | 158 | stw r1, 4*4(r3) 159 | stw r2, 5*4(r3) 160 | li r5, 1 /* return value for setmcontext */ 161 | stw r5, 6*4(r3) 162 | 163 | stw r13, (0+7)*4(r3) /* callee-save GPRs */ 164 | stw r14, (1+7)*4(r3) /* xxx: block move */ 165 | stw r15, (2+7)*4(r3) 166 | stw r16, (3+7)*4(r3) 167 | stw r17, (4+7)*4(r3) 168 | stw r18, (5+7)*4(r3) 169 | stw r19, (6+7)*4(r3) 170 | stw r20, (7+7)*4(r3) 171 | stw r21, (8+7)*4(r3) 172 | stw r22, (9+7)*4(r3) 173 | stw r23, (10+7)*4(r3) 174 | stw r24, (11+7)*4(r3) 175 | stw r25, (12+7)*4(r3) 176 | stw r26, (13+7)*4(r3) 177 | stw r27, (14+7)*4(r3) 178 | stw r28, (15+7)*4(r3) 179 | stw r29, (16+7)*4(r3) 180 | stw r30, (17+7)*4(r3) 181 | stw r31, (18+7)*4(r3) 182 | 183 | li r3, 0 /* return */ 184 | blr 185 | 186 | .globl SET 187 | SET: 188 | lwz r13, (0+7)*4(r3) /* callee-save GPRs */ 189 | lwz r14, (1+7)*4(r3) /* xxx: block move */ 190 | lwz r15, (2+7)*4(r3) 191 | lwz r16, (3+7)*4(r3) 192 | lwz r17, (4+7)*4(r3) 193 | lwz r18, (5+7)*4(r3) 194 | lwz r19, (6+7)*4(r3) 195 | lwz r20, (7+7)*4(r3) 196 | lwz r21, (8+7)*4(r3) 197 | lwz r22, (9+7)*4(r3) 198 | lwz r23, (10+7)*4(r3) 199 | lwz r24, (11+7)*4(r3) 200 | lwz r25, (12+7)*4(r3) 201 | lwz r26, (13+7)*4(r3) 202 | lwz r27, (14+7)*4(r3) 203 | lwz r28, (15+7)*4(r3) 204 | lwz r29, (16+7)*4(r3) 205 | lwz r30, (17+7)*4(r3) 206 | lwz r31, (18+7)*4(r3) 207 | 208 | lwz r1, 4*4(r3) 209 | lwz r2, 5*4(r3) 210 | 211 | lwz r0, 0*4(r3) 212 | mtlr r0 213 | lwz r0, 1*4(r3) 214 | mtcr r0 /* mtcrf 0xFF, r0 */ 215 | lwz r0, 2*4(r3) 216 | mtctr r0 217 | lwz r0, 3*4(r3) 218 | mtxer r0 219 | 220 | lwz r3, 6*4(r3) 221 | blr 222 | #endif 223 | 224 | #ifdef NEEDARMCONTEXT 225 | .globl GET 226 | GET: 227 | str r1, [r0,#4] 228 | str r2, [r0,#8] 229 | str r3, [r0,#12] 230 | str r4, [r0,#16] 231 | str r5, [r0,#20] 232 | str r6, [r0,#24] 233 | str r7, [r0,#28] 234 | str r8, [r0,#32] 235 | str r9, [r0,#36] 236 | str r10, [r0,#40] 237 | str r11, [r0,#44] 238 | str r12, [r0,#48] 239 | str r13, [r0,#52] 240 | str r14, [r0,#56] 241 | /* store 1 as r0-to-restore */ 242 | mov r1, #1 243 | str r1, [r0] 244 | /* return 0 */ 245 | mov r0, #0 246 | mov pc, lr 247 | 248 | .globl SET 249 | SET: 250 | ldr r1, [r0,#4] 251 | ldr r2, [r0,#8] 252 | ldr r3, [r0,#12] 253 | ldr r4, [r0,#16] 254 | ldr r5, [r0,#20] 255 | ldr r6, [r0,#24] 256 | ldr r7, [r0,#28] 257 | ldr r8, [r0,#32] 258 | ldr r9, [r0,#36] 259 | ldr r10, [r0,#40] 260 | ldr r11, [r0,#44] 261 | ldr r12, [r0,#48] 262 | ldr r13, [r0,#52] 263 | ldr r14, [r0,#56] 264 | ldr r0, [r0] 265 | mov pc, lr 266 | #endif 267 | 268 | #ifdef NEEDMIPSCONTEXT 269 | .globl GET 270 | GET: 271 | sw $4, 24($4) 272 | sw $5, 28($4) 273 | sw $6, 32($4) 274 | sw $7, 36($4) 275 | 276 | sw $16, 72($4) 277 | sw $17, 76($4) 278 | sw $18, 80($4) 279 | sw $19, 84($4) 280 | sw $20, 88($4) 281 | sw $21, 92($4) 282 | sw $22, 96($4) 283 | sw $23, 100($4) 284 | 285 | sw $28, 120($4) /* gp */ 286 | sw $29, 124($4) /* sp */ 287 | sw $30, 128($4) /* fp */ 288 | sw $31, 132($4) /* ra */ 289 | 290 | xor $2, $2, $2 291 | j $31 292 | nop 293 | 294 | .globl SET 295 | SET: 296 | lw $16, 72($4) 297 | lw $17, 76($4) 298 | lw $18, 80($4) 299 | lw $19, 84($4) 300 | lw $20, 88($4) 301 | lw $21, 92($4) 302 | lw $22, 96($4) 303 | lw $23, 100($4) 304 | 305 | lw $28, 120($4) /* gp */ 306 | lw $29, 124($4) /* sp */ 307 | lw $30, 128($4) /* fp */ 308 | 309 | /* 310 | * If we set $31 directly and j $31, 311 | * we would loose the outer return address. 312 | * Use a temporary register, then. 313 | */ 314 | lw $8, 132($4) /* ra */ 315 | 316 | /* bug: not setting the pc causes a bus error */ 317 | lw $25, 132($4) /* pc */ 318 | 319 | lw $5, 28($4) 320 | lw $6, 32($4) 321 | lw $7, 36($4) 322 | lw $4, 24($4) 323 | 324 | j $8 325 | nop 326 | #endif 327 | -------------------------------------------------------------------------------- /src/uctx_context.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2005-2006 Russ Cox, MIT; see COPYRIGHT */ 2 | 3 | #include "dyco/dyco_ucontext.h" 4 | 5 | #if defined(__APPLE__) 6 | #if defined(__i386__) 7 | #define NEEDX86MAKECONTEXT 8 | #define NEEDSWAPCONTEXT 9 | #elif defined(__x86_64__) 10 | #define NEEDAMD64MAKECONTEXT 11 | #define NEEDSWAPCONTEXT 12 | #else 13 | #define NEEDPOWERMAKECONTEXT 14 | #define NEEDSWAPCONTEXT 15 | #endif 16 | #endif 17 | 18 | #if defined(__FreeBSD__) && defined(__i386__) && __FreeBSD__ < 5 19 | #define NEEDX86MAKECONTEXT 20 | #define NEEDSWAPCONTEXT 21 | #endif 22 | 23 | #if defined(__OpenBSD__) && defined(__i386__) 24 | #define NEEDX86MAKECONTEXT 25 | #define NEEDSWAPCONTEXT 26 | #endif 27 | 28 | // #if defined(__linux__) && defined(__arm__) 29 | // #define NEEDSWAPCONTEXT 30 | // #define NEEDARMMAKECONTEXT 31 | // #endif 32 | 33 | #if defined(__linux__) && defined(__mips__) 34 | #define NEEDSWAPCONTEXT 35 | #define NEEDMIPSMAKECONTEXT 36 | #endif 37 | 38 | #ifdef NEEDPOWERMAKECONTEXT 39 | void 40 | makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) 41 | { 42 | ulong *sp, *tos; 43 | va_list arg; 44 | 45 | tos = (ulong*)ucp->uc_stack.ss_sp+ucp->uc_stack.ss_size/sizeof(ulong); 46 | sp = tos - 16; 47 | ucp->mc.pc = (long)func; 48 | ucp->mc.sp = (long)sp; 49 | va_start(arg, argc); 50 | ucp->mc.r3 = va_arg(arg, long); 51 | va_end(arg); 52 | } 53 | #endif 54 | 55 | #ifdef NEEDX86MAKECONTEXT 56 | void 57 | makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) 58 | { 59 | int *sp; 60 | 61 | sp = (int*)ucp->uc_stack.ss_sp+ucp->uc_stack.ss_size/4; 62 | sp -= argc; 63 | sp = (void*)((uintptr_t)sp - (uintptr_t)sp%16); /* 16-align for OS X */ 64 | memmove(sp, &argc+1, argc*sizeof(int)); 65 | 66 | *--sp = 0; /* return address */ 67 | ucp->uc_mcontext.mc_eip = (long)func; 68 | ucp->uc_mcontext.mc_esp = (int)sp; 69 | } 70 | #endif 71 | 72 | #ifdef NEEDAMD64MAKECONTEXT 73 | void 74 | makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) 75 | { 76 | long *sp; 77 | va_list va; 78 | 79 | memset(&ucp->uc_mcontext, 0, sizeof ucp->uc_mcontext); 80 | if(argc != 2) 81 | *(int*)0 = 0; 82 | va_start(va, argc); 83 | ucp->uc_mcontext.mc_rdi = va_arg(va, int); 84 | ucp->uc_mcontext.mc_rsi = va_arg(va, int); 85 | va_end(va); 86 | sp = (long*)ucp->uc_stack.ss_sp+ucp->uc_stack.ss_size/sizeof(long); 87 | sp -= argc; 88 | sp = (void*)((uintptr_t)sp - (uintptr_t)sp%16); /* 16-align for OS X */ 89 | *--sp = 0; /* return address */ 90 | ucp->uc_mcontext.mc_rip = (long)func; 91 | ucp->uc_mcontext.mc_rsp = (long)sp; 92 | } 93 | #endif 94 | 95 | #ifdef NEEDARMMAKECONTEXT 96 | void 97 | makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...) 98 | { 99 | int i, *sp; 100 | va_list arg; 101 | 102 | sp = (int*)uc->uc_stack.ss_sp+uc->uc_stack.ss_size/4; 103 | va_start(arg, argc); 104 | for(i=0; i<4 && iuc_mcontext.gregs[i] = va_arg(arg, uint); 106 | va_end(arg); 107 | uc->uc_mcontext.gregs[13] = (uint)sp; 108 | uc->uc_mcontext.gregs[14] = (uint)fn; 109 | } 110 | #endif 111 | 112 | #ifdef NEEDMIPSMAKECONTEXT 113 | void 114 | makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...) 115 | { 116 | int i, *sp; 117 | va_list arg; 118 | 119 | va_start(arg, argc); 120 | sp = (int*)uc->uc_stack.ss_sp+uc->uc_stack.ss_size/4; 121 | for(i=0; i<4 && iuc_mcontext.mc_regs[i+4] = va_arg(arg, int); 123 | va_end(arg); 124 | uc->uc_mcontext.mc_regs[29] = (int)sp; 125 | uc->uc_mcontext.mc_regs[31] = (int)fn; 126 | } 127 | #endif 128 | 129 | #ifdef NEEDSWAPCONTEXT 130 | int 131 | swapcontext(ucontext_t *oucp, const ucontext_t *ucp) 132 | { 133 | if(getcontext(oucp) == 0) 134 | setcontext(ucp); 135 | return 0; 136 | } 137 | #endif 138 | 139 | -------------------------------------------------------------------------------- /switchtest/switch_dyco.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "dyco/dyco_coroutine.h" 3 | 4 | #define TOTAL_SWITCH_COUNTER 10000000 5 | // #define SHARED_STACK 6 | static int count; 7 | struct timeval tv1, tv2; 8 | 9 | void corofun(void *arg) 10 | { 11 | // printf("hello\n"); 12 | while (1) { 13 | if (count == 0) { 14 | gettimeofday(&tv1, NULL); 15 | } 16 | 17 | // printf("ok\n"); 18 | ++count; 19 | dyco_coroutine_sleep(0); 20 | ++count; 21 | 22 | if (count > TOTAL_SWITCH_COUNTER) { 23 | gettimeofday(&tv2, NULL); 24 | time_t diff = (tv2.tv_sec - tv1.tv_sec) * 1000000 + (tv2.tv_usec - tv1.tv_usec); 25 | double speed = 1.0 * diff / TOTAL_SWITCH_COUNTER; 26 | printf("diff = %ld us, switch speed = %f M/s\n", diff, speed); 27 | dyco_schedcall_abort(); 28 | } 29 | } 30 | return; 31 | } 32 | 33 | int main() 34 | { 35 | count = 0; 36 | int i = 0; 37 | while (i++ < 2) { 38 | int cid = dyco_coroutine_create(corofun, NULL); 39 | // printf("cid = %d\n", cid); 40 | #ifndef SHARED_STACK 41 | dyco_coroutine_setStack(cid, NULL, DYCO_DEFAULT_STACKSIZE); 42 | #endif 43 | } 44 | 45 | printf("[+] scheduler start running.\n"); 46 | dyco_schedule_run(); 47 | printf("[-] scheduler stopped.\n"); 48 | return 0; 49 | } -------------------------------------------------------------------------------- /switchtest/switch_libco.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Tencent is pleased to support the open source community by making Libco available. 3 | 4 | * Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include "co_routine_specific.h" 20 | #include "co_routine.h" 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | using namespace std; 28 | 29 | #define TOTAL_SWITCH_COUNTER 10000000 30 | #define SHARED_STACK 31 | static int count; 32 | struct timeval tv1, tv2; 33 | 34 | void* cofunc(void* args) 35 | { 36 | // printf("hello\n"); 37 | while (1) { 38 | if (count == 0) { 39 | gettimeofday(&tv1, NULL); 40 | } 41 | 42 | // printf("ok\n"); 43 | ++count; 44 | poll(NULL, 0, 0); 45 | ++count; 46 | 47 | if (count > TOTAL_SWITCH_COUNTER) { 48 | gettimeofday(&tv2, NULL); 49 | time_t diff = (tv2.tv_sec - tv1.tv_sec) * 1000000 + (tv2.tv_usec - tv1.tv_usec); 50 | double speed = 1.0 * diff / TOTAL_SWITCH_COUNTER; 51 | printf("diff = %ld us, switch speed = %f M/s\n", diff, speed); 52 | exit(0); 53 | } 54 | } 55 | return NULL; 56 | } 57 | 58 | int main() 59 | { 60 | count = 0; 61 | for (int i = 0; i < 2; i++) 62 | { 63 | args[i].routine_id = i; 64 | // co_create(&args[i].co, NULL, RoutineFunc, (void*)&args[i]); 65 | co_create(&args[i].co, NULL, cofunc, NULL); 66 | coresume(args[i].co); 67 | } 68 | co_eventloop(co_get_epoll_ct(), NULL, NULL); 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /switchtest/switch_ntyco.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "nty_coroutine.h" 3 | 4 | #define TOTAL_SWITCH_COUNTER 10000000 5 | #define SHARED_STACK 6 | static int count; 7 | struct timeval tv1, tv2; 8 | 9 | void corofun(void *arg) 10 | { 11 | // printf("hello\n"); 12 | while (1) { 13 | if (count == 0) { 14 | gettimeofday(&tv1, NULL); 15 | } 16 | 17 | // printf("ok\n"); 18 | ++count; 19 | nty_coroutine_sleep(0); 20 | ++count; 21 | 22 | if (count > TOTAL_SWITCH_COUNTER) { 23 | gettimeofday(&tv2, NULL); 24 | time_t diff = (tv2.tv_sec - tv1.tv_sec) * 1000000 + (tv2.tv_usec - tv1.tv_usec); 25 | double speed = 1.0 * diff / TOTAL_SWITCH_COUNTER; 26 | printf("diff = %ld us, switch speed = %f M/s\n", diff, speed); 27 | exit(1); 28 | } 29 | } 30 | return; 31 | } 32 | 33 | int main() 34 | { 35 | count = 0; 36 | int i = 0; 37 | while (i++ < 2) { 38 | nty_coroutine *co = NULL; 39 | int cid = nty_coroutine_create(&co, corofun, NULL); 40 | // printf("cid = %d\n", cid); 41 | } 42 | 43 | printf("[+] scheduler start running.\n"); 44 | nty_schedule_run(); 45 | printf("[-] scheduler stopped.\n"); 46 | return 0; 47 | } --------------------------------------------------------------------------------