免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: waruqi
打印 上一主题 下一主题

[C] tbox新增stackless协程支持 [复制链接]

论坛徽章:
1
程序设计版块每日发帖之星
日期:2015-11-08 06:20:00
31 [报告]
发表于 2017-01-29 15:37 |只看该作者
回复 29# yulihua49

我试下。。
  1. static tb_void_t tb_demo_coroutine_client(tb_cpointer_t priv)
  2. {
  3.     // check
  4.     tb_socket_ref_t sock = (tb_socket_ref_t)priv;
  5.     tb_assert_and_check_return(sock);

  6.     // trace
  7.     tb_trace_d("[%p]: sending %s ..", sock, g_filepath);

  8.     // init file
  9.     tb_file_ref_t file = tb_file_init(g_filepath, TB_FILE_MODE_RO | TB_FILE_MODE_BINARY);
  10.     tb_assert_and_check_return(file);

  11.     // send data
  12.     tb_hize_t send = 0;
  13.     tb_hize_t size = tb_file_size(file);
  14.     tb_long_t wait = 0;
  15.     tb_hong_t time = tb_mclock();
  16.     while (send < size)
  17.     {
  18.         // 直接发送文件,利用sendfile优化文件传输
  19.         tb_hong_t real = tb_socket_sendf(sock, file, send, size - send);

  20.         // trace
  21.         tb_trace_d("[%p]: send: %ld", sock, real);

  22.         // has data?
  23.         if (real > 0)
  24.         {
  25.             send += real;
  26.             wait = 0;
  27.         }
  28.         // no data? wait it
  29.         else if (!real && !wait)
  30.         {
  31.             // 如果在协程模式下,会把socket添加到io调度器中,进行自动调度
  32.             wait = tb_socket_wait(sock, TB_SOCKET_EVENT_SEND, TB_DEMO_TIMEOUT);
  33.             tb_assert_and_check_break(wait >= 0);
  34.         }
  35.         // failed or end?
  36.         else break;
  37.     }

  38.     // trace
  39.     tb_trace_i("[%p]: send: %lld bytes %lld ms", sock, send, tb_mclock() - time);

  40.     // exit file
  41.     tb_file_exit(file);

  42.     // exit socket
  43.     tb_socket_exit(sock);
  44. }
  45. static tb_void_t tb_demo_coroutine_listen(tb_cpointer_t priv)
  46. {
  47.     // done
  48.     tb_socket_ref_t sock = tb_null;
  49.     do
  50.     {
  51.         // init socket
  52.         sock = tb_socket_init(TB_SOCKET_TYPE_TCP, TB_IPADDR_FAMILY_IPV4);
  53.         tb_assert_and_check_break(sock);

  54.         // bind socket
  55.         tb_ipaddr_t addr;
  56.         tb_ipaddr_set(&addr, tb_null, TB_DEMO_PORT, TB_IPADDR_FAMILY_IPV4);
  57.         if (!tb_socket_bind(sock, &addr)) break;

  58.         // listen socket
  59.         if (!tb_socket_listen(sock, 1000)) break;

  60.         // trace
  61.         tb_trace_i("listening ..");

  62.         // 此处也会进入协程io调度,等待accept事件
  63.         while (tb_socket_wait(sock, TB_SOCKET_EVENT_ACPT, -1) > 0)
  64.         {
  65.             // accept client sockets
  66.             tb_size_t       count = 0;
  67.             tb_socket_ref_t client = tb_null;
  68.             while ((client = tb_socket_accept(sock, tb_null)))
  69.             {
  70.                 // start client connection
  71.                 if (!tb_coroutine_start(tb_null, tb_demo_coroutine_client, client, 0)) break;
  72.                 count++;
  73.             }

  74.             // trace
  75.             tb_trace_i("listened %lu", count);
  76.         }

  77.     } while (0);

  78.     // exit socket
  79.     if (sock) tb_socket_exit(sock);
  80.     sock = tb_null;
  81. }
  82. tb_int_t main(tb_int_t argc, tb_char_t** argv)
  83. {
  84.     // check
  85.     tb_assert_and_check_return_val(argc == 2 && argv[1], -1);

  86.     // the file path
  87.     tb_char_t const* filepath = argv[1];
  88.     tb_assert_and_check_return_val(filepath, -1);

  89.     // save the file path
  90.     tb_strlcpy(g_filepath, filepath, sizeof(g_filepath));

  91.     // init scheduler
  92.     tb_co_scheduler_ref_t scheduler = tb_co_scheduler_init();
  93.     if (scheduler)
  94.     {
  95.         // start listening
  96.         tb_coroutine_start(scheduler, tb_demo_coroutine_listen, tb_null, 0);

  97.         // run scheduler
  98.         tb_co_scheduler_loop(scheduler, tb_true);

  99.         // exit scheduler
  100.         tb_co_scheduler_exit(scheduler);
  101.     }
  102.     return 0;
  103. }
