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. 25 bootstrap--v3--datetimepicker时间选择器--应用

    在模板中引用响应的文件 比如: layout.html <link rel="stylesheet" href="{% static 'stark/plugins/ ...

  2. WSL2与ensp的40故障

    在使用ensp做radius认证的时候看到了Linux平台的freeradius认证服务器,于是使用了Windows平台的sub system: WSL2,按照网上的教程安装,并且安装了docker ...

  3. freeswitch开启https,wss

    1.sip.js配置访问wss://域名:7443 2.freeswitch配置certs,使用cat   .pem .key >wss.pem,合成wss证书.需重启freeswitch 3. ...

  4. Mybatis框架中 collection 标签 和 association标签中关于 columnPrefix 属性的底层逻辑

    columnPrefix的作用是给column自动拼接上前缀, 已知多重嵌套的collection 和 association的columnPrefix属性的值是会叠加的 <associatio ...

  5. SAP ABAP 验证与替代

    1.校验与替代的作用 校验(Validation):在凭证保存前根据设置条件判断此凭证是否有效,其中可以按抬头.行项目或完全凭证来判断,然后再根据Validation设置的消息类型决定凭证是否允许保存 ...

  6. 【pyqtgraph】pyqtgraph可移动竖线LineSegmentROI的拖拽事件相关

    情景 Python+PyQt+pyqtgraph读取数据绘图,并在图像上添加了LineSegmentROI带handle的竖线(hanlde是为了RectROI的拖动),现要实现竖线可以直接拖动,并在 ...

  7. homework1(1)

    来自桂林理工大学物联网工程2019届的April 没参与过什么比赛项目但是课程学习能力还行,主要是快速学习之后很快就会忘记,接下来应该好好的总结并熟练记住运用知识完成对生活等各种的实践. 对课程的希望 ...

  8. python音乐分类--knn

    1 #利用knn算法分类音乐,将音乐进行情绪分类 2 #将音乐分为兴奋的(excited), 愤怒的(angry),悲伤的(sorrowful),轻松的(relaxed) 3 4 #可分离因素 5 # ...

  9. Chorme 兼容

    Chorme自动更新,不知道什么时候版本 就变了.之前好用的代码,突然不好用了. 启动时提示Only local connections are allowed 检查一下兼容性参照下文,下载对应的Dr ...

  10. Java开发的事务

    代码来自https://blog.csdn.net/weixin_42950079/article/details/99674292 可以看出jdbc的一个事务有这么几个步骤:1.关闭sql自动提交: ...