├── .gitignore ├── README.md ├── include ├── CorMap.h ├── context.h ├── coroutine.h ├── csignal.h ├── epoll.h ├── load.h ├── log.h ├── queue.h ├── raii.h ├── scheduler.h ├── sync.h ├── sync │ ├── atomic.h │ ├── channel.h │ ├── cond.h │ ├── countDownLatch.h │ ├── locker.h │ ├── mutex.h │ └── sem.h ├── syscall.h └── util.h ├── makefile ├── src ├── context.S ├── cormap.cpp ├── coroutine.cpp ├── csignal.cpp ├── epoll.cpp ├── load.cpp ├── scheduler.cpp └── syscall.cpp ├── test ├── channel.cpp ├── client.cpp ├── cond.cpp ├── countDownLatch.cpp ├── multiThreadServer.cpp ├── mutex.cpp ├── prio.cpp ├── sem.cpp ├── server.cpp ├── signal.cpp ├── sleep.cpp └── yield.cpp └── todo /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 一个使用C/C++基于epoll实现的高性能的stackfull协程库,通过HOOK阻塞的系统调用,网络IO事件,协程间的同步事件及定时事件驱动协程的调度,通过汇编完成协程的高速切换,支持海量协程创建,支持协程的动态跨线程负载均衡调度,优先级调度,支持协程的栈上溢出检测及协程的signal信号处理机制,提供不同线程间协程同步协作的互斥量mutex,读写锁,条件变量cond,信号量sem,countDownLatch及用于数据共享的channel等等,总之很好玩,,, 2 | -------------------------------------------------------------------------------- /include/CorMap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, xie wenwu <870585356@qq.com> 3 | * 4 | * All rights reserved. 5 | */ 6 | 7 | #ifndef __CORMAP__ 8 | #define __CORMAP__ 9 | 10 | #include 11 | #include 12 | #include 13 | #include "sync/locker.h" 14 | 15 | class Map{ 16 | private: 17 | volatile int caps; 18 | volatile int sizes; 19 | void** volatile arr; 20 | 21 | int expand(){ 22 | int newCaps = caps * 2; 23 | int newBytes = sizeof(void*) * newCaps; 24 | void **p= (void**)realloc(arr, newBytes); 25 | 26 | if(!p) 27 | return -1; 28 | else{ 29 | arr = p; 30 | int oldBytes= sizeof(void*) * caps; 31 | memset((char*)arr + oldBytes, 0 , oldBytes); 32 | caps = newCaps; 33 | return 0; 34 | } 35 | } 36 | 37 | public: 38 | Map(int caps){ 39 | int bytes = sizeof(void*) * caps; 40 | arr = (void**)malloc(bytes); 41 | memset(arr, 0 , bytes); 42 | this->caps = caps; 43 | } 44 | 45 | int set(int key, void *value){ 46 | int ret = 0; 47 | if(key < caps){ 48 | arr[key] = value; 49 | }else{ 50 | ret = expand(); 51 | if(ret != 0){ 52 | return ret; 53 | } 54 | arr[key] = value; 55 | } 56 | sizes++; 57 | return ret; 58 | } 59 | 60 | void *get(int key){ 61 | if(key < caps) 62 | return arr[key]; 63 | else 64 | return NULL; 65 | } 66 | 67 | int del(int key){ 68 | if(key < caps && arr[key] != NULL){ 69 | sizes--; 70 | arr[key] = NULL; 71 | return 0; 72 | } 73 | return -1; 74 | } 75 | 76 | int size(){ 77 | return sizes; 78 | } 79 | 80 | int cap(){ 81 | return caps; 82 | } 83 | 84 | bool empty(){ 85 | return size() == 0; 86 | } 87 | 88 | void *next(int &idx){ 89 | if(!empty()) 90 | for(; idx < cap(); ){ 91 | void *value =get(idx++); 92 | if(value != NULL) 93 | return value; 94 | } 95 | return NULL; 96 | } 97 | 98 | ~Map(){ 99 | if(arr) 100 | free(arr); 101 | } 102 | }; 103 | 104 | class Coroutine; 105 | 106 | class CorMap{ 107 | private: 108 | Map *map1; 109 | Map *map2; 110 | 111 | SpinLocker locker; 112 | 113 | static volatile CorMap *instance; 114 | CorMap(){ 115 | map1 = new Map(1024); 116 | map2 = new Map(1024); 117 | 118 | } 119 | 120 | CorMap(const CorMap&) = delete; 121 | CorMap &operator=(const CorMap&) = delete; 122 | 123 | public: 124 | static const int STARTCID = 100000000; 125 | 126 | static CorMap *Instance(){ 127 | static SpinLocker locker; 128 | if(instance != NULL) 129 | return (CorMap*)instance; 130 | locker.lock(); 131 | if(!instance) 132 | instance = new CorMap(); 133 | locker.unlock(); 134 | return (CorMap*)instance; 135 | } 136 | 137 | int set(int key, Coroutine *value){ 138 | locker.lock(); 139 | int ret; 140 | if(key < STARTCID){ 141 | ret = map1->set(key, value); 142 | }else{ 143 | ret = map2->set(key - STARTCID, value); 144 | } 145 | locker.unlock(); 146 | return ret; 147 | } 148 | 149 | Coroutine *get(int key){ 150 | Coroutine *co = NULL; 151 | locker.lock(); 152 | if(key < STARTCID){ 153 | co = (Coroutine*)map1->get(key); 154 | }else{ 155 | co = (Coroutine*)map2->get(key - STARTCID); 156 | } 157 | locker.unlock(); 158 | return co; 159 | } 160 | 161 | int del(int key){ 162 | int ret = 0; 163 | locker.lock(); 164 | if(key < STARTCID){ 165 | ret = map1->del(key); 166 | }else{ 167 | ret = map2->del(key - STARTCID); 168 | } 169 | locker.unlock(); 170 | return ret; 171 | } 172 | 173 | int size(){ 174 | return map1->size() + map2->size(); 175 | } 176 | 177 | int empty(){ 178 | return size() == 0; 179 | } 180 | 181 | //not thread safe 182 | Coroutine *next(){ 183 | static int idx1 = 1; 184 | Coroutine *co = (Coroutine*)map1->next(idx1); 185 | if(co != NULL) 186 | return co; 187 | 188 | static int idx2 = 1; 189 | co = (Coroutine*)map2->next(idx2); 190 | if(co == NULL) 191 | idx1 = idx2 = 1; 192 | return co; 193 | } 194 | 195 | ~CorMap(){ 196 | if(map1) 197 | delete map1; 198 | if(map2) 199 | delete map2; 200 | } 201 | }; 202 | 203 | #endif 204 | -------------------------------------------------------------------------------- /include/context.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, xie wenwu <870585356@qq.com> 3 | * 4 | * All rights reserved. 5 | */ 6 | 7 | #ifndef __CONTEXT__ 8 | #define __CONTEXT__ 9 | 10 | typedef struct Context{ 11 | 12 | #ifdef __i386__ 13 | long ebx,ecx,edx,sp,ebp,esi,edi,pc; 14 | #elif __x86_64__ 15 | long rbx,rcx,rdx,sp,rbp,rsi,r12,r13,r14,r15,pc; 16 | #endif 17 | 18 | }Context; 19 | 20 | extern "C"{ 21 | int save(Context *cxt); 22 | void restore(Context *cxt, long funPtr); 23 | } 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /include/coroutine.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, xie wenwu <870585356@qq.com> 3 | * 4 | * All rights reserved. 5 | */ 6 | 7 | #ifndef __COROUTINE__ 8 | #define __COROUTINE__ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "context.h" 16 | #include "queue.h" 17 | 18 | enum{ 19 | NEW, 20 | RUNNABLE, 21 | RUNNING, 22 | WAITING, 23 | SYNCING, 24 | STOPPING, 25 | STOPPED, 26 | DEAD 27 | }; 28 | 29 | typedef int(*Routine)(void *); 30 | 31 | class Scheduler; 32 | 33 | class Coroutine{ 34 | private: 35 | friend void startCoroutine(); 36 | friend struct compare; 37 | 38 | int state; 39 | int prio; 40 | 41 | int type; 42 | int epfd; 43 | 44 | union Id{ 45 | int fd; 46 | int cid; 47 | }id; 48 | pid_t groupid; 49 | 50 | void *arg; 51 | char *stack; 52 | int stackSize; 53 | Routine routine; 54 | Context context; 55 | 56 | int signal; 57 | bool intr; 58 | time_t timeout; 59 | 60 | Scheduler *schdeuler; 61 | 62 | private: 63 | Coroutine(const Coroutine &) = delete; 64 | Coroutine &operator=(const Coroutine&) = delete; 65 | 66 | private: 67 | void init(Routine routine, void *arg, int prio, int cid); 68 | 69 | public: 70 | Coroutine *next; 71 | 72 | Coroutine(Routine routine, void *arg); 73 | 74 | Coroutine(); 75 | 76 | void setStackSize(int size){ 77 | this->stackSize = size; 78 | } 79 | 80 | int getStackSize(){ 81 | return stackSize; 82 | } 83 | 84 | char* getStack(){ 85 | return stack; 86 | } 87 | 88 | int setContext(Context &cxt){ 89 | context = cxt; 90 | } 91 | 92 | Context* getContext(){ 93 | return &context; 94 | } 95 | 96 | void setFd(int fd){ 97 | id.fd = fd; 98 | } 99 | 100 | int getFd(){ 101 | return id.fd; 102 | } 103 | 104 | void setType(int type){ 105 | this->type = type; 106 | } 107 | 108 | int getType(){ 109 | return type; 110 | } 111 | 112 | void setEpfd(int epfd){ 113 | this->epfd = epfd; 114 | } 115 | 116 | int getEpfd(){ 117 | return epfd; 118 | } 119 | 120 | int start(); 121 | 122 | void stop(); 123 | 124 | int getcid(){ 125 | return id.cid; 126 | } 127 | 128 | void setGroupid(pid_t gid){ 129 | groupid = gid; 130 | } 131 | 132 | pid_t getGroupid(){ 133 | return groupid; 134 | } 135 | 136 | int getSignal(){ 137 | return signal; 138 | } 139 | 140 | void setSignal(int signo){ 141 | if(signo == 0){ 142 | signal = 0; 143 | return; 144 | } 145 | signal |= (1<timeout = timeout; 150 | } 151 | 152 | time_t getTimeout(){ 153 | return timeout; 154 | } 155 | 156 | void setState(int state){ 157 | this->state = state; 158 | } 159 | 160 | int getState(){ 161 | return state; 162 | } 163 | 164 | void setIntr(bool intr){ 165 | this->intr = intr; 166 | } 167 | 168 | bool getIntr(){ 169 | return intr; 170 | } 171 | 172 | void setPrio(int prio){ 173 | assert(prio<=SCH_PRIO_SIZE && prio>=1); 174 | this->prio = prio - 1; 175 | } 176 | 177 | int getPrio(){ 178 | return prio; 179 | } 180 | 181 | void setSched(Scheduler* sched){ 182 | schdeuler = sched; 183 | } 184 | 185 | Scheduler* getSched(){ 186 | return schdeuler; 187 | } 188 | 189 | ~Coroutine(); 190 | }; 191 | 192 | struct compare{ 193 | bool operator()(Coroutine* &left, Coroutine* &right){ 194 | return left->timeout > right->timeout; 195 | } 196 | }; 197 | 198 | int getcid(); 199 | int gettid(); 200 | 201 | extern __thread Coroutine *current; 202 | 203 | extern void wakeup(Coroutine *co); 204 | extern void stopCoroutines(); 205 | extern int waitOnTimer(int timeout); 206 | extern int ckill(Coroutine *co, int signo); 207 | extern int ckill(int cid, int signo); 208 | extern int csignal(int signo, void (*handler)(int)); 209 | 210 | Coroutine *createCoroutine(int (*routine)(void *), void *arg); 211 | 212 | #define yield\ 213 | do{\ 214 | if(current == NULL){\ 215 | current = new Coroutine();\ 216 | }\ 217 | waitOnTimer(0);\ 218 | }while(0) 219 | 220 | #define resume(co)\ 221 | do{\ 222 | if(co != NULL){\ 223 | wakeup(co)\ 224 | }\ 225 | }while(0) 226 | 227 | #endif 228 | -------------------------------------------------------------------------------- /include/csignal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, xie wenwu <870585356@qq.com> 3 | * 4 | * All rights reserved. 5 | */ 6 | #include "coroutine.h" 7 | 8 | typedef void (*SignalHandler)(int); 9 | extern SignalHandler signalHandler[]; 10 | 11 | void doSignal(); 12 | int ckill(int cid, int signo); 13 | int ckill(Coroutine *co, int signo); 14 | int csignal(int signo, SignalHandler handler); 15 | void sigdefHandler(int signo); 16 | -------------------------------------------------------------------------------- /include/epoll.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, xie wenwu <870585356@qq.com> 3 | * 4 | * All rights reserved. 5 | */ 6 | 7 | #ifndef __EPOLL__ 8 | #define __EPOLL__ 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "cormap.h" 14 | #include "log.h" 15 | 16 | enum {READABLE = EPOLLIN, WRITEABLE = EPOLLOUT}; 17 | 18 | class Coroutine; 19 | extern __thread Coroutine *current; 20 | 21 | static inline int epollCreate(int max){ 22 | return epoll_create(max); 23 | } 24 | 25 | static inline int eventCtl(int epollFd, int fd, int type, int mode){ 26 | epoll_event event; 27 | event.events = type|EPOLLET; 28 | if(type == WRITEABLE) event.events |= EPOLLONESHOT; 29 | assert(current!=NULL); 30 | event.data.ptr = current; 31 | int ret = epoll_ctl(epollFd, mode, fd, &event); 32 | if(ret < 0){ 33 | log(ERROR,"epoll epfd:%d fd:%d type:%d mode:%d error: %s", epollFd, fd, type, mode, strerror(errno)); 34 | } 35 | return ret; 36 | } 37 | 38 | static inline int epollAddEvent(int epollFd, int fd, int type){ 39 | return eventCtl(epollFd, fd, type, EPOLL_CTL_ADD); 40 | } 41 | 42 | static inline int epollDelEvent(int epollFd, int fd, int type){ 43 | return eventCtl(epollFd, fd, type, EPOLL_CTL_DEL); 44 | } 45 | 46 | static inline int epollModEvent(int epollFd, int fd, int type){ 47 | return eventCtl(epollFd, fd, type, EPOLL_CTL_MOD); 48 | } 49 | 50 | static inline int epollWait(int epollFd, epoll_event *events, int maxEventSize, int inthz){ 51 | return epoll_wait(epollFd, events, maxEventSize, inthz); 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /include/load.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, xie wenwu <870585356@qq.com> 3 | * 4 | * All rights reserved. 5 | */ 6 | 7 | #ifndef __LOAD__ 8 | #define __LOAD__ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | struct CpuStat{ 20 | char cpu[8]; 21 | unsigned long user_time; 22 | unsigned long nice_time; 23 | unsigned long sys_time; 24 | unsigned long idle_time; 25 | unsigned long iowait_time; 26 | unsigned long irq_time; 27 | unsigned long sirq_time; 28 | }; 29 | 30 | struct TaskStat{ 31 | int pid; 32 | char cmd[16]; 33 | char state; 34 | int ppid; 35 | int group; 36 | int session; 37 | int tty_nr; 38 | int tty_pgrp; 39 | unsigned long flags; 40 | unsigned long min_flt; 41 | unsigned long cmin_flt; 42 | unsigned long maj_flt; 43 | unsigned long cmaj_flt; 44 | unsigned long utime; 45 | unsigned long stime; 46 | long cutime; 47 | long cstime; 48 | long prio; 49 | long nice; 50 | int num_threads; 51 | long it_real_value; 52 | unsigned long long start_time; 53 | unsigned long vsize; 54 | long rss; 55 | unsigned long rlim_cur; 56 | unsigned long start_code; 57 | unsigned long end_code; 58 | unsigned long tart_stack; 59 | unsigned long esp; 60 | unsigned long eip; 61 | unsigned long pending; 62 | unsigned long blocked; 63 | unsigned long sigign; 64 | unsigned long sigcatch; 65 | unsigned long wchan; 66 | unsigned long nswap; 67 | unsigned long cnswap; 68 | int exit_signal; 69 | int cpu_num; 70 | long rt_prio; 71 | long policy; 72 | }; 73 | 74 | int getCpuCount(); 75 | 76 | class Stat{ 77 | private: 78 | int cpuFd, procFd, threadFd; 79 | 80 | CpuStat cpuStat; 81 | 82 | void openStat(); 83 | void closeStat(); 84 | 85 | unsigned long getTaskTime(int fd); 86 | 87 | public: 88 | Stat(){ 89 | openStat(); 90 | } 91 | 92 | inline void getCpuStat(); 93 | 94 | unsigned long getProcTime(){ 95 | return getTaskTime(procFd); 96 | } 97 | 98 | unsigned long getThreadTime(){ 99 | return getTaskTime(threadFd); 100 | } 101 | 102 | unsigned long getCpuTime(){ 103 | return cpuStat.user_time + cpuStat.nice_time + cpuStat.sys_time + cpuStat.idle_time + cpuStat.iowait_time + cpuStat.irq_time + cpuStat.sirq_time; 104 | } 105 | 106 | unsigned long getIdleTime(){ 107 | return cpuStat.idle_time; 108 | } 109 | 110 | ~Stat(){ 111 | closeStat(); 112 | } 113 | }; 114 | 115 | class Load{ 116 | private: 117 | int statCount; 118 | Stat stat; 119 | time_t statTime; 120 | unsigned long threadT1, threadT2, procT1, procT2, cpuT1, cpuT2, idleT1, idleT2; 121 | 122 | public: 123 | int procUsage, procUsage_, threadUsage, threadUsage_, sysUsage, sysUsage_; 124 | int cpuCount; 125 | 126 | public: 127 | Load(); 128 | 129 | bool cacl(); 130 | 131 | ~Load(){} 132 | }; 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /include/log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, xie wenwu <870585356@qq.com> 3 | * 4 | * All rights reserved. 5 | */ 6 | 7 | #ifndef __LOG__ 8 | #define __LOG__ 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | extern int gettid(); 16 | extern int getcid(); 17 | 18 | #define INFO "INFO", __FILE__, __LINE__ 19 | #define WARN "WARN", __FILE__, __LINE__ 20 | #define ERROR "ERROR", __FILE__, __LINE__ 21 | #define DEBUG "DEBUG", __FILE__, __LINE__ 22 | 23 | static inline void logPrint(const char* lev, const char *file, int line, const char *format, ...){ 24 | char buf[128]; 25 | time_t now=time(NULL); 26 | struct tm date; 27 | localtime_r(&now,&date); 28 | sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d %s(%d) tid:%d cid:%d %s -> ", 29 | date.tm_year+1900, date.tm_mon+1, date.tm_mday, 30 | date.tm_hour, date.tm_min, date.tm_sec, 31 | basename(file), line, gettid(), getcid(), lev); 32 | int len = strlen(buf); 33 | va_list ap; 34 | va_start(ap, format); 35 | vsnprintf(buf+len, 256, format, ap); 36 | va_end(ap); 37 | printf("%s\n", buf); 38 | } 39 | 40 | #define log logPrint 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /include/queue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, xie wenwu <870585356@qq.com> 3 | * 4 | * All rights reserved. 5 | */ 6 | 7 | #ifndef __QUEUE__ 8 | #define __QUEUE__ 9 | //a first in first out queue, only used when item is point 10 | 11 | #include "sync/locker.h" 12 | 13 | template 14 | bool isLinked(T item){ 15 | return item->next != item; 16 | } 17 | 18 | template 19 | class Queue{ 20 | private: 21 | LockerType locker; 22 | volatile int sizes; 23 | volatile T head, tail; 24 | 25 | public: 26 | Queue(){ 27 | sizes = 0; 28 | head = tail = NULL; 29 | } 30 | 31 | void push(T item){ 32 | assert(item != NULL); 33 | if(isLinked(item)) 34 | return; 35 | 36 | 37 | locker.lock(); 38 | item->next = NULL; 39 | if(tail == NULL){ 40 | head = tail = item; 41 | }else{ 42 | tail->next = item; 43 | tail = item; 44 | } 45 | sizes++; 46 | locker.unlock(); 47 | } 48 | 49 | T pop(){ 50 | locker.lock(); 51 | T item = NULL; 52 | if(head != NULL){ 53 | item = head; 54 | head = head->next; 55 | item->next = item; 56 | sizes--; 57 | if(!head) 58 | tail = NULL; 59 | } 60 | locker.unlock(); 61 | return item; 62 | } 63 | 64 | void erase(T item){ 65 | if(!isLinked(item)) 66 | return; 67 | 68 | T cur, pre; 69 | 70 | locker.lock(); 71 | for(cur = pre = head; cur != NULL; pre = cur, cur = cur->next){ 72 | if(item != cur) continue; 73 | pre->next = cur->next; 74 | } 75 | locker.unlock(); 76 | } 77 | 78 | int size(){ 79 | return sizes; 80 | } 81 | 82 | bool empty(){ 83 | return size() == 0; 84 | } 85 | }; 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /include/raii.h: -------------------------------------------------------------------------------- 1 | #ifndef __RAII__ 2 | #define __RAII__ 3 | 4 | class Raii{ 5 | private: 6 | Locker *locker; 7 | 8 | public: 9 | Raii(Locker *locker){ 10 | this->locker = locker; 11 | locker->lock(); 12 | } 13 | 14 | ~Raii(){ 15 | locker->unlock(); 16 | locker = NULL; 17 | } 18 | }; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /include/scheduler.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DoasIsay/XCoroutine/18a8e794897fedefbe99b434da309e07baeb4fd3/include/scheduler.h -------------------------------------------------------------------------------- /include/sync.h: -------------------------------------------------------------------------------- 1 | #ifndef __SYNC__ 2 | #define __SYNC__ 3 | 4 | #include "sync/sem.h" 5 | #include "sync/atomic.h" 6 | #include "sync/countDownLatch.h" 7 | #include "sync/channel.h" 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /include/sync/atomic.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, xie wenwu <870585356@qq.com> 3 | * 4 | * All rights reserved. 5 | */ 6 | 7 | #ifndef __ATOMIC__ 8 | #define __ATOMIC__ 9 | 10 | class Atomic{ 11 | private: 12 | volatile long count; 13 | 14 | public: 15 | Atomic(int value=0):count(value){} 16 | 17 | long inc(int val = 1){ 18 | return __sync_add_and_fetch(&count, val); 19 | } 20 | 21 | long dec(int val = 1){ 22 | return __sync_sub_and_fetch(&count, val); 23 | } 24 | 25 | long get(){ 26 | return count; 27 | } 28 | 29 | void set(long count){ 30 | this->count = count; 31 | } 32 | 33 | bool cas(long oldVal, long newVal){ 34 | return __sync_bool_compare_and_swap(&count, oldVal, newVal); 35 | } 36 | 37 | }; 38 | 39 | static inline bool cas(long *ptr, long oldVal, long newVal){ 40 | return __sync_bool_compare_and_swap(ptr, oldVal, newVal); 41 | } 42 | 43 | #define membar do{ __sync_synchronize(); }while(0) 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/sync/channel.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DoasIsay/XCoroutine/18a8e794897fedefbe99b434da309e07baeb4fd3/include/sync/channel.h -------------------------------------------------------------------------------- /include/sync/cond.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DoasIsay/XCoroutine/18a8e794897fedefbe99b434da309e07baeb4fd3/include/sync/cond.h -------------------------------------------------------------------------------- /include/sync/countDownLatch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, xie wenwu <870585356@qq.com> 3 | * 4 | * All rights reserved. 5 | */ 6 | 7 | #ifndef __COUNT_DOWN_LATCH__ 8 | #define __COUNT_DOWN_LATCH__ 9 | 10 | #include "cond.h" 11 | #include "mutex.h" 12 | 13 | class CountDownLatch{ 14 | private: 15 | volatile int count; 16 | Cond cond; 17 | Mutex mutex; 18 | 19 | public: 20 | CountDownLatch(int count){ 21 | this->count = count; 22 | } 23 | 24 | int wait(int timeout = -1){ 25 | if(count == 0) return 0; 26 | 27 | mutex.lock(); 28 | if(count == 0){ 29 | mutex.unlock(); 30 | return 0; 31 | } 32 | int ret = cond.wait(mutex, timeout); 33 | mutex.unlock(); 34 | 35 | return ret; 36 | } 37 | 38 | void countDown(){ 39 | mutex.lock(); 40 | count--; 41 | mutex.unlock(); 42 | 43 | if(count == 0) cond.broadcast(); 44 | } 45 | 46 | int getCount(){ 47 | return count; 48 | } 49 | }; 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /include/sync/locker.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DoasIsay/XCoroutine/18a8e794897fedefbe99b434da309e07baeb4fd3/include/sync/locker.h -------------------------------------------------------------------------------- /include/sync/mutex.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DoasIsay/XCoroutine/18a8e794897fedefbe99b434da309e07baeb4fd3/include/sync/mutex.h -------------------------------------------------------------------------------- /include/sync/sem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, xie wenwu <870585356@qq.com> 3 | * 4 | * All rights reserved. 5 | */ 6 | 7 | #ifndef __SEM__ 8 | #define __SEM__ 9 | 10 | #include "cond.h" 11 | 12 | class Sem{ 13 | private: 14 | volatile int permits, used; 15 | Mutex mutex; 16 | Cond cond; 17 | 18 | public: 19 | Sem(int pers){ 20 | used = 0; 21 | permits = pers; 22 | } 23 | 24 | void wait(){ 25 | mutex.lock(); 26 | 27 | while(used >= permits){ 28 | log(INFO, "permits %d used %d, wait until used < permits", permits, used); 29 | cond.wait(mutex); 30 | log(INFO, "wakeup used %d", used); 31 | } 32 | used++; 33 | 34 | mutex.unlock(); 35 | } 36 | 37 | void signal(){ 38 | mutex.lock(); 39 | if(used > 0) used--; 40 | mutex.unlock(); 41 | 42 | cond.signal(); 43 | } 44 | }; 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /include/syscall.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (c) 2020, xie wenwu <870585356@qq.com> 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef __SYSCALL__ 9 | #define __SYSCALL__ 10 | 11 | typedef int (*SysClose)(int fd); 12 | typedef int (*SysDup)(int oldfd); 13 | typedef int (*SysListen)(int sockfd, int backlog); 14 | typedef unsigned int (*SysSleep)(unsigned int seconds); 15 | typedef ssize_t (*SysRead)(int fd, void *buf, size_t count); 16 | typedef int (*SysSocket)(int domain, int type, int protocol); 17 | typedef ssize_t (*SysWrite)(int fd, const void *buf, size_t count); 18 | typedef int (*SysAccept)(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 19 | typedef int (*SysConnect)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 20 | 21 | extern SysDup sysDup ; 22 | extern SysRead sysRead ; 23 | extern SysClose sysClose ; 24 | extern SysSleep sysSleep ; 25 | extern SysWrite sysWrite ; 26 | extern SysListen sysListen ; 27 | extern SysSocket sysSocket ; 28 | extern SysAccept sysAccept ; 29 | extern SysConnect sysConnect; 30 | 31 | #endif -------------------------------------------------------------------------------- /include/util.h: -------------------------------------------------------------------------------- 1 | #ifndef __UTIL__ 2 | #define __UTIL__ 3 | #include 4 | static inline long milliseconds(){ 5 | struct timeval tv; 6 | 7 | gettimeofday(&tv, NULL); 8 | return tv.tv_usec/1000; 9 | } 10 | 11 | static inline long seconds(){ 12 | return time(NULL); 13 | } 14 | 15 | #endif -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | 2 | all:libtoco.so yield server client multiThreadServer sleep signal prio mutex cond sem countDownLatch channel 3 | 4 | SSRC = $(wildcard ./src/*.S) 5 | 6 | CPPSRC = $(wildcard ./src/*.cpp ./test/*.cpp) 7 | 8 | OBJS = $(patsubst %.S,%.o,$(SSRC)) $(patsubst %.cpp,%.o,$(CPPSRC)) 9 | 10 | INCLUDES = -I./test -I./include 11 | LIBS = -L./ 12 | 13 | CFLAGS = -g -std=c++0x -fPIC -shared -fstack-protector-all -lpthread\ 14 | -DSCH_PRIO_SIZE=8\ 15 | -DSCH_STACK_SIZE=4096\ 16 | -DCOR_STACK_SIZE=4096\ 17 | -DSTACK_SEPARATE\ 18 | -DLOADBALANCE_FACTOR=95 19 | 20 | LFLAGS = -g $(LIBS) -ltoco -fstack-protector-all 21 | 22 | %.o:%.cpp 23 | g++ -c $(CFLAGS) $(INCLUDES) $< -o $@ 24 | 25 | %.o:%.S 26 | g++ -c $(CFLAGS) $(INCLUDES) $< -o $@ 27 | 28 | libtoco.so:$(OBJS) 29 | g++ $(CFLAGS) -o libtoco.so ./src/*.o -lpthread -ldl 30 | 31 | yield:$(OBJS) 32 | g++ $(LFLAGS) -o yield ./test/yield.o 33 | 34 | client:$(OBJS) 35 | g++ $(LFLAGS) -o client ./test/client.o 36 | 37 | server:$(OBJS) 38 | g++ $(LFLAGS) -o server ./test/server.o 39 | 40 | multiThreadServer:$(OBJS) 41 | g++ $(LFLAGS) -o multiThreadServer ./test/multiThreadServer.o -lpthread 42 | 43 | sleep:$(OBJS) 44 | g++ $(LFLAGS) -o sleep ./test/sleep.o 45 | 46 | signal:$(OBJS) 47 | g++ $(LFLAGS) -o signal ./test/signal.o 48 | 49 | prio:$(OBJS) 50 | g++ $(LFLAGS) -o prio ./test/prio.o 51 | 52 | mutex:$(OBJS) 53 | g++ $(LFLAGS) -o mutex ./test/mutex.o 54 | 55 | cond:$(OBJS) 56 | g++ $(LFLAGS) -o cond ./test/cond.o 57 | 58 | sem:$(OBJS) 59 | g++ $(LFLAGS) -o sem ./test/sem.o 60 | 61 | countDownLatch:$(OBJS) 62 | g++ $(LFLAGS) -o countDownLatch ./test/countDownLatch.o 63 | 64 | channel:$(OBJS) 65 | g++ $(LFLAGS) -o channel ./test/channel.o 66 | 67 | clean: 68 | rm -rf ./src/*.o ./test/*.o libtoco.so yield client server multiThreadServer sleep signal prio mutex cond sem countDownLatch channel -------------------------------------------------------------------------------- /src/context.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, xie wenwu <870585356@qq.com> 3 | * 4 | * All rights reserved. 5 | */ 6 | .globl save 7 | .text 8 | save: 9 | #ifdef __i386__ 10 | movl 4(%esp), %eax 11 | movl %ebx, (%eax) 12 | movl %ecx, 4(%eax) 13 | movl %edx, 8(%eax) 14 | popl %ebx 15 | movl %esp, 12(%eax) 16 | movl %ebp, 16(%eax) 17 | movl %esi, 20(%eax) 18 | movl %edi, 24(%eax) 19 | movl %ebx, 28(%eax) 20 | pushl %ebx 21 | movl (%eax), %ebx 22 | movl $0, %eax 23 | ret 24 | 25 | #elif __x86_64__ 26 | movq %rbx, (%rdi) 27 | movq %rcx, 8(%rdi) 28 | movq %rdx, 16(%rdi) 29 | pop %rax 30 | movq %rsp, 24(%rdi) 31 | movq %rbp, 32(%rdi) 32 | movq %rsi, 40(%rdi) 33 | movq %r12, 48(%rdi) 34 | movq %r13, 56(%rdi) 35 | movq %r14, 64(%rdi) 36 | movq %r15, 72(%rdi) 37 | movq %rax, 80(%rdi) 38 | push %rax 39 | movl $0, %eax 40 | ret 41 | 42 | #endif 43 | 44 | .globl restore 45 | .text 46 | restore: 47 | #ifdef __i386__ 48 | movl 4(%esp), %eax 49 | movl 8(%esp), %edi 50 | movl (%eax), %ebx 51 | movl 4(%eax), %ecx 52 | movl 8(%eax), %edx 53 | movl 12(%eax), %esp 54 | movl 16(%eax), %ebp 55 | movl 20(%eax), %esi 56 | push 28(%eax) 57 | push 24(%eax) 58 | call %edi 59 | pop %edi 60 | pop(%esp) 61 | movl $1, %eax 62 | ret 63 | 64 | #elif __x86_64__ 65 | movq (%rdi), %rbx 66 | movq 8(%rdi), %rcx 67 | movq 16(%rdi), %rdx 68 | movq 24(%rdi), %rsp 69 | movq 32(%rdi), %rbp 70 | movq 48(%rdi), %r12 71 | movq 56(%rdi), %r13 72 | movq 64(%rdi), %r14 73 | movq 72(%rdi), %r15 74 | push 80(%rdi) 75 | push 40(%rdi) 76 | call %rsi 77 | pop %rsi 78 | pop (%rsp) 79 | movl $1, %eax 80 | ret 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /src/cormap.cpp: -------------------------------------------------------------------------------- 1 | #include "cormap.h" 2 | 3 | volatile CorMap* CorMap::instance = NULL; 4 | -------------------------------------------------------------------------------- /src/coroutine.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, wenwu xie <870585356@qq.com> 3 | * All rights reserved. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "coroutine.h" 13 | #include "cormap.h" 14 | 15 | const static int DEF_PRIO = SCH_PRIO_SIZE/2; 16 | 17 | __thread Coroutine *current = NULL; 18 | 19 | static int allocCid(Coroutine *co){ 20 | int cid; 21 | CorMap *corMap = CorMap::Instance(); 22 | static SpinLocker locker; 23 | locker.lock(); 24 | for(cid = CorMap::STARTCID ; corMap->get(cid) != NULL; ++cid); 25 | corMap ->set(cid, co); 26 | locker.unlock(); 27 | return cid; 28 | } 29 | 30 | void Coroutine::init(Routine routine, void *arg, 31 | int prio, int cid){ 32 | type = -1; 33 | epfd = -1; 34 | signal = 0; 35 | timeout = 0; 36 | next = this; 37 | intr = false; 38 | 39 | stack = NULL; 40 | this->arg = arg; 41 | stackSize = COR_STACK_SIZE; 42 | this->routine = routine; 43 | 44 | id.cid = cid; 45 | groupid = 0; 46 | 47 | state = NEW; 48 | setPrio(prio); 49 | schdeuler = NULL; 50 | } 51 | 52 | 53 | Coroutine::Coroutine(Routine routine, void *arg){ 54 | init(routine, arg, DEF_PRIO, allocCid(this)); 55 | } 56 | 57 | Coroutine::Coroutine(){ 58 | init(NULL, NULL ,SCH_PRIO_SIZE, 0); 59 | } 60 | 61 | extern void startCoroutine(); 62 | extern void wakeup(Coroutine *co); 63 | 64 | int Coroutine::start(){ 65 | if(getcid() < 0) return -1; 66 | 67 | save(&context); 68 | context.pc = (long)startCoroutine; 69 | 70 | if(stack == NULL) stack = (char*)malloc(stackSize); 71 | assert(stack != NULL); 72 | context.sp = (long)(stack + stackSize); 73 | 74 | wakeup(this); 75 | return 0; 76 | } 77 | 78 | void Coroutine::stop(){ 79 | if(state == DEAD) return; 80 | 81 | setState(STOPPING); 82 | ckill(this,SIGTERM); 83 | } 84 | 85 | Coroutine::~Coroutine(){ 86 | setState(DEAD); 87 | assert(stack != NULL); 88 | free(stack); 89 | stack = NULL; 90 | } 91 | 92 | Coroutine *createCoroutine(int (*routine)(void *), void *arg){ 93 | Coroutine *co= new Coroutine(routine, arg); 94 | co->start(); 95 | return co; 96 | } 97 | 98 | int getcid(){ 99 | if(current == NULL) return 0; 100 | return current->getcid(); 101 | } 102 | 103 | int gettid(){ 104 | int tid; 105 | if(current == NULL ||(tid = current->getGroupid()) == 0) return syscall(__NR_gettid); 106 | return tid; 107 | } 108 | 109 | -------------------------------------------------------------------------------- /src/csignal.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DoasIsay/XCoroutine/18a8e794897fedefbe99b434da309e07baeb4fd3/src/csignal.cpp -------------------------------------------------------------------------------- /src/epoll.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, xie wenwu <870585356@qq.com> 3 | * 4 | * All rights reserved. 5 | */ 6 | 7 | -------------------------------------------------------------------------------- /src/load.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, xie wenwu <870585356@qq.com> 3 | * 4 | * All rights reserved. 5 | */ 6 | 7 | #include "load.h" 8 | #include 9 | #include 10 | #include 11 | 12 | int getCpuCount(){ 13 | FILE *fp = fopen("/proc/cpuinfo", "r"); 14 | assert(fp != NULL); 15 | 16 | char *pos = NULL; 17 | char buf[1024] = {0}; 18 | char process[32] = {0}; 19 | 20 | while(fgets(buf, sizeof(buf), fp) != NULL){ 21 | if((pos = strstr(buf, "processor")) == NULL) continue; 22 | strcpy(process, buf); 23 | } 24 | 25 | pos = strstr(process, ":"); 26 | 27 | return atoi(pos + 1) + 1; 28 | } 29 | 30 | void Stat::openStat(){ 31 | pid_t pid = getpid(); 32 | pid_t tid = syscall(__NR_gettid); 33 | 34 | char path[32]; 35 | sprintf(path, "/proc/%d/stat", pid); 36 | procFd = open(path, O_RDONLY); 37 | 38 | sprintf(path, "/proc/%d/task/%d/stat", pid, tid); 39 | threadFd = open(path, O_RDONLY); 40 | 41 | cpuFd = open("/proc/stat", O_RDONLY); 42 | } 43 | 44 | void Stat::closeStat(){ 45 | close(cpuFd); 46 | close(procFd); 47 | close(threadFd); 48 | } 49 | 50 | void Stat::getCpuStat(){ 51 | char buff[256] = {0}; 52 | 53 | lseek(cpuFd, 0, SEEK_SET); 54 | read(cpuFd, buff, 256); 55 | 56 | sscanf(buff,"%s %lu %lu %lu %lu %lu %lu %lu",cpuStat.cpu, &cpuStat.user_time, &cpuStat.nice_time, 57 | &cpuStat.sys_time, &cpuStat.idle_time, &cpuStat.iowait_time, 58 | &cpuStat.irq_time, &cpuStat.sirq_time); 59 | } 60 | 61 | unsigned long Stat::getTaskTime(int fd){ 62 | char buff[512] = {0}; 63 | 64 | lseek(fd, 0, SEEK_SET); 65 | read(fd, buff, 512); 66 | 67 | TaskStat stat; 68 | sscanf(buff,"%d %s %c %d %d %d %d %d %lu %lu \ 69 | %lu %lu %lu %lu %lu %ld %ld %ld %ld %d %ld %llu %lu %ld %lu %lu %lu %lu %lu \ 70 | %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu\n", 71 | &stat.pid, stat.cmd, &stat.state, &stat.ppid, &stat.group, &stat.session, 72 | &stat.tty_nr, &stat.tty_pgrp, &stat.flags, &stat.min_flt, &stat.cmin_flt, &stat.maj_flt, 73 | &stat.cmaj_flt, &stat.utime, &stat.stime, &stat.cutime, &stat.cstime, &stat.prio, &stat.nice, 74 | &stat.num_threads, &stat.it_real_value, &stat.start_time, &stat.vsize, &stat.rss, &stat.rlim_cur, 75 | &stat.start_code, &stat.end_code, &stat.tart_stack, &stat.esp, &stat.eip, &stat.pending, &stat.blocked, 76 | &stat.sigign, &stat.sigcatch, &stat.wchan, &stat.nswap, &stat.cnswap, &stat.exit_signal, &stat.cpu_num, &stat.rt_prio, &stat.policy); 77 | 78 | return stat.utime + stat.stime + stat.cutime + stat.cstime; 79 | } 80 | 81 | Load::Load(){ 82 | sysUsage = procUsage = threadUsage = 0; 83 | sysUsage_ = procUsage_ = threadUsage_ = 0; 84 | 85 | cpuCount = getCpuCount(); 86 | 87 | cpuT1 = stat.getCpuTime(); 88 | procT1 = stat.getProcTime(); 89 | idleT1 = stat.getIdleTime(); 90 | threadT1 = stat.getThreadTime(); 91 | 92 | statTime = time(NULL); 93 | statCount = 0; 94 | } 95 | 96 | bool Load::cacl(){ 97 | time_t now = time(NULL); 98 | if(now - statTime < 1) return false; 99 | statTime = now; 100 | statCount++; 101 | 102 | stat.getCpuStat(); 103 | cpuT2 = stat.getCpuTime(); 104 | procT2 = stat.getProcTime(); 105 | idleT2 = stat.getIdleTime(); 106 | threadT2 = stat.getThreadTime(); 107 | 108 | unsigned long cpuTime = cpuT2 - cpuT1; 109 | 110 | sysUsage_ += (100 - (idleT2 - idleT1) * 100/ cpuTime); 111 | procUsage_ += ((procT2 - procT1) * 100 / cpuTime * cpuCount); 112 | threadUsage_ += ((threadT2 - threadT1) * 100 / cpuTime * cpuCount); 113 | 114 | cpuT1 = cpuT2; 115 | procT1 = procT2; 116 | idleT1 = idleT2; 117 | threadT1 = threadT2; 118 | 119 | if(statCount == 10){ 120 | sysUsage = sysUsage_ / statCount; 121 | procUsage = procUsage_ / statCount; 122 | threadUsage = threadUsage_ / statCount; 123 | 124 | sysUsage_ = procUsage_ = threadUsage_ = 0; 125 | statCount = 0; 126 | } 127 | return true; 128 | } 129 | 130 | -------------------------------------------------------------------------------- /src/scheduler.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DoasIsay/XCoroutine/18a8e794897fedefbe99b434da309e07baeb4fd3/src/scheduler.cpp -------------------------------------------------------------------------------- /src/syscall.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, xie wenwu <870585356@qq.com> 3 | * 4 | * All rights reserved. 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "syscall.h" 15 | #include "scheduler.h" 16 | 17 | SysDup sysDup = (SysDup)dlsym(RTLD_NEXT, "dup"); 18 | SysRead sysRead = (SysRead)dlsym(RTLD_NEXT, "read"); 19 | SysClose sysClose = (SysClose)dlsym(RTLD_NEXT, "close"); 20 | SysSleep sysSleep = (SysSleep)dlsym(RTLD_NEXT, "sleep"); 21 | SysWrite sysWrite = (SysWrite)dlsym(RTLD_NEXT, "write"); 22 | SysListen sysListen = (SysListen)dlsym(RTLD_NEXT, "listen"); 23 | SysSocket sysSocket = (SysSocket)dlsym(RTLD_NEXT, "socket"); 24 | SysAccept sysAccept = (SysAccept)dlsym(RTLD_NEXT, "accept"); 25 | SysConnect sysConnect = (SysConnect)dlsym(RTLD_NEXT, "connect"); 26 | 27 | 28 | int setNoBlock(int fd, int block=1) { 29 | int flags; 30 | if ((flags = fcntl(fd, F_GETFL)) == -1) { 31 | log(ERROR, "fcntl get fd %d error %s", fd, strerror(errno)); 32 | return -1; 33 | } 34 | 35 | if(block) flags |= O_NONBLOCK; 36 | else flags &= ~O_NONBLOCK; 37 | if (fcntl(fd, F_SETFL, flags) == -1) { 38 | log(ERROR, "fcntl set fd %d error %s", fd, strerror(errno)); 39 | return -1; 40 | } 41 | return 0; 42 | } 43 | 44 | int socket(int domain, int type, int protocol){ 45 | int fd = sysSocket(domain, type, protocol); 46 | if(!current || fd == -1) 47 | return fd; 48 | 49 | setNoBlock(fd); 50 | 51 | return fd; 52 | } 53 | 54 | int listen(int sockfd, int backlog){ 55 | int ret = sysListen(sockfd, backlog); 56 | return ret; 57 | } 58 | 59 | int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen){ 60 | int ret = sysConnect(sockfd, addr, addrlen); 61 | if(!current) 62 | return ret; 63 | 64 | int error = -1; 65 | socklen_t len = sizeof(error); 66 | if(ret != -1) 67 | return ret; 68 | if(errno != EINPROGRESS) 69 | return ret; 70 | if(waitOnWrite(sockfd) < 0) 71 | return ret; 72 | 73 | ret = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len); 74 | if(ret < 0) 75 | return ret; 76 | if(error != 0) 77 | errno = error; 78 | 79 | return ret; 80 | } 81 | 82 | int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen){ 83 | int fd = sysAccept(sockfd, addr, addrlen); 84 | if(!current) 85 | return fd; 86 | 87 | if(fd != -1){ 88 | setNoBlock(fd); 89 | return fd; 90 | } 91 | if(errno != EAGAIN) 92 | return -1; 93 | if(waitOnRead(sockfd) < 0) 94 | return -1; 95 | 96 | return accept(sockfd, addr, addrlen); 97 | } 98 | 99 | ssize_t read(int fd, void *buf, size_t count){ 100 | int ret = sysRead(fd, buf, count); 101 | if(!current) 102 | return ret; 103 | 104 | if(ret != -1 || errno != EAGAIN) 105 | return ret; 106 | 107 | if(waitOnRead(fd) < 0) 108 | return ret; 109 | 110 | return read(fd, buf, count); 111 | } 112 | 113 | ssize_t write(int fd, const void *buf, size_t count){ 114 | int ret = sysWrite(fd, buf, count); 115 | if(!current) 116 | return ret; 117 | 118 | if(ret != -1 || errno != EAGAIN) 119 | return ret; 120 | 121 | if(waitOnWrite(fd) < 0) 122 | return ret; 123 | 124 | return write(fd, buf, count); 125 | } 126 | 127 | int close(int fd){ 128 | clear(current); 129 | 130 | return sysClose(fd); 131 | } 132 | 133 | unsigned int sleep(unsigned int seconds){ 134 | int ret; 135 | if(!current) 136 | return sysSleep(seconds); 137 | else 138 | ret = waitOnTimer((seconds + time(NULL))*1000); 139 | 140 | return ret; 141 | } 142 | 143 | int dup(int oldfd){ 144 | int fd = sysDup(oldfd); 145 | if(!current) 146 | return fd; 147 | 148 | if(fd != -1){ 149 | setNoBlock(fd); 150 | } 151 | 152 | return fd; 153 | } 154 | 155 | -------------------------------------------------------------------------------- /test/channel.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "coroutine.h" 5 | #include "sync.h" 6 | #include "log.h" 7 | 8 | using namespace std; 9 | 10 | bool isExit = false; 11 | 12 | Atomic atomic; 13 | Channel channel(10); 14 | 15 | int producer(void *){ 16 | while(!isExit){ 17 | int item = atomic.inc(); 18 | log(INFO, "producer %d", item); 19 | //channel.push(item); 20 | channel<>item; 29 | log(INFO, "consumer %d", item); 30 | } 31 | } 32 | 33 | void *Producer(void *){ 34 | createCoroutine(producer, NULL); 35 | createCoroutine(producer, NULL); 36 | createCoroutine(producer, NULL); 37 | createCoroutine(producer, NULL); 38 | createCoroutine(producer, NULL); 39 | createCoroutine(producer, NULL); 40 | createCoroutine(producer, NULL); 41 | createCoroutine(producer, NULL); 42 | createCoroutine(producer, NULL); 43 | yield; 44 | } 45 | 46 | void *Consumer(void *){ 47 | createCoroutine(consumer, NULL); 48 | createCoroutine(consumer, NULL); 49 | createCoroutine(consumer, NULL); 50 | yield; 51 | } 52 | 53 | void quit(int signo) 54 | { 55 | isExit = true; 56 | stopCoroutines(); 57 | } 58 | 59 | void ignore(int signo){ 60 | cout<<"ignore signo "< 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "coroutine.h" 13 | #include "log.h" 14 | 15 | 16 | bool isExit = false; 17 | 18 | int readWriteRoutine(void *arg){ 19 | 20 | int fd = socket(AF_INET, SOCK_STREAM, 0); 21 | if(-1 == fd) 22 | { 23 | printf("create socket fail error:%s\n",strerror(errno)); 24 | return -1; 25 | } 26 | 27 | struct sockaddr_in addr; 28 | bzero(&addr,sizeof(struct sockaddr_in)); 29 | addr.sin_family=AF_INET; 30 | addr.sin_addr.s_addr= inet_addr("127.0.0.1"); 31 | addr.sin_port=htons(5566); 32 | 33 | if(connect(fd,(struct sockaddr *)(&addr), sizeof(struct sockaddr)) < 0) 34 | { 35 | printf("connect fail error:%s \n",strerror(errno)); 36 | return -1; 37 | } 38 | 39 | char buf[]="I am coming,,,,,,,"; 40 | 41 | while(!isExit){ 42 | int ret = write(fd,buf,sizeof(buf)); 43 | if(ret <= 0){ 44 | log(ERROR, "fd:%d write error:%s", fd, strerror(errno)); 45 | break; 46 | } 47 | //log(INFO, "fd:%d send %s\n", fd, buf); 48 | 49 | ret = read(fd,buf,sizeof(buf)); 50 | if(ret < 0){ 51 | log(ERROR, "fd:%d read error:%s", fd, strerror(errno)); 52 | break; 53 | } 54 | } 55 | close(fd); 56 | return 0; 57 | } 58 | 59 | void quit(int signo) 60 | { 61 | isExit = true; 62 | stopCoroutines(); 63 | } 64 | 65 | int main(int argvs, char *argv[]) 66 | { 67 | signal(SIGINT, quit); 68 | signal(SIGTERM, quit); 69 | signal(SIGPIPE, SIG_IGN); 70 | 71 | for(int i=0; i<10000 && !isExit; i++) 72 | createCoroutine(readWriteRoutine, NULL); 73 | 74 | yield; 75 | 76 | log(INFO, "exit sucess"); 77 | } 78 | -------------------------------------------------------------------------------- /test/cond.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "coroutine.h" 5 | #include "log.h" 6 | #include 7 | #include "sync.h" 8 | 9 | using namespace std; 10 | 11 | bool isExit = false; 12 | 13 | int i =0; 14 | Mutex mutex; 15 | Cond condNotFull, condNotEmpty; 16 | list que; 17 | 18 | int producer(void *){ 19 | while(!isExit){ 20 | mutex.lock(); 21 | 22 | while(que.size() == 10 && !isExit){ 23 | log(INFO, "que full %d wait", que.size()); 24 | condNotFull.wait(mutex); 25 | log(INFO, "wakeup"); 26 | } 27 | 28 | int tmp = i++; 29 | que.push_back(i); 30 | log(INFO, "producer %d", tmp); 31 | 32 | mutex.unlock(); 33 | condNotEmpty.signal(); 34 | } 35 | condNotEmpty.broadcast(); 36 | } 37 | 38 | int consumer(void *){ 39 | while(!isExit){ 40 | mutex.lock(); 41 | 42 | while(que.empty() && !isExit){ 43 | log(INFO, "que empty %d wait", que.size()); 44 | condNotEmpty.wait(mutex); 45 | log(INFO, "wakeup"); 46 | } 47 | 48 | if(!que.empty()){ 49 | int tmp = que.front(); 50 | log(INFO, "consumer %d", tmp); 51 | que.pop_front(); 52 | } 53 | 54 | mutex.unlock(); 55 | condNotFull.signal(); 56 | } 57 | condNotFull.broadcast(); 58 | } 59 | 60 | 61 | void *Consumer(void *){ 62 | createCoroutine(consumer, NULL); 63 | createCoroutine(consumer, NULL); 64 | createCoroutine(consumer, NULL); 65 | yield; 66 | } 67 | 68 | void *Producer(void *){ 69 | createCoroutine(producer, NULL); 70 | createCoroutine(producer, NULL); 71 | createCoroutine(producer, NULL); 72 | yield; 73 | } 74 | 75 | void quit(int signo) 76 | { 77 | isExit = true; 78 | stopCoroutines(); 79 | } 80 | 81 | void ignore(int signo){ 82 | cout<<"ignore signo "< 2 | #include "coroutine.h" 3 | #include "sync.h" 4 | #include "log.h" 5 | 6 | int ret[10] = {0}; 7 | int arr[1000] = {0}; 8 | CountDownLatch latch(10); 9 | 10 | int map(void *arg){ 11 | int startIdx = *(int*)arg; 12 | 13 | for(int i = startIdx; i < startIdx + 100; i++){ 14 | ret[startIdx/100] += arr[i]; 15 | yield; 16 | } 17 | 18 | latch.countDown(); 19 | log(INFO, "map[%d-%d] = %d exit count %d", startIdx, startIdx + 100, ret[startIdx/100], latch.getCount()); 20 | } 21 | 22 | int reduce(void *){ 23 | latch.wait(); 24 | 25 | long sum = 0; 26 | for(int i = 0; i< 10; i++) 27 | sum += ret[i]; 28 | log(INFO, "reduce %d exit", sum); 29 | } 30 | 31 | void *startMapTask(void *arg){ 32 | int startIdx = *(int*)arg; 33 | int args[5]; 34 | int j=0; 35 | 36 | for(int i = startIdx; i < startIdx + 500; i+=100){ 37 | args[j] = i; 38 | createCoroutine(map, args + j++); 39 | } 40 | 41 | yield; 42 | log(INFO, "exit sucess"); 43 | } 44 | 45 | void *startReduceTask(void *){ 46 | createCoroutine(reduce, NULL); 47 | yield; 48 | log(INFO, "exit sucess"); 49 | } 50 | 51 | int main(){ 52 | for(int i = 1; i <= 1000; i++) 53 | arr[i-1] = i; 54 | 55 | pthread_t t0,t1,t2; 56 | int startIdx0 = 0, startIdx1 = 500; 57 | 58 | pthread_create(&t0, NULL, startReduceTask, NULL); 59 | pthread_create(&t1, NULL, startMapTask, &startIdx0); 60 | pthread_create(&t2, NULL, startMapTask, &startIdx1); 61 | 62 | pthread_join(t0, NULL); 63 | pthread_join(t1, NULL); 64 | pthread_join(t2, NULL); 65 | 66 | log(INFO, "exit sucess"); 67 | } 68 | 69 | -------------------------------------------------------------------------------- /test/multiThreadServer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "coroutine.h" 8 | #include "log.h" 9 | #include "syscall.h" 10 | 11 | volatile bool isExit = false; 12 | 13 | int socketHandleCoroutine(void *arg){ 14 | char buf[19]; 15 | int fd = *(int*)arg; 16 | 17 | //log(INFO, "start socketHandleCoroutine fd:%d", fd); 18 | 19 | while(!isExit){ 20 | int ret = read(fd, buf, 19); 21 | if(ret == 0) 22 | break; 23 | else if(ret < 0){ 24 | //log(ERROR, "fd:%d read error:%s\n", fd, strerror(errno)); 25 | break; 26 | } 27 | //log(INFO, "fd:%d recv %s", fd, buf); 28 | 29 | ret = write(fd, buf, 19); 30 | if(ret <= 0){ 31 | //log(ERROR, "fd:%d write error:%s\n", fd, strerror(errno)); 32 | break; 33 | } 34 | } 35 | close(fd); 36 | delete (int*)arg; 37 | 38 | return 0; 39 | } 40 | 41 | int acceptCoroutine(void *arg){ 42 | int serverFd = dup(*(int*)arg); 43 | 44 | while(!isExit){ 45 | int *clientFd = new int; 46 | 47 | if((*clientFd = accept(serverFd, NULL ,NULL)) != -1){ 48 | //log(INFO, "accept fd %d", *clientFd); 49 | createCoroutine(socketHandleCoroutine, (void*)clientFd); 50 | }else{ 51 | log(ERROR, "accept error:%s", strerror(errno)); 52 | break; 53 | } 54 | } 55 | 56 | close(serverFd); 57 | return 0; 58 | } 59 | 60 | void quit(int signo) 61 | { 62 | isExit = true; 63 | stopCoroutines(); 64 | } 65 | 66 | void *fun(void *arg){ 67 | int fd = *(int*)arg; 68 | 69 | Coroutine *co = createCoroutine(acceptCoroutine, &fd); 70 | 71 | co->setPrio(1); 72 | yield; 73 | 74 | log(INFO, "exit sucess"); 75 | } 76 | 77 | void *fun1(void *arg){ 78 | 79 | sysSleep(60); 80 | yield; 81 | 82 | log(INFO, "exit sucess"); 83 | } 84 | 85 | 86 | int main(int argc, char** argv){ 87 | signal(SIGINT, quit); 88 | signal(SIGTERM, quit); 89 | signal(SIGPIPE, SIG_IGN); 90 | 91 | int serverFd; 92 | struct sockaddr_in addr; 93 | 94 | if((serverFd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ 95 | printf("create socket error: %s\n", strerror(errno)); 96 | return 0; 97 | } 98 | 99 | memset(&addr, 0, sizeof(addr)); 100 | addr.sin_family = AF_INET; 101 | addr.sin_addr.s_addr = htonl(INADDR_ANY); 102 | addr.sin_port = htons(5566); 103 | if(bind(serverFd, (struct sockaddr*)&addr, sizeof(addr)) < 0){ 104 | printf("bind socket error: %s)\n", strerror(errno)); 105 | return 0; 106 | } 107 | if(listen(serverFd, 10000) < 0){ 108 | printf("listen socket error: %s\n", strerror(errno)); 109 | return 0; 110 | } 111 | 112 | pthread_t t0,t1,t2; 113 | pthread_create(&t0, NULL, fun , &serverFd); 114 | pthread_create(&t1, NULL, fun1, NULL); 115 | pthread_create(&t2, NULL, fun1, NULL); 116 | 117 | pthread_join(t0, NULL); 118 | pthread_join(t1, NULL); 119 | pthread_join(t2, NULL); 120 | 121 | close(serverFd); 122 | 123 | log(INFO, "exit sucess"); 124 | } 125 | -------------------------------------------------------------------------------- /test/mutex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "coroutine.h" 5 | #include "sync.h" 6 | #include "log.h" 7 | 8 | using namespace std; 9 | 10 | bool isExit = false; 11 | 12 | Mutex mutex; 13 | 14 | int i =0; 15 | 16 | int test(void *){ 17 | while(!isExit){ 18 | mutex.lock(); 19 | 20 | if(i == 1000000000){ 21 | mutex.unlock(); 22 | break; 23 | } 24 | i++; 25 | 26 | mutex.unlock(); 27 | } 28 | } 29 | 30 | void *fun(void *){ 31 | createCoroutine(test, NULL); 32 | createCoroutine(test, NULL); 33 | createCoroutine(test, NULL); 34 | yield; 35 | } 36 | 37 | void quit(int signo) 38 | { 39 | isExit = true; 40 | stopCoroutines(); 41 | } 42 | 43 | void ignore(int signo){ 44 | cout<<"ignore signo "< 2 | #include 3 | #include "coroutine.h" 4 | #include "log.h" 5 | 6 | using namespace std; 7 | 8 | int test1(void *){ 9 | cout<<"test1"<setPrio(8); 32 | co2->setPrio(5); 33 | co3->setPrio(1); 34 | 35 | co1->start(); 36 | co2->start(); 37 | co3->start(); 38 | 39 | yield; 40 | 41 | log(INFO, "exit sucess"); 42 | } 43 | -------------------------------------------------------------------------------- /test/sem.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "coroutine.h" 5 | #include "log.h" 6 | #include 7 | #include "sync.h" 8 | 9 | using namespace std; 10 | 11 | bool isExit = false; 12 | 13 | int i =0; 14 | SpinLocker locker; 15 | Sem sem(10); 16 | list que; 17 | 18 | int producer(void *){ 19 | while(!isExit){ 20 | sem.wait(); 21 | 22 | locker.lock(); 23 | int tmp = i++; 24 | que.push_back(i); 25 | log(INFO, "producer %d", tmp); 26 | locker.unlock(); 27 | } 28 | } 29 | 30 | int consumer(void *){ 31 | while(!isExit){ 32 | locker.lock(); 33 | if(!que.empty()){ 34 | int tmp = que.front(); 35 | log(INFO, "consumer %d", tmp); 36 | que.pop_front(); 37 | } 38 | locker.unlock(); 39 | 40 | sem.signal(); 41 | } 42 | } 43 | 44 | 45 | void *Consumer(void *){ 46 | createCoroutine(consumer, NULL); 47 | createCoroutine(consumer, NULL); 48 | createCoroutine(consumer, NULL); 49 | yield; 50 | } 51 | 52 | void *Producer(void *){ 53 | createCoroutine(producer, NULL); 54 | createCoroutine(producer, NULL); 55 | createCoroutine(producer, NULL); 56 | yield; 57 | } 58 | 59 | void quit(int signo) 60 | { 61 | isExit = true; 62 | stopCoroutines(); 63 | } 64 | 65 | void ignore(int signo){ 66 | cout<<"ignore signo "< 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "coroutine.h" 9 | #include "log.h" 10 | 11 | bool isExit = false; 12 | 13 | int socketHandleCoroutine(void *arg){ 14 | char buf[32]; 15 | int fd = *(int*)arg; 16 | 17 | log(INFO, "start socketHandleCoroutine fd:%d", fd); 18 | 19 | while(!isExit){ 20 | int ret = read(fd, buf, 19); 21 | if(ret <= 0) 22 | break; 23 | log(INFO, "fd:%d recv %s", fd, buf); 24 | 25 | ret = write(fd, buf, 19); 26 | if(ret <= 0){ 27 | log(ERROR, "fd:%d write error:%s\n", fd, strerror(errno)); 28 | break; 29 | } 30 | } 31 | close(fd); 32 | delete (int*)arg; 33 | 34 | return 0; 35 | } 36 | 37 | int acceptCoroutine(void *arg){ 38 | int serverFd; 39 | struct sockaddr_in addr; 40 | 41 | if((serverFd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ 42 | log(ERROR, "create socket error: %s\n", strerror(errno)); 43 | return 0; 44 | } 45 | 46 | memset(&addr, 0, sizeof(addr)); 47 | addr.sin_family = AF_INET; 48 | addr.sin_addr.s_addr = htonl(INADDR_ANY); 49 | addr.sin_port = htons(5566); 50 | if(bind(serverFd, (struct sockaddr*)&addr, sizeof(addr)) < 0){ 51 | log(ERROR, "bind socket error: %s)\n", strerror(errno)); 52 | return 0; 53 | } 54 | if(listen(serverFd, 10000) < 0){ 55 | log(ERROR, "listen socket error: %s\n", strerror(errno)); 56 | return 0; 57 | } 58 | 59 | 60 | while(!isExit){ 61 | int *clientFd = new int; 62 | 63 | if((*clientFd = accept(serverFd, NULL, NULL)) > 2){ 64 | log(INFO,"accept fd %d", *clientFd); 65 | createCoroutine(socketHandleCoroutine, (void*)clientFd); 66 | }else{ 67 | log(ERROR, "accept error:%s", strerror(errno)); 68 | break; 69 | } 70 | 71 | } 72 | 73 | close(serverFd); 74 | } 75 | 76 | void quit(int signo) 77 | { 78 | isExit = true; 79 | stopCoroutines(); 80 | } 81 | 82 | int main(int argc, char** argv){ 83 | signal(SIGINT, quit); 84 | signal(SIGTERM, quit); 85 | signal(SIGPIPE, SIG_IGN); 86 | 87 | Coroutine *co = new Coroutine(acceptCoroutine, NULL); 88 | co->setPrio(1); 89 | yield; 90 | 91 | log(INFO, "exit sucess"); 92 | } 93 | 94 | -------------------------------------------------------------------------------- /test/signal.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "csignal.h" 3 | #include 4 | #include "coroutine.h" 5 | #include "log.h" 6 | 7 | using namespace std; 8 | 9 | Coroutine *co0 = NULL; 10 | Coroutine *co1 = NULL; 11 | Coroutine *co2 = NULL; 12 | Coroutine *co3 = NULL; 13 | 14 | int test0(void *arg){ 15 | cout< 2 | #include "coroutine.h" 3 | #include "log.h" 4 | 5 | using namespace std; 6 | 7 | int test0(void *){ 8 | cout<<"test0 0"< 2 | #include 3 | #include "coroutine.h" 4 | #include "log.h" 5 | 6 | using namespace std; 7 | 8 | int test0(void *){ 9 | cout<<"test0 0"<