复制代码

论坛徽章:
1
程序设计版块每日发帖之星
日期:2015-11-08 06:20:00
32 [报告]
发表于 2017-01-29 15:38 |只看该作者
回复 29# yulihua49

可以贴代码啊。。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
33 [报告]
发表于 2017-01-29 19:46 |只看该作者
waruqi 发表于 2017-01-29 15:38
回复 29# yulihua49

可以贴代码啊。。

贴了3遍都没了,还白说了好多话,伤心了。

论坛徽章:
1
程序设计版块每日发帖之星
日期:2015-11-08 06:20:00
34 [报告]
发表于 2017-01-30 10:35 |只看该作者
额。。好吧。。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
35 [报告]
发表于 2017-02-01 20:06 |只看该作者
waruqi 发表于 2017-01-30 10:35
额。。好吧。。

static void *thread_work(void *param)
{
resource *rs=(resource *)param;
int ret,fds;
TCB *task=NULL;
struct epoll_event event;

        ShowLog(2,"%s:thread %lx start!",__FUNCTION__,pthread_self());
        getcontext(&rs->tc);
        if(task)  pthread_mutex_unlock(&task->lock);

        while(1) {
//从就绪队列取一个任务
                pthread_mutex_lock(&rpool.mut);
                while(!(task=rdy_get())) {
                        if(rpool.flg >= tpool.rdy_num) break;
                        rpool.flg++;
                        ret=pthread_cond_wait(&rpool.cond,&rpool.mut); //没有任务,等待
                        rpool.flg--;
                }
                pthread_mutex_unlock(&rpool.mut);
                if(task) {
                        if(!task->AIO_flg && !task->call_back) {
                                task->fd=task->conn.Socket;
                                ShowLog(5,"%s:tid=%lx,TCB_no=%d from rdy_queue",__FUNCTION__,
                                        pthread_self(),task->sv.TCB_no);
                                if(task->fd>=0) {
                                        do_epoll(task,0,0);
                                }
                                continue;
                        }
                } else  {
                        fds = epoll_wait(g_epoll_fd, &event, 1 , -1);
                        if(fds < 0){
                                        ShowLog(1,"%s:epoll_wait err=%d,%s",__FUNCTION__,errno,strerror(errno));
                                usleep(30000000);
                                continue;
                                }
                         task = (TCB *)event.data.ptr;
                        if(task->events) {
                            ShowLog(1,"%s:tid=%lx,TCB_no=%d,task->events=%08X,conflict!",__FUNCTION__,
                                    pthread_self(),task->sv.TCB_no,task->events);//发现惊群
                            task=NULL;
                            continue;//丢掉它
                        }
                        task->events=event.events;
                }
                rs->timestamp=now_usec();
                if(task->status>0) set_showid(task->ctx);//Showid 应该在会话上下文结构里
               
                if(task->AIO_flg) {//fiber task
                    task->uc.uc_link=&rs->tc;
                    rs->tc.uc_link=(ucontext_t *)task;
ShowLog(5,"%s:tid=%lx,resume to TCB_no=%d",__FUNCTION__,pthread_self(),task->sv.TCB_no);
                        pthread_mutex_lock(&task->lock);//防止其他线程提前闯入
                        setcontext(&task->uc);        //== longjmp()
                        continue;//no action,logic only
                }
                if(task->uc.uc_stack.ss_size>0) {//call_back模式,抢入了,进入同步模式
            rs->tc.uc_link=NULL;
ShowLog(5,"%s:tid %lx 抢入 SYNC",__FUNCTION__,pthread_self());
                        do_work(task->sv.TCB_no);
                        continue;
                }
                if(!rs->tc.uc_stack.ss_sp) {
ShowLog(5,"%s:%lx create fiber for TCB_no=%d",__FUNCTION__,rs->tid,task->sv.TCB_no);
                        task->uc.uc_stack.ss_sp=mmap(0, use_stack_size,
                                PROT_READ | PROT_WRITE | PROT_EXEC,
                                MAP_PRIVATE | MAP_ANON | MAP_GROWSDOWN, -1, 0);
                        if(task->uc.uc_stack.ss_sp==MAP_FAILED) {
                                task->uc.uc_stack.ss_sp=NULL;
                                do_work(task->sv.TCB_no); //进行你的服务,不使用AIO
                                continue;
                        }
                } else {
//ShowLog(5,"%s:%lx reuse fiber for TCB_no=%d",__FUNCTION__,rs->tid,task->sv.TCB_no);
                        task->uc.uc_stack.ss_sp=rs->tc.uc_stack.ss_sp;
                        rs->tc.uc_stack.ss_sp=NULL;
                        rs->tc.uc_stack.ss_size=0;
                }
                task->uc.uc_stack.ss_size=use_stack_size;
                task->uc.uc_link=&rs->tc;
                rs->tc.uc_link=(ucontext_t *)task;
                makecontext(&task->uc,(void (*)())do_work,1,task->sv.TCB_no);

                ret=swapcontext(&rs->tc,&task->uc);
                if(ret<0) {
                        ShowLog(1,"%s:swapcontext fault TCB_NO=%d,tid=%lx,errno=%d,%s",
                                __FUNCTION__,task->sv.TCB_no,pthread_self(),ret,strerror(abs(ret)));
                        rs->tc.uc_link=NULL;
                        task->uc.uc_link=NULL;
                        if(task->uc.uc_stack.ss_sp)
                                munmap(task->uc.uc_stack.ss_sp,task->uc.uc_stack.ss_size);
                        task->uc.uc_stack.ss_sp=NULL;
                        task->uc.uc_stack.ss_size=0;
                        do_work(task->sv.TCB_no);
                        mthr_showid_del(rs->tid);
                        continue;
                }
                if(!task) {
                        ShowLog(1,"%s:aft swapcontext task is NULL",__FUNCTION__);
                        continue;
                }
                if(!task->AIO_flg) {//service complate
                        if(!rs->tc.uc_stack.ss_size) {//回收fiber stack
//ShowLog(5,"%s:%lx release fiber from TCB_no=%d",__FUNCTION__,rs->tid,task->sv.TCB_no);
                                rs->tc.uc_stack.ss_sp=task->uc.uc_stack.ss_sp;
                                if(rs->tc.uc_stack.ss_sp)
                                         rs->tc.uc_stack.ss_size=use_stack_size;
                                else rs->tc.uc_stack.ss_size=0;
                        } else {
ShowLog(5,"%s:%lx destroy fiber from TCB_no=%d",__FUNCTION__,rs->tid,task->sv.TCB_no);
                                if(task->uc.uc_stack.ss_sp)
                                        munmap(task->uc.uc_stack.ss_sp,task->uc.uc_stack.ss_size);
                        }
                        task->uc.uc_stack.ss_sp=NULL;
                        rs->tc.uc_link=NULL;
                        task->uc.uc_link=NULL;
                        task->uc.uc_stack.ss_size=0;//mark fiber cpmplate
//ShowLog(5,"%s:TCB_no=%d,tid=%lx,timeout=%d,conn.timeout=%d",__FUNCTION__,task->sv.TCB_no,rs->tid,task->timeout,task->conn.timeout);
                } else {
                        pthread_mutex_unlock(&task->lock);

ShowLog(5,"%s:tid=%lx,fiber yield from TCB_no=%d",
                        __FUNCTION__,pthread_self(),task->sv.TCB_no);
                }
                mthr_showid_del(rs->tid);
        }
        ShowLog(1,"%s:tid=%lx canceled",__FUNCTION__,pthread_self());
        mthr_showid_del(rs->tid);
        rs->timestamp=now_usec();
        rs->status=0;
        rs->tid=0;
        if(rs->tc.uc_stack.ss_sp) {
                munmap(rs->tc.uc_stack.ss_sp,rs->tc.uc_stack.ss_size);
                rs->tc.uc_stack.ss_sp=NULL;
                rs->tc.uc_stack.ss_size=0;
        }
        return NULL;
}


