getcontext/setupcontext/swapcontext/setcontext 方式的协程实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <poll.h>
#include <errno.h>
#include <unistd.h>
#include <ucontext.h>
#include <sys/time.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/in.h> #define MYPORT 12345
#define MAX_STACK 8192
#define MAX_EVENTS 1024 int epollfd; typedef struct sock_ctx {
int sock ;
ucontext_t * rctx ;
ucontext_t * wctx ;
}sock_ctx; void read_sock();
void write_sock(); uint32_t high32(uint64_t value) {
return value >> 32;
} uint32_t low32(uint64_t value) {
return value;
} void * make64(uint32_t low, uint32_t high) {
return (void *)((uint64_t) high << 32 | low);
} void setupcontext(ucontext_t * ctx, sock_ctx * sockctx, void(*func)()) {
makecontext( ctx, func, 2, low32((uint64_t)sockctx), high32((uint64_t)sockctx) );
} // 定义
int epoll_action(int epollevt, sock_ctx* sockctx, int action) {
struct epoll_event event;
event.events = epollevt;
event.data.ptr = sockctx;
return epoll_ctl(epollfd, action, sockctx->sock, &event);
} // 宏定义
#define epoll_mod(epollevt, sockctx) epoll_action(epollevt, sockctx, EPOLL_CTL_MOD)
// 宏定义
#define epoll_add(epollevt, sockctx) epoll_action(epollevt, sockctx, EPOLL_CTL_ADD)
// 宏定义
#define epoll_del(sockctx) epoll_ctl(epollfd, EPOLL_CTL_DEL, sockctx->sock, NULL) void write_sock(int low, int high) {
sock_ctx * sockctx = (sock_ctx *)make64(low, high);
epoll_mod(EPOLLIN, sockctx);
printf("write_sock[%d] --- function\n", (int)sockctx->sock);
setcontext( sockctx->wctx->uc_link );
} void read_sock(int low, int high) {
sock_ctx * sockctx = (sock_ctx *)make64(low, high);
while ( 1 ) {
char body[1024] = {0};
int ret = recv( sockctx->sock, (char *)body, 1024, 0 );
if ( ret == 0 ) {
printf("sock disconnect\n");
epoll_del(sockctx);
setcontext(sockctx->rctx->uc_link);
break;
} else if ( ret < 0 ) {
printf("sock error : %d\n", errno);
break;
} printf("read_sock[%d] --- buf = %s\n", sockctx->sock, body);
if ( ret < 1024 ) {
break;
}
} epoll_mod(EPOLLOUT, sockctx);
printf("read_sock[%d] --- function\n", (int)sockctx->sock);
setcontext( sockctx->rctx->uc_link );
} void accept_sock(int low, int high) {
struct sockaddr_in sin;
socklen_t len = sizeof(struct sockaddr_in);
sock_ctx * tmpctx = (sock_ctx *)make64(low, high);
bzero(&sin, len);
int confd = accept(tmpctx->sock, (struct sockaddr*)&sin, &len);
if ( confd < 0 ) {
printf("bad accept\n");
return;
} sock_ctx * sockctx = malloc(sizeof(sock_ctx));
sockctx->sock = confd;
sockctx->rctx = malloc(sizeof(ucontext_t));
sockctx->wctx = malloc(sizeof(ucontext_t));
getcontext(sockctx->rctx);
getcontext(sockctx->wctx); sockctx->rctx ->uc_link = tmpctx->rctx->uc_link;
sockctx->rctx ->uc_stack.ss_size = MAX_STACK;
sockctx->rctx ->uc_stack.ss_sp = malloc(MAX_STACK);
sockctx->wctx ->uc_link = tmpctx->rctx->uc_link;
sockctx->wctx ->uc_stack.ss_size = MAX_STACK;
sockctx->wctx ->uc_stack.ss_sp = malloc(MAX_STACK);
setupcontext( sockctx->rctx, sockctx, (void(*)())read_sock );
setupcontext( sockctx->wctx, sockctx, (void(*)())write_sock );
printf("accept_sock ---- new connection %d\n", confd); if ( epoll_add(EPOLLIN, sockctx) < 0 ) {
printf( "epoll_ctl failed\n" ) ;
return;
}
setcontext ( tmpctx->rctx->uc_link ) ;
} //-------------------------------------------------------
// 这个方式性能不一定高,只是演示协程的用法
//-------------------------------------------------------
int main() {
ucontext_t ctx_main;
int i, timeout = 100000;
fd_set readfds, writefds;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr; int sockListen = socket(AF_INET, SOCK_STREAM, 0);
if ( sockListen < 0 ) {
printf("socket error\n");
return -1;
} bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(MYPORT);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if ( bind(sockListen, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0 ) {
printf("bind error\n");
return -1;
} if ( listen(sockListen, 5) < 0 ) {
printf("listen error\n");
return -1;
} epollfd = epoll_create(MAX_EVENTS);
sock_ctx * sockctx = malloc(sizeof(sock_ctx));
sockctx->sock = sockListen;
sockctx->wctx = 0;
sockctx->rctx = malloc(sizeof(ucontext_t));
getcontext( sockctx->rctx ); sockctx->rctx->uc_link = &ctx_main;
sockctx->rctx->uc_stack.ss_size = MAX_STACK;
sockctx->rctx->uc_stack.ss_sp = malloc(MAX_STACK);
setupcontext( sockctx->rctx, sockctx, (void(*)())accept_sock ); if ( epoll_add(EPOLLIN, sockctx) < 0 ) {
printf("epoll add fail : fd = %d\n", sockListen);
return -1;
} while ( 1 ) {
struct epoll_event eventList[MAX_EVENTS];
int ret = epoll_wait(epollfd, eventList, MAX_EVENTS, timeout);
if ( ret == 0 ) {
continue;
} else if ( ret < 0 ) {
break;
} printf("epoll_wait wakeup enter\n");
for ( i = 0; i < ret; i++ ) {
sock_ctx * sockctx = (sock_ctx *)eventList[i].data.ptr ;
if ( (eventList[i].events & EPOLLERR) || (eventList[i].events & EPOLLHUP) ) {
printf ( "sock[%d] error\n", sockctx->sock );
close (sockctx->sock);
continue;
}
if ( eventList[i].events & EPOLLIN ) {
if ( swapcontext( &ctx_main, sockctx->rctx ) == -1 ) {
printf ( "swapcontext read error\n");
}
} else if ( eventList[i].events & EPOLLOUT ) {
if ( swapcontext( &ctx_main, sockctx->wctx ) == -1 ) {
printf ( "swapcontext write error\n");
}
}
}
printf("epoll_wait wakeup leave\n");
} close(epollfd);
close(sockListen); return 0;
}

  setjmp/longjmp 的实现方式

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <poll.h>
#include <errno.h>
#include <unistd.h>
#include <setjmp.h>
#include <sys/time.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/in.h> #define MYPORT 12345
#define MAX_STACK 8192
#define MAX_EVENTS 1024 int epollfd;
struct epoll_event eventList[MAX_EVENTS]; typedef struct sock_ctx {
int sock;
jmp_buf rjmp; // read jmp
jmp_buf wjmp; // write jmp
jmp_buf bjmp; // back jmp
}sock_ctx; //-----------------------------------------------------------------------------------------
// 很多函数内的参数和变量经过 setjmp/longjmp 后,并不能正确恢复,所以需要重新赋值
// setjmp/longjmp 中间可能会被 信号中断,堆栈信息也不能恢复,想做成熟的框架,还得继续改进
//----------------------------------------------------------------------------------------- // 挂起 ( 不能用函数 setjmp 需要保存当前函数的栈帧信息 )
#define co_yield(oldjmp, newjmp, value) \
int setjmp_ret = setjmp(oldjmp); \
if ( 0 == setjmp_ret ) { \
longjmp(newjmp, value); \
} // 定义
int epoll_action(int epollevt, sock_ctx* sockctx, int action) {
struct epoll_event event;
event.events = epollevt;
event.data.ptr = sockctx;
return epoll_ctl(epollfd, action, sockctx->sock, &event);
} // 宏定义
#define epoll_mod(epollevt, sockctx) epoll_action(epollevt, sockctx, EPOLL_CTL_MOD)
// 宏定义
#define epoll_add(epollevt, sockctx) epoll_action(epollevt, sockctx, EPOLL_CTL_ADD)
// 宏定义
#define epoll_del(sockctx) epoll_ctl(epollfd, EPOLL_CTL_DEL, sockctx->sock, NULL) typedef void (*co_func)(jmp_buf *, sock_ctx*);
int start_coroutine(jmp_buf * tjmp, co_func func, void* arg) {
if ( 0 == setjmp(*tjmp) ) {
func(tjmp, arg);
return 0;
}
return 1;
} void write_sock(jmp_buf * newjmp, sock_ctx* sockctx) {
co_yield(sockctx->wjmp, *newjmp, 1);
sockctx = (sock_ctx*)eventList[setjmp_ret - 1].data.ptr;
printf("write_sock[%d] run %p\n", (int)sockctx->sock, sockctx); while ( 1 ) {
epoll_mod(EPOLLIN, sockctx);
printf("write_sock[%d] --- function1\n", (int)sockctx->sock); co_yield(sockctx->wjmp, sockctx->bjmp, 1);
sockctx = (sock_ctx*)eventList[setjmp_ret - 1].data.ptr;
printf("write_sock[%d] --- function2\n", (int)sockctx->sock);
}
} void read_sock(jmp_buf* newjmp, sock_ctx* sockctx) {
co_yield(sockctx->rjmp, *newjmp, 1);
sockctx = (sock_ctx*)eventList[setjmp_ret - 1].data.ptr;
printf("read_sock[%d] run %p\n", (int)sockctx->sock, sockctx); while ( 1 ) {
while ( 1 ) {
char body[1024] = { 0 };
int ret = recv(sockctx->sock, (char*)body, 1024, 0);
if ( ret == 0 ) {
printf("sock disconnect\n");
epoll_del(sockctx);
longjmp(sockctx->bjmp, 2);
break;
} else if ( ret < 0 ) {
printf("sock error : %d\n", errno);
break;
} printf("read_sock[%d] --- buf = %s\n", sockctx->sock, body);
if (ret < 1024) {
break;
}
} epoll_mod(EPOLLOUT, sockctx);
printf("read_sock[%d] --- function1\n", (int)sockctx->sock); co_yield(sockctx->rjmp, sockctx->bjmp, 1);
sockctx = (sock_ctx*)eventList[setjmp_ret - 1].data.ptr;
printf("read_sock[%d] --- function2\n", (int)sockctx->sock);
}
} void accept_sock(jmp_buf* newjmp, sock_ctx* tmpctx) {
co_yield(tmpctx->rjmp, *newjmp, 1);
tmpctx = (sock_ctx*)eventList[setjmp_ret - 1].data.ptr;
printf("accept_sock run %d: %p\n", setjmp_ret, tmpctx); while ( 1 ) {
struct sockaddr_in sin;
socklen_t len = sizeof(struct sockaddr_in);
bzero(&sin, len);
int confd = accept(tmpctx->sock, (struct sockaddr*)&sin, &len);
if (confd < 0) {
printf("%d bad accept(%d)\n", tmpctx->sock, errno);
return;
} sock_ctx* sockctx = malloc(sizeof(sock_ctx));
sockctx->sock = confd;
start_coroutine(&tmpctx->rjmp, read_sock, sockctx);
start_coroutine(&tmpctx->rjmp, write_sock, sockctx);
printf("accept_sock ---- new connection %d\n", confd); epoll_add(EPOLLIN, sockctx);
printf("accept_sock[%d] --- function1\n", (int)tmpctx->sock); co_yield(tmpctx->rjmp, tmpctx->bjmp, 1);
tmpctx = (sock_ctx*)eventList[setjmp_ret - 1].data.ptr;
printf("accept_sock[%d] --- function2\n", (int)tmpctx->sock);
}
} int main() {
int i, timeout = 100000;
fd_set readfds, writefds;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr; int sockListen = socket(AF_INET, SOCK_STREAM, 0);
if ( sockListen < 0 ) {
printf("socket error\n");
return -1;
} bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(MYPORT);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if ( bind(sockListen, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0 ) {
printf("bind error\n");
return -1;
} if ( listen(sockListen, 5) < 0 ) {
printf("listen error\n");
return -1;
} epollfd = epoll_create(MAX_EVENTS); jmp_buf mjmp;
sock_ctx* sockctx = malloc(sizeof(sock_ctx));
sockctx->sock = sockListen;
start_coroutine(&mjmp, accept_sock, sockctx);
if ( -1 == epoll_add(EPOLLIN, sockctx)) {
printf("epoll_ctl error\n");
return -1;
} while ( 1 ) {
int ret = epoll_wait(epollfd, eventList, MAX_EVENTS, timeout);
if ( ret == 0 ) {
continue;
} else if ( ret < 0 ) {
break;
} printf("epoll_wait wakeup enter\n");
for ( i = 0; i < ret; i++ ) {
sock_ctx * sockctx = (sock_ctx *)eventList[i].data.ptr ;
if ( (eventList[i].events & EPOLLERR) || (eventList[i].events & EPOLLHUP) ) {
printf ( "sock[%d] error\n", sockctx->sock );
close (sockctx->sock);
continue;
}
if ( eventList[i].events & EPOLLIN ) {
co_yield(sockctx->bjmp, sockctx->rjmp, i + 1);
} else if ( eventList[i].events & EPOLLOUT ) {
co_yield(sockctx->bjmp, sockctx->wjmp, i + 1);
}
}
printf("epoll_wait wakeup leave\n");
} close(epollfd);
close(sockListen); return 0;
}

  

协程 + epoll 的两个小例子的更多相关文章

  1. vuex2.0+两个小例子

    首先vuex概念比较多,一定要搞懂里面的概念,可以参考官网Vuex2.0概念,我写此文的目的是希望能对前端爱好者提供个参考,加深对vuex2.0各核心概念的理解. 废话少说,直接上干货.这是官网上的一 ...

  2. Vuex2.0边学边记+两个小例子

    最近在研究Vuex2.0,搞了好几天终于有点头绪了. 首先vuex概念比较多,一定要搞懂里面的概念,可以参考官网Vuex2.0概念,我写此文的目的是希望能对前端爱好者提供个参考,加深对vuex2.0各 ...

  3. libconfig第二篇----两个小例子

    本文只看粗体即可,太多catch语句.两个例子均来自libconfig包的example文件夹下面,. 例子一: #include <iostream> #include <ioma ...

  4. 学习HttpClient,从两个小例子开始

    前言 HTTP(Hyper-Text Transfer Protocol,超文本传输协议)在如今的互联网也许是最重要的协议,我们每天做的很多事情都与之有关,比如,网上购物.刷博客.看新闻等.偶尔你的上 ...

  5. 两个小例子彻底明白python decorator

    一:没有什么实际意思,就是单纯的理解decorator.使用装饰器完全可以阻止方法中的代码执行. class json_test(object): def __init__(self, *arg, * ...

  6. 关于Finereport移动端报表二次开发的两个小例子

    例1:刷新页面 1. 问题描述 A超链至B填报,B提交数据后返回A时,A自动刷新显示新的数据. 2. 解决方案 1. contentPane.setAppearRefresh();  //在A的加载结 ...

  7. 协程实现tcp两个客户端的通讯

    import socket import gevent from gevent import monkey monkey.patch_all() def cb_work(recv_num,send_n ...

  8. 基于ASIO的协程与网络编程

    协程 协程,即协作式程序,其思想是,一系列互相依赖的协程间依次使用CPU,每次只有一个协程工作,而其他协程处于休眠状态.协程可以在运行期间的某个点上暂停执行,并在恢复运行时从暂停的点上继续执行. 协程 ...

  9. 12.python进程\协程\异步IO

    进程 创建进程 from multiprocessing import Process import time def func(name): time.sleep(2) print('hello', ...

  10. 线程池、进程池(concurrent.futures模块)和协程

    一.线程池 1.concurrent.futures模块 介绍 concurrent.futures模块提供了高度封装的异步调用接口 ThreadPoolExecutor:线程池,提供异步调用 Pro ...

随机推荐

  1. 博弈论[leetocde913]

    class Solution { static final int MOUSE_WIN = 1; static final int CAT_WIN = 2; static final int DRAW ...

  2. 学习dash篇-layout页面布局

    Dash介绍 Dash官网教程地址:https://dash.plotly.com/introduction 数据分析工作的结果,通常是数据表格.图表,分析报告.这些东西office的三件套基本都能满 ...

  3. <鸳鸯刀>&<白马啸西风>随笔

    这两部作品比较小众,也不如之前的作品优秀,因此简单写一下好了. <鸳鸯刀> 陕西西安府威信镖局的总镖头."铁鞭镇八方"周威信,带领一支七十多人的镖队正前往京城.路途之上 ...

  4. EF getCookie

    table class="table table-bordered"> <thead> <tr> <td>商品名称</td> ...

  5. linux修改网络

    如何修改ip 临时方法: ifconfig DIVICE IP netmask NETMASK 知识临时修改ip,重启或重启网络恢复 在一个网卡上设置多个ip ifconfig DEVICE:NUMB ...

  6. DAST 代码分析

    DA部分 输入图片大小: images.size: torch.Size([1, 3, 512, 1024])labels.size: torch.Size([1, 512, 1024]) input ...

  7. Day09-方法

    方法 一.何谓方法 java方法是语句的集合,他们在一起执行一个功能 方法是解决一类问题的步骤的有序集合 方法包含于类或对象中 方法在程序中被创建,在其他地方被引用 设计方法的原则: 方法的本意是功能 ...

  8. python3 文件上传

    1 # 文件上传方法 2 def upload_files(filepath, url, headers, data): 3 filename = filepath.split('\\')[-1] 4 ...

  9. elementUI el-tree报错 Cannot read property ‘setCheckedKeys’ of undefined"

    给树节点赋值时,执行下面代码会报错,原因是:DOM元素未加载完成. 以下为错误写法. handleRowClick(row) { this.$refs.tree.setCheckedKeys(ids) ...

  10. 【python】第一模块 步骤四 第二课、实现飞机大战(未完待续)

    第二课.实现飞机大战 一.项目介绍 项目实战:飞机大战 课程目标 掌握面向对象分析和开发的思想 能对项目进行拆分,进行模块化开发 了解项目开发的基本流程 理解并运用python的包.模块相关知识 理解 ...