Home > programming > lthread代码分析(一)

lthread代码分析(一)

  我们的服务器程序基本上都是基于多线程的。理由很简单,需要同时处理很多请求。但是随之而来的问题也不少,有的是设计上的失误。,有的是代码上的欠缺。例如:有很多的RPC调用都是同步调用,这个就意味着调用者的当前的线程就会被一直阻塞到调用返回或者超时。一旦被调用端出现了什么问题,调用者的当前线程就不能去做其他的事情。一个最简单的解决办法就是增加线程数量,但是这并不是一个非常完美的解决方案。线程越多,系统在线程切换上面所消耗的时间也越多,而且一个系统上的线程数量也不能无休止的往上增长。

  有一天,我发现有一个python的package叫做gevent,就是在python利用coroutine实现网络框架,在网络方面主要应用了libevent(epoll),在coroutine方面使用了greenlet

  于是乎我自然想到了是否可以在c/c++上面应用这个特性呢?epoll是的有的,缺的就是一个coroutine类似的轻量级线程了。后来就在github上面发现了lthread这个东西,下面记录一下我看这个库代码的一些过程和所想所得。

int _switch(struct _cpu_state *new_state, struct _cpu_state *cur_state);
__asm__ (
"    .text                                  n"
"    .p2align 2,,3                          n"
".globl _switch                             n"
"_switch:                                   n"
"__switch:                                  n"
"movl 8(%esp), %edx      # fs->%edx         n"
"movl %esp, 0(%edx)      # save esp         n"
"movl %ebp, 4(%edx)      # save ebp         n"
"movl (%esp), %eax       # save eip         n"
"movl %eax, 8(%edx)                         n"
"movl %ebx, 12(%edx)     # save ebx,esi,edi n"
"movl %esi, 16(%edx)                        n"
"movl %edi, 20(%edx)                        n"
"movl 4(%esp), %edx      # ts->%edx         n"
"movl 20(%edx), %edi     # restore ebx,esi,edi      n"
"movl 16(%edx), %esi                                n"
"movl 12(%edx), %ebx                                n"
"movl 0(%edx), %esp      # restore esp              n"
"movl 4(%edx), %ebp      # restore ebp              n"
"movl 8(%edx), %eax      # restore eip              n"
"movl %eax, (%esp)                                  n"
"ret                                                n"
);

以上是这部分呢,就是lthread里面切换不同轻量级线程的代码了,代码本身就很好的说明了这个函数是干什么的。倒是第一次看到注释时候被这个fs->%edx  ts->%edx给弄晕了。其实前面的8 个movl就是把当前的寄存器的值保存到curstate指向的数据够中,后面的8个movl从newstate中恢复执行环境.  这个函数执行完毕以后,CPU就会执行new_state里面所指定的环境的内容。其中,执行环境主要包括 esp ebp eip(这个不能直接赋值) 。

这里罗列一下lthread里面我认为比较重要的两个数据结构_lthread和_sched

 

struct _lthread {
    struct              _cpu_state st;/*这个是当前的_lthread被切换以后保留下来的cpu执行环境,下次执行的时候需要*/
    void                (*fun)(lthread_t *lt, void *);/*_lthread的执行函数*/
    void                *arg;
    void                *data;
    size_t              stack_size;/*这个是用于lthread切换的时候指明栈空间使用的大小*/
    lt_state_t          state;
    sched_t             *sched;
    compute_sched_t     *compute_sched;
    uint64_t            timeout;
    uint64_t            ticks;
    uint64_t            birth;
    uint64_t            id;
    int                 fd_wait; /* fd we are waiting on */
    char                funcname[64];
    lthread_t           *lt_join;
    void                **lt_exit_ptr;
    LIST_ENTRY(_lthread)    new_next;
    LIST_ENTRY(_lthread)    sleep_next;
    LIST_ENTRY(_lthread)    compute_next;
    LIST_ENTRY(_lthread)    compute_sched_next;
    sched_node_t        *sched_node;
    lthread_l_t         *sleep_list;
    void                *stack;
    void                *ebp;
};
struct _sched {
    size_t              stack_size;/*调度器对应的栈大小,lthread运行的时候实际使用的是调度器所拥有的栈空间*/
    int                 total_lthreads;
    int                 waiting_state;
    int                 sleeping_state;
    int                 poller;
    int                 nevents;
    uint64_t            default_timeout;
    int                 total_new_events;
    /* lists to save an lthread depending on its state */
    lthread_l_t         new;
    lthread_l_t         compute;
    struct rb_root      sleeping;
    uint64_t            birth;
    void                *stack;
    lthread_t           *current_lthread;
    struct _cpu_state   st;/*调度器被切换以后的cpu执行环境,以便恢复以后继续进行调度工作*/
    struct epoll_event  eventlist[LT_MAX_EVENTS];
    int                 compute_pipes[2];
    pthread_mutex_t     compute_mutex;
};

[to be continue …]

Categories: programming Tags: ,
  1. No comments yet.
  1. No trackbacks yet.