论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
36 [报告]
发表于 2017-02-03 01:18 |只看该作者
本帖最后由 windoze 于 2017-02-03 01:25 编辑

stackless coroutine里面不能有局部变量,这个东西更像CPS,所有coroutine local state都要放在一个外部的stack frame里面,你可以想象它是这个样子的:

  1. f1(stack_frame *shadow_stack) {
  2.     // 创建两个局部变量
  3.     shadow_stack->push_local_variable("var1") = 10;
  4.     shadow_stack->push_local_variable("var2") = shadow_stack->get_local_variable("var1")+42;
  5.     // ...
  6.     // 调用f2,f2必须也长这个样子
  7.     shadow_stack->push(address_of(return_to_here));
  8.     longjmp(f2, shadow_stack);   // f2结束时会longjmp回来
  9.     // caller负责清理stack
  10. return_to_here:
  11.     shadow_stack->pop();
  12.     // ...
  13.     // 返回前清理局部变量
  14.     shadow_stack->pop_local_variable("var1");
  15.     shadow_stack->pop_local_variable("var2");
  16.     longjmp(shadow_stack->top, shadow_stack);
  17. }
复制代码

整个函数并没有使用machine stack,而是搞了一个shadow stack,所以只需要一个固定尺寸的结构就可以做coroutine。

但是这种方式最讨厌的地方在于coroutine里面绝对不能用machine stack,因为machine stack当前sp之上也可能有有效的数据,比如最开始的起始函数里在第一个continuation之后定义的局部变量,也就是说你不但不能使用局部变量,甚至不能调用其它正常的函数,因为一次正常的函数调用会有入栈出栈的动作。
正确的姿势应该是由编译器做全局CPS变换,C#里面的async/await就是这么搞的,python里面的generator/yield也可以说是这么搞的(话说python本来就没用machine stack,倒是没有不能调用其它函数的麻烦),据说java 9里也要有类似的东西。

论坛徽章:
1
程序设计版块每日发帖之星
日期:2015-11-08 06:20:00
37 [报告]
发表于 2017-02-07 13:55 |只看该作者
回复 36# windoze

对于stackless协程,一般情况下没必要做成动态栈,如果变量不多的话,可以做成struct,虽然会浪费一些空间,但是可读性、易用性会好很多。。
例如,我用stackless协程写的server:

  1. // the client type
  2. typedef struct __tb_demo_lo_client_t
  3. {
  4.     // the client socket
  5.     tb_socket_ref_t     sock;

  6.     // the file
  7.     tb_file_ref_t       file;

  8.     // the data buffer size
  9.     tb_hize_t           size;

  10.     // the send size
  11.     tb_hize_t           send;

  12.     // the real size
  13.     tb_hong_t           real;

  14.     // the wait state
  15.     tb_long_t           wait;

  16.     // the time
  17.     tb_hong_t           time;

  18. }tb_demo_lo_client_t, *tb_demo_lo_client_ref_t;

  19. // the listen type
  20. typedef struct __tb_demo_lo_listen_t
  21. {
  22.     // the listen socket
  23.     tb_socket_ref_t     sock;

  24.     // the address
  25.     tb_ipaddr_t         addr;

  26.     // the client socket
  27.     tb_socket_ref_t     client;

  28. }tb_demo_lo_listen_t, *tb_demo_lo_listen_ref_t;

  29. static tb_void_t tb_demo_lo_coroutine_client(tb_lo_coroutine_ref_t coroutine, tb_cpointer_t priv)
  30. {
  31.     // check
  32.     tb_demo_lo_client_ref_t client = (tb_demo_lo_client_ref_t)priv;
  33.     tb_assert(client);

  34.     // enter coroutine
  35.     tb_lo_coroutine_enter(coroutine)
  36.     {
  37.         // trace
  38.         tb_trace_d("[%p]: sending %s ..", client->sock, g_filepath);

  39.         // init file
  40.         client->file = tb_file_init(g_filepath, TB_FILE_MODE_RO | TB_FILE_MODE_BINARY);
  41.         tb_assert(client->file);

  42.         // send data
  43.         client->size = tb_file_size(client->file);
  44.         client->time = tb_mclock();
  45.         while (client->send < client->size)
  46.         {
  47.             // send it
  48.             client->real = tb_socket_sendf(client->sock, client->file, client->send, client->size - client->send);

  49.             // trace
  50.             tb_trace_d("[%p]: send: %ld", client->sock, client->real);

  51.             // has data?
  52.             if (client->real > 0)
  53.             {
  54.                 client->send += client->real;
  55.                 client->wait = 0;
  56.             }
  57.             // no data? wait it
  58.             else if (!client->real && !client->wait)
  59.             {
  60.                 // wait it
  61.                 tb_lo_coroutine_waitio(client->sock, TB_SOCKET_EVENT_SEND, TB_DEMO_TIMEOUT);

  62.                 // wait ok
  63.                 client->wait = tb_lo_coroutine_events();
  64.                 tb_assert_and_check_break(client->wait >= 0);
  65.             }
  66.             // failed or end?
  67.             else break;
  68.         }

  69.         // trace
  70.         tb_trace_i("[%p]: send: %lld bytes %lld ms", client->sock, client->send, tb_mclock() - client->time);

  71.         // exit file
  72.         tb_file_exit(client->file);

  73.         // exit socket
  74.         tb_socket_exit(client->sock);
  75.     }
  76. }
  77. static tb_void_t tb_demo_lo_coroutine_listen(tb_lo_coroutine_ref_t coroutine, tb_cpointer_t priv)
  78. {
  79.     // check
  80.     tb_demo_lo_listen_ref_t listen = (tb_demo_lo_listen_ref_t)priv;
  81.     tb_assert(listen);

  82.     // enter coroutine
  83.     tb_lo_coroutine_enter(coroutine)
  84.     {
  85.         // done
  86.         do
  87.         {
  88.             // init socket
  89.             listen->sock = tb_socket_init(TB_SOCKET_TYPE_TCP, TB_IPADDR_FAMILY_IPV4);
  90.             tb_assert_and_check_break(listen->sock);

  91.             // bind socket
  92.             tb_ipaddr_set(&listen->addr, tb_null, TB_DEMO_PORT, TB_IPADDR_FAMILY_IPV4);
  93.             if (!tb_socket_bind(listen->sock, &listen->addr)) break;

  94.             // listen socket
  95.             if (!tb_socket_listen(listen->sock, 1000)) break;

  96.             // trace
  97.             tb_trace_i("listening ..");

  98.             // loop
  99.             while (1)
  100.             {
  101.                 // wait accept events
  102.                 tb_lo_coroutine_waitio(listen->sock, TB_SOCKET_EVENT_ACPT, -1);

  103.                 // wait ok
  104.                 if (tb_lo_coroutine_events() > 0)
  105.                 {
  106.                     // accept client sockets
  107.                     while ((listen->client = tb_socket_accept(listen->sock, tb_null)))
  108.                     {
  109.                         // start client connection
  110.                         if (!tb_lo_coroutine_start(tb_lo_scheduler_self(), tb_demo_lo_coroutine_client, tb_lo_coroutine_pass1(tb_demo_lo_client_t, sock, listen->client))) break;
  111.                     }
  112.                 }
  113.             }

  114.         } while (0);

  115.         // exit socket
  116.         if (listen->sock) tb_socket_exit(listen->sock);
  117.         listen->sock = tb_null;
  118.     }
  119. }

  120. tb_int_t main(tb_int_t argc, tb_char_t** argv)
  121. {
  122.     // check
  123.     tb_assert_and_check_return_val(argc == 2 && argv[1], -1);

  124.     // init tbox
  125.     if (!tb_init(tb_null, tb_null)) return -1;

  126.     // the file path
  127.     tb_char_t const* filepath = argv[1];
  128.     tb_assert_and_check_return_val(filepath, -1);

  129.     // save the file path
  130.     tb_strlcpy(g_filepath, filepath, sizeof(g_filepath));

  131.     // init scheduler
  132.     tb_lo_scheduler_ref_t scheduler = tb_lo_scheduler_init();
  133.     if (scheduler)
  134.     {
  135.         // start listening
  136.         tb_lo_coroutine_start(scheduler, tb_demo_lo_coroutine_listen, tb_lo_coroutine_pass(tb_demo_lo_listen_t));

  137.         // run scheduler
  138.         tb_lo_scheduler_loop(scheduler, tb_true);

  139.         // exit scheduler
  140.         tb_lo_scheduler_exit(scheduler);
  141.     }

  142.     // exit tbox
  143.     tb_exit();
  144.     return 0;
  145. }
复制代码


或者可以看下,我用stackless写的http server,可读性跟stackfull比,差不了多少。。

stackless的http server: https://github.com/tboox/tbox/blob/master/src/demo/coroutine/stackless/http_server.c
stackfull的http server: https://github.com/tboox/tbox/blob/master/src/demo/coroutine/http_server.c

论坛徽章:
1
程序设计版块每日发帖之星
日期:2015-11-08 06:20:00
38 [报告]
发表于 2017-02-07 14:03 |只看该作者
回复 36# windoze

一般情况下,就算是stackless协程,也没必要去用动态栈,变量不多的话,直接Struct就行了,虽然会浪费一点空间,但是可读性、易用性会提升不少,跟stackfull的使用,其实差别已经不是很大了
例如,可以看下我用stackless写的server:
  1. // the client type
  2. typedef struct __tb_demo_lo_client_t
  3. {
  4.     // the client socket
  5.     tb_socket_ref_t     sock;

  6.     // the file
  7.     tb_file_ref_t       file;

  8.     // the data buffer size
  9.     tb_hize_t           size;

  10.     // the send size
  11.     tb_hize_t           send;

  12.     // the real size
  13.     tb_hong_t           real;

  14.     // the wait state
  15.     tb_long_t           wait;

  16.     // the time
  17.     tb_hong_t           time;

  18. }tb_demo_lo_client_t, *tb_demo_lo_client_ref_t;

  19. // the listen type
  20. typedef struct __tb_demo_lo_listen_t
  21. {
  22.     // the listen socket
  23.     tb_socket_ref_t     sock;

  24.     // the address
  25.     tb_ipaddr_t         addr;

  26.     // the client socket
  27.     tb_socket_ref_t     client;

  28. }tb_demo_lo_listen_t, *tb_demo_lo_listen_ref_t;

  29. static tb_void_t tb_demo_lo_coroutine_client(tb_lo_coroutine_ref_t coroutine, tb_cpointer_t priv)
  30. {
  31.     // check
  32.     tb_demo_lo_client_ref_t client = (tb_demo_lo_client_ref_t)priv;
  33.     tb_assert(client);

  34.     // enter coroutine
  35.     tb_lo_coroutine_enter(coroutine)
  36.     {
  37.         // trace
  38.         tb_trace_d("[%p]: sending %s ..", client->sock, g_filepath);

  39.         // init file
  40.         client->file = tb_file_init(g_filepath, TB_FILE_MODE_RO | TB_FILE_MODE_BINARY);
  41.         tb_assert(client->file);

  42.         // send data
  43.         client->size = tb_file_size(client->file);
  44.         client->time = tb_mclock();
  45.         while (client->send < client->size)
  46.         {
  47.             // send it
  48.             client->real = tb_socket_sendf(client->sock, client->file, client->send, client->size - client->send);

  49.             // trace
  50.             tb_trace_d("[%p]: send: %ld", client->sock, client->real);

  51.             // has data?
  52.             if (client->real > 0)
  53.             {
  54.                 client->send += client->real;
  55.                 client->wait = 0;
  56.             }
  57.             // no data? wait it
  58.             else if (!client->real && !client->wait)
  59.             {
  60.                 // wait it
  61.                 tb_lo_coroutine_waitio(client->sock, TB_SOCKET_EVENT_SEND, TB_DEMO_TIMEOUT);

  62.                 // wait ok
  63.                 client->wait = tb_lo_coroutine_events();
  64.                 tb_assert_and_check_break(client->wait >= 0);
  65.             }
  66.             // failed or end?
  67.             else break;
  68.         }

  69.         // trace
  70.         tb_trace_i("[%p]: send: %lld bytes %lld ms", client->sock, client->send, tb_mclock() - client->time);

  71.         // exit file
  72.         tb_file_exit(client->file);

  73.         // exit socket
  74.         tb_socket_exit(client->sock);
  75.     }
  76. }
  77. static tb_void_t tb_demo_lo_coroutine_listen(tb_lo_coroutine_ref_t coroutine, tb_cpointer_t priv)
  78. {
  79.     // check
  80.     tb_demo_lo_listen_ref_t listen = (tb_demo_lo_listen_ref_t)priv;
  81.     tb_assert(listen);

  82.     // enter coroutine
  83.     tb_lo_coroutine_enter(coroutine)
  84.     {
  85.         // done
  86.         do
  87.         {
  88.             // init socket
  89.             listen->sock = tb_socket_init(TB_SOCKET_TYPE_TCP, TB_IPADDR_FAMILY_IPV4);
  90.             tb_assert_and_check_break(listen->sock);

  91.             // bind socket
  92.             tb_ipaddr_set(&listen->addr, tb_null, TB_DEMO_PORT, TB_IPADDR_FAMILY_IPV4);
  93.             if (!tb_socket_bind(listen->sock, &listen->addr)) break;

  94.             // listen socket
  95.             if (!tb_socket_listen(listen->sock, 1000)) break;

  96.             // trace
  97.             tb_trace_i("listening ..");

  98.             // loop
  99.             while (1)
  100.             {
  101.                 // wait accept events
  102.                 tb_lo_coroutine_waitio(listen->sock, TB_SOCKET_EVENT_ACPT, -1);

  103.                 // wait ok
  104.                 if (tb_lo_coroutine_events() > 0)
  105.                 {
  106.                     // accept client sockets
  107.                     while ((listen->client = tb_socket_accept(listen->sock, tb_null)))
  108.                     {
  109.                         // start client connection
  110.                         if (!tb_lo_coroutine_start(tb_lo_scheduler_self(), tb_demo_lo_coroutine_client, tb_lo_coroutine_pass1(tb_demo_lo_client_t, sock, listen->client))) break;
  111.                     }
  112.                 }
  113.             }

  114.         } while (0);

  115.         // exit socket
  116.         if (listen->sock) tb_socket_exit(listen->sock);
  117.         listen->sock = tb_null;
  118.     }
  119. }

  120. tb_int_t main(tb_int_t argc, tb_char_t** argv)
  121. {
  122.     // check
  123.     tb_assert_and_check_return_val(argc == 2 && argv[1], -1);

  124.     // init tbox
  125.     if (!tb_init(tb_null, tb_null)) return -1;

  126.     // the file path
  127.     tb_char_t const* filepath = argv[1];
  128.     tb_assert_and_check_return_val(filepath, -1);

  129.     // save the file path
  130.     tb_strlcpy(g_filepath, filepath, sizeof(g_filepath));

  131.     // init scheduler
  132.     tb_lo_scheduler_ref_t scheduler = tb_lo_scheduler_init();
  133.     if (scheduler)
  134.     {
  135.         // start listening
  136.         tb_lo_coroutine_start(scheduler, tb_demo_lo_coroutine_listen, tb_lo_coroutine_pass(tb_demo_lo_listen_t));

  137.         // run scheduler
  138.         tb_lo_scheduler_loop(scheduler, tb_true);

  139.         // exit scheduler
  140.         tb_lo_scheduler_exit(scheduler);
  141.     }

  142.     // exit tbox
  143.     tb_exit();
  144.     return 0;
  145. }
复制代码



或者可以对比下,分别用stackless和stackfull写的http server,差别不是很大:

stackfull http server: https://github.com/tboox/tbox/bl ... utine/http_server.c
stackless http server: https://github.com/tboox/tbox/bl ... kless/http_server.c

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
39 [报告]
发表于 2017-02-07 20:23 |只看该作者
yulihua49 发表于 2017-02-01 20:06
static void *thread_work(void *param){resource *rs=(resource *)param;int ret,fds;TCB *task=NULL;st ...

我的天啊,审核也不说一声害的我发了好多。
这么多天了,弄的我都不知说什么好了,忘差不多了。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
40 [报告]
发表于 2017-02-07 20:27 |只看该作者
zylthinking 发表于 2017-01-23 16:18
你这个是怎么一个用法啊

corotine(char* addr) {

发一堆帖子审核了好几天,弄的我都不知道该说啥了,你先看着,有问题问吧,我答。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP