Full Code of shonm520/mu_event for AI

master 3a5da1ad8eaa cached
33 files
47.8 KB
13.9k tokens
119 symbols
1 requests
Download .txt
Repository: shonm520/mu_event
Branch: master
Commit: 3a5da1ad8eaa
Files: 33
Total size: 47.8 KB

Directory structure:
gitextract_05tbt9ce/

├── README.md
└── src/
    ├── buffer.c
    ├── buffer.h
    ├── config.h
    ├── connection.c
    ├── connection.h
    ├── epoll.c
    ├── epoll.h
    ├── event.c
    ├── event.h
    ├── event_loop.c
    ├── event_loop.h
    ├── example/
    │   ├── echo/
    │   │   ├── echosvr
    │   │   ├── echosvr.c
    │   │   └── run.sh
    │   └── timer/
    │       ├── run.sh
    │       ├── test_timer
    │       └── test_timer.c
    ├── listener.c
    ├── listener.h
    ├── logger.c
    ├── logger.h
    ├── makefile
    ├── ring_buffer.c
    ├── ring_buffer.h
    ├── servermanager.c
    ├── servermanager.h
    ├── tcpclient.c
    ├── tcpclient.h
    ├── testcase/
    │   ├── test_buffer.c
    │   └── test_timer.c
    ├── timer.c
    └── timer.h

================================================
FILE CONTENTS
================================================

================================================
FILE: README.md
================================================
#### C语言版muduo,对muduo的部分设计做了优化
#### 之前用buffer队列实现的缓冲区,效果不是很好,后来使用了环形缓冲区

#### 下面是和muduo的部分性能对比测试,测试标准参考陈硕大佬自己的标准 https://blog.csdn.net/solstice/article/details/5864889 


#### 下面是各数据时的吞吐量对比
![吞吐量对比1](https://upload-images.jianshu.io/upload_images/9444378-b2ae69351584481a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


#### 通过使用环形缓冲区,使得吞吐量大大提高,并超过了muduo。我想除了学习到了muduo的精华,还因为目前我的程序结构比较简单,没有其他杂项的缘故

#### 下图是发送数据量为16384B,不同并发连接下的对比
![并发时吞吐量对比2](https://upload-images.jianshu.io/upload_images/9444378-63e04366068867a7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

###### 可以看到多连接时(高并发时)muevent吞吐量也超过了muduo


#### QQ讨论群:858791125


================================================
FILE: src/buffer.c
================================================
#include <stdlib.h>
#include <string.h>
#include "buffer.h"
#include "config.h"


socket_buffer* socket_buffer_new()
{
    socket_buffer* sb = (socket_buffer*)mu_malloc(sizeof(socket_buffer));
    sb->size = 0;
    sb->offset = 0;
    sb->head = sb->tail = NULL;
    sb->pool = (buffer_pool*)mu_malloc(sizeof(buffer_pool));
    sb->pool->head = NULL;
    sb->pool->len = 0;
    return sb;
}

void socket_buffer_free(socket_buffer* sb)
{
    buffer_node* head = sb->pool->head;
    for(; head != NULL; head = head->next)  {
        if (head->msg)  {
            mu_free(head->msg);
            head->msg = NULL;
        }
    }
}

buffer_node* new_buffer_node(int size)
{
    buffer_node** pool =  (buffer_node**)mu_malloc(sizeof(buffer_node*) * size);
    int i = 0;
    for (i = 0; i < size; i++)  {
        pool[i] = (buffer_node*)mu_malloc(sizeof(buffer_node));
    }
    for (i = 0; i < size; i++)  {
        pool[i]->msg = NULL;
        pool[i]->sz = 0;
        pool[i]->next = pool[i + 1];
    }
    pool[size - 1]->next = 0;
    return pool[0];
}


int buffer_push_data(socket_buffer* sb, char* msg, int sz)     //写数据到缓冲池中的新结点,然后sb指向新结点
{
    if (msg == NULL || sz == 0)  {
        return 0;
    }
    buffer_pool* pool = sb->pool;
    buffer_node* free_node = NULL;
    if (pool->head == NULL)  {                //缓冲池已空
        int len = pool->len + 1;
        int size = 8;
        if (len <= LARGE_PAGE_NODE - 3 )  {
            size <<= len;
        }  else  {
            size <<= LARGE_PAGE_NODE - 3;
        }
        free_node = new_buffer_node(size);
        pool->len = size;
    }
    else  {
        free_node = pool->head;
    }   
    pool->head = free_node->next;            //取pool的头结点作为free_node,然后头结点指向next
    char* msgt = (char*)mu_malloc(sz);
    memcpy(msgt, msg, sz);
    free_node->msg = msgt;
    free_node->sz = sz;
    free_node->next = NULL;

    if (sb->head == NULL)  {
        sb->head = sb->tail = free_node;
    }  else  {
        sb->tail->next = free_node;
        sb->tail = free_node;
    }
    sb->size += sz;
    return sb->size;
}


void buffer_node_release(socket_buffer* sb)    //返回给缓冲池
{
    buffer_pool* pool = sb->pool;
    buffer_node* free_node = sb->head;     //把头结点释放
    sb->offset = 0;
    sb->head = free_node->next;            //重置数据区
    if (sb->head == NULL)  {
        sb->tail = NULL;
    }
    free_node->next = pool->head;          //把该结点加入到缓冲池
    mu_free(free_node->msg);               //这里放心free因为结点的指针有自己的空间
    free_node->msg = NULL;
    free_node->sz = 0;
    pool->head = free_node;                //重置缓冲池头结点
}


char* buffer_read_spec(socket_buffer* sb, int sz, int* realSz)    //读取缓冲区sz个字节
{
    if (sz == 0)  {
        return NULL;
    }
    if (sb->size < sz)  {     //缓冲区数据不够
        if (realSz)  {
            return buffer_read_all(sb, realSz);
        }
        else {
            return NULL;
        }
    }

    buffer_pool* pool = sb->pool;   
    sb->size -= sz;
    buffer_node* cur = sb->head;
    char* msg = (char*)mu_malloc(sz);
    int curLen = cur->sz - sb->offset;
    if (sz <= curLen)  {            //要读取的数据小于等于当前结点剩余的数据
        memcpy(msg, cur->msg + sb->offset, sz);
        sb->offset += sz;
        if (sz == curLen)  {        //刚好读完就释放该结点
            buffer_node_release(sb);    
        }
        return msg;
    }
    else  {    //要读取的数据大于当前结点的数据,其余结点又有
        int offset = 0;
        for ( ;; )  {
            int curLen = cur->sz - sb->offset;
            if (curLen >= sz)  {          //第二次读
                memcpy(msg + offset, cur->msg + sb->offset, sz);
                offset += sz;
                sb->offset += sz;
                if (curLen == sz)  {
                    buffer_node_release(sb);
                }
                break;
            }
            int real_sz = (sz < curLen) ? sz : curLen;
            memcpy(msg + offset, cur->msg + sb->offset, real_sz);   //先把当前结点剩余的的数据给读取了
            offset += real_sz;
            buffer_node_release(sb);
            sz -= curLen;
            if (sz == 0)  {
                break;
            }
            cur = sb->head;    //由于上面释放过,这里是新的结点
            if (!cur)   { 
                break;
            }
        }
        return msg;
    }
    return NULL;
}

char* buffer_read_all(socket_buffer* sb, int* retNum)      //读取缓冲区所有的字节
{
    int total_size = sb->size;
    if (total_size <= 0)  {
        return NULL;
    }
    char* msg = (char*)mu_malloc(total_size + 1); 
    int offset = 0;
    while(sb->head)  {
        buffer_node* cur = sb->head;
        int curLen = cur->sz - sb->offset;

        memcpy(msg + offset, cur->msg + sb->offset, curLen);
        offset += curLen; 
        buffer_node_release(sb);       //这里会重置sb->offset并重新设置头
    }
     if (retNum)  {
        *retNum = offset;
    }
    sb->size = 0;
    return msg;
}

int buffer_get_size(socket_buffer* sb)
{
    if (sb)
        return sb->size;
    return 0;
}







================================================
FILE: src/buffer.h
================================================
#pragma once

struct buffer_node_t {
    char* msg;
    int sz;
    struct buffer_node_t* next;

    char* buf;
    int cap;
};
 
 
struct buffer_pool_t {
    struct buffer_node_t* head;  
    int len;
};


struct socket_buffer_t {
    int size;
    int offset;
    struct buffer_node_t* head;
    struct buffer_node_t* tail;

    struct buffer_pool_t*  pool;
};



typedef struct buffer_node_t   buffer_node;
typedef struct socket_buffer_t socket_buffer;
typedef struct buffer_pool_t   buffer_pool;

socket_buffer* socket_buffer_new();
void socket_buffer_free(socket_buffer* sb);
int   buffer_push_data(socket_buffer* sb, char* msg, int sz);
void  buffer_node_release(socket_buffer* sb);
char* buffer_read_spec(socket_buffer* sb, int sz, int* realSz);
char* buffer_read_all(socket_buffer* sb, int* retNum);   

int buffer_get_size(socket_buffer* sb);

================================================
FILE: src/config.h
================================================
#pragma once 
#include <stdlib.h>

#ifndef bool
    #define bool int 
#endif

#ifndef true
    #define true 1
#endif 

#ifndef false
    #define false 0
#endif 


#ifndef NULL
    #define NULL 0
#endif 


#define mu_malloc malloc
#define mu_free   free

#define LARGE_PAGE_NODE 12   //buffer node 的对齐

#define MAX_EVENTS  32       //epoll_wait一次性监听最大的事件数量

#define DEFAULT_PORT  2020   //默认端口
#define MAX_LOOP 4           //max thread



#define MAX_TIMER_EVENT 100 //最大定时器个数   

================================================
FILE: src/connection.c
================================================
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/uio.h>
#include "connection.h"
#include "event_loop.h"
#include "event.h"
#include "config.h"
#include "ring_buffer.h"
#include "logger.h"


/*
    这里的connection仅仅指客户端连接后建立的socket connnection
*/


static void connection_passive_close(connection* conn);
static void connection_disconnect(connection* conn);
static void event_readable_callback(int fd, event* ev, void* arg);
static void event_writable_callback(int fd, event* ev, void* arg);

connection* connection_create(int connfd, message_callback_pt msg_cb)
{
    connection* conn = (connection* )mu_malloc(sizeof(connection));
    if (conn == NULL)  {
        debug_ret("create connection failed, file: %s, line: %d", __FILE__, __LINE__);
        return NULL;
    }

    memset(conn, 0, sizeof(connection));
    conn->connfd = connfd;
    conn->message_callback = msg_cb;

    //创建连接的时候没有指定EPOLLOUT,是因为在epoll水平触发的情形下指定EPOLLOUT会导致写事件一直被触发(通常写缓冲区是不满的)
    //这里的高效实现方式是有数据时直接调用发送,如果发现发送函数send调用之后缓冲区还有数据,则开启EPOLLOUT事件发送完毕后又关闭事件
    event* ev = (event*)event_create(connfd,  EPOLLIN | EPOLLPRI, event_readable_callback, conn, event_writable_callback, conn);
    if (ev == NULL)  {
        debug_ret("create event failed, file: %s, line: %d", __FILE__, __LINE__);
        mu_free(conn);
        return NULL;
    }

    conn->conn_event = ev;
    
    return conn;    
}


void connection_start(connection* conn, event_loop* loop)
{
    if (! conn->ring_buffer_read)  {
        conn->ring_buffer_read = ring_buffer_new();
    }

    if (! conn->ring_buffer_write)  {
        conn->ring_buffer_write = ring_buffer_new();
    }
    event_add_io(loop->epoll_fd, conn->conn_event);
}


static int read_buffer(int fd, connection* conn)       //使用了readv但是好像并没有提高效率,不过使用了栈上数据,避免了malloc,free
{
    int nread2 = 65536;
    char extrabuf2[nread2];
    struct iovec vec[2];

    char* start = ring_buffer_readable_start(conn->ring_buffer_read);
    int available_bytes = ring_buffer_available_bytes(conn->ring_buffer_read);
    vec[0].iov_base = start;
    vec[0].iov_len = available_bytes;        //一开始时为0,并不读到ring_buffer中去
    vec[1].iov_base = extrabuf2;
    vec[1].iov_len = nread2;

    ssize_t nread = readv(fd, vec, 2);      //最多读iovec结构体指定的长度,而且fd一定是非阻塞的
    if (nread == 0)  {
        return 0;
    }
    else if (nread < 0)  {
        if (errno == EAGAIN || errno == EWOULDBLOCK)  {
            return -1;
        }
        else  {
            debug_msg("read n < 0, fd : %d, file: %s, line: %d", conn->connfd, __FILE__, __LINE__);
            return -1;
        }
    }
    else if (nread <= available_bytes)  {
        conn->ring_buffer_read->end += nread;
        return nread;
    }
    else  {
        conn->ring_buffer_read->end += available_bytes;
        ring_buffer_push_data(conn->ring_buffer_read, extrabuf2, nread - available_bytes);
        return nread;
    }
    return -1;
}


static void event_readable_callback(int fd, event* ev, void* arg)
{
    connection* conn = (connection*)arg;
    int nread = read_buffer(fd, conn);
    if (nread > 0 && conn->message_callback)  {
        conn->message_callback(conn);
    }
    else if(nread <= 0)  {
        connection_passive_close(conn);
    }
}

static void event_writable_callback(int fd, event* ev, void* arg)
{
    int len = 0;
    connection* conn = (connection*)arg;
    char* msg = ring_buffer_get_msg(conn->ring_buffer_write, &len);
    if (msg && len > 0)  {
        int n = send(conn->connfd, msg, len, 0);
        if (n > 0)  {
            ring_buffer_release_bytes(conn->ring_buffer_write, n);
            len = ring_buffer_readable_bytes(conn->ring_buffer_write);
            if (len == 0)  {                  //发送完所有缓冲区数据后要关闭写触发
                event_disable_writing(conn->conn_event);
                if (conn->state == State_Closing)  {
                    connection_free(conn);    //如不关闭一直会触发
                    conn->state = State_Closed;
                }
            }
        }
    }
}

static void connection_passive_close(connection* conn)
{
    //printf("connection_passive_close!!! %d, life time is %d \n", conn->connfd, (int)time(NULL) - conn->time_on_connect);
    connection_disconnect(conn);
}

void connection_established(connection* conn)
{
    if (conn->connected_cb)
        conn->connected_cb(conn);
}

void connection_active_close(connection* conn)
{   
    //printf("active close %d\n", conn->connfd);
    connection_disconnect(conn);
}

void connection_set_disconnect_callback(connection* conn, connection_callback_pt cb)
{
    conn->disconnected_cb = cb;
}

static void connection_disconnect(connection* conn)
{
    conn->state = State_Closing;
    if (ring_buffer_readable_bytes(conn->ring_buffer_write) > 0)   {     //收到对方关闭写的通知时,如果缓冲区还有数据要发送则等数据发送完毕后再关闭socket
        event_enable_writing(conn->conn_event); 
    }
    else  {
        connection_free(conn);    //如不关闭一直会触发
        conn->state = State_Closed;
    }
}

void connection_free(connection* conn)
{
    if (conn->disconnected_cb)  {
        conn->disconnected_cb(conn);
    }

    event_free(conn->conn_event);

    if (conn->ring_buffer_read)  {
        ring_buffer_free(conn->ring_buffer_read);
    }
    if (conn->ring_buffer_write)  {
        ring_buffer_free(conn->ring_buffer_write);
    }
    
    mu_free(conn);
}


void connection_send(connection *conn, char *buf, size_t len)  //外部调用来发送数据
{
    if (ring_buffer_readable_bytes(conn->ring_buffer_write) == 0)  {         //缓冲区为空直接发送
        int ret = send(conn->connfd, buf, len, 0);
    }
    else  {
        printf("connection_send %d\n", len);
        ring_buffer_push_data(conn->ring_buffer_write, buf, len);
        event_enable_writing(conn->conn_event);              //须开启才能发送
    }
}


int connection_send_buffer(connection *conn)                 //外部调用来发送数据
{
    int len = 0;
    char* msg = ring_buffer_get_msg(conn->ring_buffer_write, &len);
    if (msg && len > 0)  {
        int n = send(conn->connfd, msg, len, 0);
        if (n == -1)  {
            return -1;
        }
        if (n > 0)  {
            ring_buffer_release_bytes(conn->ring_buffer_write, n);
            if (n < len)  {       //没有发完全
                event_enable_writing(conn->conn_event);      //须开启才能发送
                return 1;
            }
            else  {
                return 0;
            }
        }
    }
    return -1;
}

================================================
FILE: src/connection.h
================================================

#pragma once

typedef struct connection_t connection;

typedef void (*message_callback_pt) (connection* conn);
typedef void (*connection_callback_pt)(connection *conn);

typedef struct event_t event;

typedef struct event_loop_t event_loop; 

typedef struct socket_buffer_t socket_buffer;
typedef struct ring_buffer_t   ring_buffer;
typedef struct buffer_pool_t   buffer_pool;

enum {
    State_Closing = 1,
    State_Closed = 2,
};

struct connection_t  {
    int connfd;
    event* conn_event;    //清理阶段和改变事件时用到
    message_callback_pt      message_callback;
    connection_callback_pt   connected_cb;
    connection_callback_pt   disconnected_cb;

    ring_buffer*   ring_buffer_read;
    ring_buffer*   ring_buffer_write;

    int state;

    void*  handler;
    char*  client_ip;        //client ip
    int    client_port;      //client port
    int    time_on_connect;   
};


connection* connection_create(int fd, message_callback_pt msg_cb);
void connection_start(connection* conn, event_loop* loop);
void connection_established(connection* conn);
void connection_active_close(connection* conn);
void connection_free(connection* conn);
void connection_send(connection *conn, char *buf, size_t len);
int connection_send_buffer(connection *conn);

void connection_set_disconnect_callback(connection* conn, connection_callback_pt cb);



================================================
FILE: src/epoll.c
================================================
#include <sys/time.h>
#include <sys/epoll.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include "logger.h"
#include "epoll.h"
#include "event.h"
#include "config.h"


int epoller_create()
{
    int epoll_fd = epoll_create(1024);  //大于0就好
    if (epoll_fd == -1)  {
         debug_ret("create epoll failed, file : %s, line : %d", __FILE__, __LINE__);
        return -1;
    }
    return epoll_fd;
}

void epoll_free(int fd)
{
    close(fd);
}

void epoller_add(int epoll_fd, event* e)
{
    struct epoll_event ev;
    ev.events = e->event_flag;
    ev.data.ptr = e;

    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, e->fd, &ev) == -1)  {
        debug_sys("epoll_ctl add failed, file : %s, line : %d", __FILE__, __LINE__);
    }
}

void epoller_del(int epoll_fd, event* e)
{
    struct epoll_event ev;
    ev.events = e->event_flag;

    if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, e->fd, &ev) == -1)  {
        debug_sys("epoll_ctl del failed, file : %s, line : %d", __FILE__, __LINE__);
    }
}

void epoller_modify(int epoll_fd, event* e)
{
    struct epoll_event ev;
    ev.events = e->event_flag;
    ev.data.ptr = e;

    if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, e->fd, &ev) == -1)  {
        debug_sys("epoll_fd modify failed, file : %s, line : %d", __FILE__, __LINE__);
    }
}


struct timeval epoller_dispatch(int epoll_fd, int timeout)
{
    struct epoll_event events[MAX_EVENTS];
    int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, timeout);

    if (nfds == -1)  {
        if (errno != EINTR)  {
            debug_sys("epoll_wait failed, file : %s, line : %d", __FILE__, __LINE__);
        }
    }

    struct timeval now;
    gettimeofday(&now, NULL);

    int i;
    event* ev;
    for (i = 0; i < nfds; i++)  {
        ev = (event*)events[i].data.ptr;
        ev->time = now;
        ev->active_event = events[i].events;
        event_handler(ev);
    }

    struct timeval end;
    gettimeofday(&end, NULL);
    return end;
}

================================================
FILE: src/epoll.h
================================================
#pragma once


typedef struct event_t event;

int epoller_create();
void epoller_free();

void epoller_add(int fd, event* ev);
void epoller_del(int fd, event* ev);
void epoller_modify(int fd, event* ev);

struct timeval epoller_dispatch(int fd, int timeout);

================================================
FILE: src/event.c
================================================
#include <sys/epoll.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include "event.h"
#include "servermanager.h"
#include "event_loop.h"
#include "logger.h"
#include "epoll.h"

static void event_error_handler(event* ev)
{
    event_free(ev);
}

void event_handler(event* ev)
{
    if (ev->active_event & (EPOLLHUP | EPOLLERR))  {
        event_error_handler(ev);
        return;
    }

    if (ev->active_event & (EPOLLIN | EPOLLPRI))  {
        if (ev->event_read_handler)  {
            ev->event_read_handler(ev->fd, ev, ev->r_arg);
        }
    }
    if (ev->active_event & EPOLLOUT)  {
        if (ev->event_write_handler)  {
            ev->event_write_handler(ev->fd, ev, ev->w_arg);
        }
    }
}

event* event_create(int fd, short event_flag, event_callback_pt read_cb,
                    void* r_arg, event_callback_pt write_cb, void* w_arg)
{
    event* ev = (event*)malloc(sizeof(event));
    if (ev == NULL)  {
        debug_ret("file: %s, line: %d", __FILE__, __LINE__);
        return NULL;
    }

    ev->fd = fd;
    ev->event_flag = event_flag;
    ev->active_event = 0;
    ev->event_read_handler = read_cb;
    ev->r_arg = r_arg;

    ev->event_write_handler = write_cb;
    ev->w_arg = w_arg;

    return ev;
}

void event_free(event* ev)
{
    event_stop(ev);
    close(ev->fd);
	free(ev);
}

void event_add_io(int epoll_fd, event* ev)
{
    epoller_add(epoll_fd, ev);
    ev->epoll_fd = epoll_fd;
    ev->is_working = 1;
}

void event_modify_flag(event* ev, int new_flag)
{
    if (ev->is_working == 0)  {
        debug_msg("epoll_fd cannot modify, because it's not working now! %s, line: %d", __FILE__, __LINE__);
        return;
    }
    ev->event_flag = new_flag;
    epoller_modify(ev->epoll_fd, ev);
}

void event_add_flag(event* ev, int add_flag, int plus)
{
    int flag = ev->event_flag |= add_flag;
    if (plus == 0)  {
        flag = ev->event_flag &= ~add_flag;
    }
    event_modify_flag(ev, flag);
}

void event_enable_writing(event* ev)
{
    event_add_flag(ev, EPOLLOUT, 1);
}

void event_disable_writing(event* ev)
{
    event_add_flag(ev, EPOLLOUT, 0);
}


void event_stop(event *ev)
{
	if (ev->is_working == 0)                   //判断事件ev是否在epoll中,防止重复删除同一事件
		return;

    epoller_del(ev->epoll_fd, ev);

	ev->is_working = 0;
}

================================================
FILE: src/event.h
================================================
#pragma once
#include <sys/time.h>


typedef struct event_t event;
typedef struct server_manager_t server_manager;

typedef void (*event_callback_pt)(int fd, event* ev, void* arg);

struct event_t {
    int fd;
    int event_flag;
    int active_event;
    struct timeval time;

    event_callback_pt event_read_handler;
    void* r_arg;

    event_callback_pt event_write_handler;
    void* w_arg;

    int is_working;
    int epoll_fd;
};


event* event_create(int fd, short event_flag, event_callback_pt read_cb,
                    void* r_arg, event_callback_pt write_cb, void* w_arg);

int event_start(event* ev);
void event_stop(event* ev);
void event_free(event* ev);

void event_add_io(int epoll_fd, event* ev);
void event_enable_writing(event* ev);
void event_disable_writing(event* ev);

void event_handler(event* ev);

================================================
FILE: src/event_loop.c
================================================
#include <stdlib.h>
#include <stdio.h>
#include "logger.h"
#include "event_loop.h"
#include "config.h"
#include "epoll.h"


event_loop* event_loop_create()
{
    event_loop* loop = (event_loop*)mu_malloc(sizeof(event_loop));
    if (loop == NULL)  {
        debug_ret("create event loop failed, file : %s, line : %d", __FILE__, __LINE__);
        return NULL;
    }

    loop->epoll_fd = epoller_create();
    if (loop->epoll_fd == -1)  {
        debug_ret("epooler_create failed, file : %s, line : %d", __FILE__, __LINE__);
        mu_free(loop);
        return NULL;
    }

    return loop;
}

void event_loop_run(event_loop* loop)
{
    int timeout = -1;
    while(1)  {
        epoller_dispatch(loop->epoll_fd, timeout);
    }
}

================================================
FILE: src/event_loop.h
================================================
#pragma once

struct event_loop_t  {
    int epoll_fd;
};

typedef struct event_loop_t event_loop;

event_loop* event_loop_create();
void event_loop_run(event_loop* el);

================================================
FILE: src/example/echo/echosvr.c
================================================

#include <stdio.h>
#include "servermanager.h"
#include "connection.h"
#include "listener.h"
#include "ring_buffer.h"
#include "config.h"

void onMessage(connection *conn)
{
    int size = 0;
    char* msg = ring_buffer_get_msg(conn->ring_buffer_read, &size);
    printf("read all : %s, %d\n", msg, size);

    char buf[] = "abcd";
    connection_send(conn, buf, sizeof(buf) - 1);

    connection_send(conn, msg, size);
}

void onConnection(connection* conn)
{
    printf("connected!!! ip:port %s:%d\n", conn->client_ip, conn->client_port);
}

int main(int argc, char* argv[])
{
    int port = DEFAULT_PORT;
    int thread_num = MAX_LOOP;
    if (argc >= 2)
        port = atoi(argv[1]);
    if (argc >= 3)
        thread_num = atoi(argv[2]);
  
    printf("port, thread_num is %d, %d \n", port, thread_num);

	server_manager *manager = server_manager_create(port, thread_num);
	inet_address addr = addr_create("any", port);
	listener_create(manager, addr, onMessage, onConnection);
	server_manager_run(manager);

	return 0;
}




================================================
FILE: src/example/echo/run.sh
================================================
rm -f echosvr

gcc -o echosvr *.c ../../*.c -lpthread -g -I ../../ 

================================================
FILE: src/example/timer/run.sh
================================================
   
rm  test_timer   
echo "rm"
gcc -o test_timer test_timer.c ../../*.c -lpthread  -g -I ../../ 

================================================
FILE: src/example/timer/test_timer.c
================================================
#include<stdio.h>
#include "config.h"
#include "connection.h"
#include "servermanager.h"
#include "listener.h"
#include "timer.h"



static void timer_cb(void* arg)
{
    printf("timer tick 2 seconds!!!!\n\n");
}

static void timer_cb1(void* arg)
{
    printf("timer tick 1500 miseconds!!!!\n\n");
}

static void timer_cb_once(void* arg)
{
    printf("timer tick once!!!!\n\n");
}


int main(int argc, char* argv[])  
{
    
    int port = DEFAULT_PORT;
    int thread_num = MAX_LOOP;
    if (argc >= 2)
        port = atoi(argv[1]);
    if (argc >= 3)
        thread_num = atoi(argv[2]);


	server_manager *manager = server_manager_create(port, thread_num);
	inet_address addr = addr_create("any", port);
	listener_create(manager, addr, NULL, NULL);

    timer ti;
    ti.type = TIMER_OPT_REPEAT;
    ti.time_out = 2000;
    ti.callback = timer_cb;
    ti.arg = NULL;

    server_manager_add_timer(manager, ti);

    ti.type = TIMER_OPT_REPEAT;
    ti.time_out = 1500;
    ti.callback = timer_cb1;
    server_manager_add_timer(manager, ti);
    ti.type = TIMER_OPT_ONCE;
    ti.time_out = 5000;
    ti.callback = timer_cb_once;
    server_manager_add_timer(manager, ti);
	server_manager_run(manager);

	return 0;
}

================================================
FILE: src/listener.c
================================================
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/tcp.h> 
#include <stdio.h>
#include <time.h>
#include "listener.h"
#include "servermanager.h"
#include "event.h"
#include "connection.h"
#include "event_loop.h"
#include "logger.h"


extern event_loop *g_loops[];


inet_address addr_create(const char *ip, int port)
{
	if (ip == NULL)
		debug_quit("addr_create failed, ip is null, file: %s, line: %d", __FILE__, __LINE__);
	
	inet_address new_addr;

	memset(&new_addr.addr, 0, sizeof(new_addr.addr));
	new_addr.addr.sin_family = AF_INET;
	
	if (strcmp(ip, "any") == 0)
		new_addr.addr.sin_addr.s_addr = htonl(INADDR_ANY);
	else if(inet_pton(AF_INET, ip, &new_addr.addr.sin_addr) <= 0)
		debug_quit("inet_pton failed, file: %s, line: %d", __FILE__, __LINE__);
	
	new_addr.addr.sin_port = htons(port);
	return new_addr;
}

static void default_disconnected_callback(connection* conn)
{

}

static void event_accept_callback(int listenfd, event* ev, void* arg)
{
    server_manager *manager = (server_manager *)arg;
	inet_address client_addr;
	socklen_t clilen = sizeof(client_addr.addr);
	
	int connfd = accept(listenfd, (struct sockaddr *)&client_addr.addr,	&clilen);
	if (connfd < 0)  {
		int save = errno;
		if (save == EAGAIN || save == ECONNABORTED || save == EINTR ||
            save == EPROTO || save == EPERM || save == EMFILE)
		{
			return;
		}
		else  {
			debug_sys("accept failed, file: %s, line: %d", __FILE__, __LINE__);
		}
	}

	fcntl(connfd, F_SETFL, fcntl(connfd, F_GETFL) | O_NONBLOCK);

    static int i = 0;
	if (i >= manager->loop_num)
		i = 0;

    event_loop* loop = NULL;
    if (manager->loop_num == 0)  {     //如果没有开启线程则用主线程的
        loop = manager->loop;
    }
    else  {
        loop = g_loops[i++];
    }

    int tcp_nodelay = 1;              //不等对方发送ack直接发送减少延迟
    setsockopt(connfd, IPPROTO_TCP, TCP_NODELAY,(const void *) &tcp_nodelay, sizeof(int));                               
	
	connection *conn = connection_create(connfd, manager->msg_callback);      //后面的参数是指有消息时的用户回调
	if (conn == NULL)  {
		debug_quit("create connection failed, file: %s, line: %d", __FILE__, __LINE__);
	}
    conn->client_ip = inet_ntoa(client_addr.addr.sin_addr);
    conn->client_port = ntohs(client_addr.addr.sin_port);  //used for debug
    conn->time_on_connect = time(NULL);
    conn->disconnected_cb = default_disconnected_callback;
	
	if (manager->new_connection_callback) {
        conn->connected_cb = manager->new_connection_callback;
        connection_established(conn);
    }

    connection_start(conn, loop);
}


#define ERR_SOCKET 1
#define ERR_BIND   2
#define ERR_LISTEN 3
#define ERR_EVENT  4

listener* listener_create(server_manager* manager, inet_address ls_addr,
                         message_callback_pt msg_cb, connection_callback_pt new_con_cb)
{
    listener* ls = (listener*)malloc(sizeof(listener));
    if (ls == NULL)  {
        debug_ret("create listener failed, file: %s, line: %d", __FILE__, __LINE__);
        return NULL;
    }

    ls->listen_addr = ls_addr;

    manager->msg_callback = msg_cb;
    manager->new_connection_callback = new_con_cb;

    int err_code = 0;
    event* lev = NULL;
    int listen_fd;
    do {
        listen_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);     //创建非阻塞套接字 
        if (listen_fd < 0)  {
            err_code = ERR_SOCKET;
            break;
        }

        int opt = 1;
        setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
        int ret = bind(listen_fd, (struct sockaddr *)&ls_addr.addr, sizeof(ls_addr.addr));
        if (ret < 0)  {
            err_code = ERR_BIND;
            break;
        }

        ret = listen(listen_fd, SOMAXCONN);
        if (ret < 0)  {
            err_code = ERR_LISTEN;
            break;
        }

        lev = event_create(listen_fd, EPOLLIN | EPOLLPRI, event_accept_callback, manager, NULL, NULL);       //后面参数是写事件回调及其参数,由于这里是监听socket不需要
        if (lev == NULL)  {
            err_code = ERR_EVENT;
            break;
        }
    } while(0);

    if (err_code != 0)  {
        debug_ret("create listener failed, error code is %d, file: %s, line: %d", err_code, __FILE__, __LINE__);
        if (listen_fd > 0)  {
            close(listen_fd);
        }
        free(ls);
        return NULL;
    }  
    else  {
        event_add_io(manager->loop->epoll_fd, lev);
    }
	
    return ls;
}



================================================
FILE: src/listener.h
================================================
#pragma once
#include <sys/socket.h>
#include <netinet/in.h>



/* 封装的IPv4地址和port */
typedef struct inet_addr_t {
	struct sockaddr_in addr;
} inet_address;

inet_address addr_create(const char *ip, int port);

typedef struct connection_t connection;

typedef void (*connection_callback_pt)(connection *conn);
typedef void (*message_callback_pt)(connection *conn);


typedef struct listener_t listener;

struct listener_t  {
    inet_address listen_addr;
    //event* ls_event;
};

typedef struct server_manager_t server_manager;

listener* listener_create(server_manager* manager, inet_address ls_addr,
                         message_callback_pt msg_cb, connection_callback_pt new_con_cb);

void listener_free(listener* ls);

================================================
FILE: src/logger.c
================================================

#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>


#define MAXLINE	128

#define DBG_PRINTF debug_print

static void	debug_print(int, const char *, va_list);

/* 系统调用非致命错误
 * 打印用户信息 + errno信息后返回
 */
void debug_ret(const char *fmt, ...)
{
	va_list	ap;

	va_start(ap, fmt);
	DBG_PRINTF(1, fmt, ap);
	va_end(ap);
}

/* 系统调用致命错误
 * 打印用户信息 + errno信息后终止进程
 */
void debug_sys(const char *fmt, ...)
{
	va_list	ap;

	va_start(ap, fmt);
	DBG_PRINTF(1, fmt, ap);
	va_end(ap);
	exit(1);
}

/* 非系统调用致命错误
 * 打印用户信息后终止进程
 */
void debug_quit(const char *fmt, ...)
{
	va_list	ap;

	va_start(ap, fmt);
	DBG_PRINTF(0, fmt, ap);
	va_end(ap);
	exit(1);
}

/* 普通用户信息 */
void debug_msg(const char *fmt, ...)
{
	va_list	ap;

	va_start(ap, fmt);
	DBG_PRINTF(0, fmt, ap);
	va_end(ap);
}

/* 打印核心函数 */
static void debug_print(int errnoflag, const char *fmt, va_list ap)
{
	int	errno_save, n;
	char buf[MAXLINE + 1];

	errno_save = errno;

	vsnprintf(buf, MAXLINE, fmt, ap);	/* safe */

	n = strlen(buf);
	if (errnoflag)
		snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save));
	strcat(buf, "\n");

	fflush(stderr);
	fputs(buf, stderr);	/* no newline */
	fflush(stderr);
}



================================================
FILE: src/logger.h
================================================

#pragma once

void debug_ret(const char *fmt, ...);
void debug_sys(const char *fmt, ...);
void debug_msg(const char *fmt, ...);
void debug_quit(const char *fmt, ...);

================================================
FILE: src/makefile
================================================
src = $(wildcard ./*c)
obj = $(patsubst ./%.c, ./%.o, $(src))

LIB = libmuevent.a
CC = gcc
CFLAGS := -g -lpthread 



%.o:%.c
	$(CC) $(CFLAGS) -c $< -o $@ 

$(LIB):$(obj)
	rm -f $@
	ar cr $@ $(obj)
	rm -f $(obj) 



.PHONY:clean
clean:
	rm -f $(obj) $(LIB) 
.PHONY:cleantemp
cleantemp:
	rm -f $(obj) 

================================================
FILE: src/ring_buffer.c
================================================
#include <string.h>
#include <stdlib.h>
#include "ring_buffer.h"
#include "config.h"

ring_buffer* ring_buffer_new()
{
    ring_buffer* rb = (ring_buffer*)mu_malloc(sizeof(ring_buffer));
    memset(rb, 0, sizeof(ring_buffer));
    return rb;
}


void ring_buffer_free(ring_buffer* rb)
{
    if (rb->msg)  {
        mu_free(rb->msg);
    }
}



void ring_buffer_push_data(ring_buffer* rb, char* msg, int size)
{
    int used = rb->end - rb->start;
    int available = rb->cap - used;
    if (available < size)  {          //可用数据不足了
        if (rb->start > size)  {      //可以塞前面
            memmove(rb->msg, rb->msg + rb->start, used);
            rb->start = 0;
            memcpy(rb->msg + used, msg, size);
            rb->end = used + size;
        }
        else  {
            rb->cap = rb->cap * 2 + size;
            char* new_msg = (char*)mu_malloc(rb->cap);
            if (used > 0 )  {
                memcpy(new_msg, rb->msg + rb->start, used);
            }
            memcpy(new_msg + used, msg, size);
            if (rb->msg)  {    //刚开始非空
                mu_free(rb->msg);
            }
            rb->msg = new_msg;
            rb->start = 0;
            rb->end = size + used;
        }
    }
    else  {
        memcpy(rb->msg + rb->end, msg, size);
        rb->end += size;
    }
}




char* ring_buffer_readable_start(ring_buffer* rb)
{
    return rb->msg + rb->start;
}

char* ring_buffer_get_msg(ring_buffer* rb, int* len)
{
    char* msg = rb->msg + rb->start;
    if (len)  {
        int ocuSize = rb->end - rb->start;
        *len = ocuSize;
    }
    if (rb->end == rb->start)  {
        msg = NULL;
    }
    return msg;
}


int ring_buffer_readable_bytes(ring_buffer* rb)
{
    int ocuSize = rb->end - rb->start;
    return ocuSize;
}

int ring_buffer_available_bytes(ring_buffer* rb)
{
    return rb->cap - rb->end;
}

void ring_buffer_release_bytes(ring_buffer* rb, int size)
{
    if (rb->msg + rb->start)  {
        memset(rb->msg + rb->start, 0, size);
    }
    rb->start += size;
    if (rb->start == rb->end)  {
        rb->start = rb->end = 0;
    }
}

================================================
FILE: src/ring_buffer.h
================================================
#pragma once

struct ring_buffer_t   {
    int start;
    int end;
    int cap;
    
    char* msg;

};

typedef struct ring_buffer_t ring_buffer;

ring_buffer* ring_buffer_new();
void ring_buffer_free(ring_buffer* rb);

void ring_buffer_push_data(ring_buffer* rb, char* msg, int size);



char* ring_buffer_readable_start(ring_buffer* rb);

int ring_buffer_readable_bytes(ring_buffer* rb);

void ring_buffer_release_bytes(ring_buffer* rb, int size);

char* ring_buffer_get_msg(ring_buffer* rb, int* len);

int ring_buffer_available_bytes(ring_buffer* rb);



================================================
FILE: src/servermanager.c
================================================
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/time.h>
#include "servermanager.h"
#include "event_loop.h"
#include "epoll.h"
#include "config.h"
#include "timer.h"
#include "logger.h"

event_loop *g_loops[MAX_LOOP];

int started_loop = 0;
pthread_spinlock_t lock;

void* spawn_thread(void *arg)
{
	int i = (long)arg;
	g_loops[i] = event_loop_create();
    pthread_spin_lock(&lock);
    started_loop++;
    pthread_spin_unlock(&lock);
	event_loop_run(g_loops[i]);
    return 0;
}


server_manager* server_manager_create(int port, int thread_num)
{
    pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE);
    server_manager* manager = (server_manager*)malloc(sizeof(server_manager));
    if (manager == NULL)  {
		debug_ret("create server_manager failed, file: %s, line: %d", __FILE__, __LINE__);
		return NULL;
	}
	manager->listen_port = port;

    manager->loop = event_loop_create();
    if (manager->loop == NULL)  {
        debug_ret("create epoller failed, file: %s, line: %d", __FILE__, __LINE__);
	 	mu_free(manager);
	 	return NULL;
    }

    signal(SIGPIPE, SIG_IGN);

    if (thread_num < 0 || thread_num > MAX_LOOP) {
        thread_num = MAX_LOOP;
    }
    manager->loop_num = thread_num;
    pthread_t tid;
    long long i = 0;
	for (i = 0; i < thread_num; i++)  {
		pthread_create(&tid, NULL, spawn_thread, (void *)i);
	}

    while(true)  {       //等event_loop全部create完毕
        pthread_spin_lock(&lock);
        if (started_loop == thread_num)  {
            pthread_spin_unlock(&lock);
            break;
        }
        pthread_spin_unlock(&lock);
    }

    pthread_spin_destroy(&lock);
    manager->timer_manager = timer_manager_create();
	
	return manager;
}

void server_manager_time_event(server_manager* manager, int timeout)
{
    timer_manager* tm = manager->timer_manager;
    if (!tm || tm->size <= 0)  {
        return;
    }

    timer_manager_update(tm, timeout);

    timer* top = tm->top;
    while(top->time_left <= 0)  {
        timer ti = timer_manager_pop(tm);
        if (ti.type == TIMER_OPT_ONCE)  {
            ti.callback(ti.arg);
        }
        else if (ti.type == TIMER_OPT_REPEAT)  {
            server_manager_add_timer(manager, ti);
            ti.callback(ti.arg);
        }
        top = tm->top;
    }
}


bool calc_timeout(server_manager* manager, int* timeout)
{
    timer_manager* tm = manager->timer_manager;
    if (tm && tm->size > 0 && tm->top)  {
        *timeout = tm->top->time_left;
        return true;
    }
    *timeout = -1;
    return false;
}


void server_manager_add_timer(server_manager* manager, timer ti)
{
    timer_manager* tm = manager->timer_manager;
    if (!tm)  {
        return ;
    }

    timer_manager_push(tm, ti);
}



void server_manager_run(server_manager* manager)
{
    int timeout = -1;
    while(1)  {
        bool has_timeout = calc_timeout(manager, &timeout);

        struct timeval now;
        gettimeofday(&now, NULL);
        struct timeval trigger_time = epoller_dispatch(manager->loop->epoll_fd, timeout);       //

        int64_t diff = (trigger_time.tv_sec - now.tv_sec) * 1000 * 1000 + (trigger_time.tv_usec - now.tv_usec);
        timeout = diff / 1000;

        if (has_timeout)  {
            server_manager_time_event(manager, timeout);         //已经过去了多少毫秒
        }
    }
}

================================================
FILE: src/servermanager.h
================================================
#pragma once 


typedef struct connection_t connection;

typedef void (*connection_callback_pt)(connection *conn);
typedef void (*message_callback_pt)(connection *conn);

typedef struct event_loop_t event_loop;

typedef struct timer_ timer;

typedef struct timer_manager_t timer_manager;


struct server_manager_t {
    int epoll_fd;
    int listen_port;
    int loop_num;

    event_loop* loop;

    connection_callback_pt new_connection_callback;
    message_callback_pt msg_callback;

    timer_manager* timer_manager;
};


typedef struct server_manager_t server_manager;


server_manager* server_manager_create(int port, int thread_num);
void server_manager_run(server_manager* manager);

void server_manager_add_timer(server_manager* manager, timer ti);

 

================================================
FILE: src/tcpclient.c
================================================
#include <sys/epoll.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "tcpclient.h"
#include "config.h"
#include "event_loop.h"
#include "event.h"
#include "connection.h"
#include "logger.h"


tcpclient* tcpclient_create(const char* ip, short port)
{
    tcpclient* cli = (tcpclient*)mu_malloc(sizeof(tcpclient));
    int socket_fd = socket(AF_INET, SOCK_STREAM, 0);  
    if (socket_fd < 0)  {
        debug_ret("create socket failed, file: %s, line: %d", __FILE__, __LINE__);
        return NULL;
	}
    cli->connfd = socket_fd;
    cli->ip = (char*)ip;
    cli->port = port;

    signal(SIGPIPE, SIG_IGN);

    return cli;
}

static void default_disconnect_callback(connection* conn)
{
    printf("client disconnected#######\n\n");
}


int tcpclient_connect(tcpclient* cli, connected_callback_pt connected_cb, message_callback_pt msg_cb)
{
    struct sockaddr_in server_address;
    memset( &server_address, 0, sizeof(server_address));
    server_address.sin_family = AF_INET;
    inet_pton( AF_INET, cli->ip, &server_address.sin_addr);
    server_address.sin_port = htons(cli->port);

    int ret = connect(cli->connfd, (struct sockaddr*)&server_address, sizeof(server_address));
    if (ret == -1)  {
        debug_sys("connect failed, file: %s, line: %d", __FILE__, __LINE__);
        return -1;
    }

    connection *conn = connection_create(cli->connfd, msg_cb);      //后面的参数是指有消息时的用户回调
	if (conn == NULL)  {
		debug_quit("create connection failed, file: %s, line: %d", __FILE__, __LINE__);
	}
    conn->disconnected_cb = default_disconnect_callback;

    connected_cb(conn);
    return 0;
}



void tcpclient_run(event_loop* loop)
{
    event_loop_run(loop);
}



================================================
FILE: src/tcpclient.h
================================================
#pragma once

typedef struct event_loop_t event_loop;
typedef struct connection_t connection;
typedef void (*message_callback_pt)(connection *conn);

struct tcpclient_t  {
    int connfd;
    char* ip;
    short port;

    event_loop* loop;
    //message_callback_pt msg_callback;
};


typedef struct tcpclient_t tcpclient;

tcpclient* tcpclient_create(const char* ip, short port);


typedef void (*connected_callback_pt)(connection *conn);

int tcpclient_connect(tcpclient* cli, connected_callback_pt connected_cb, message_callback_pt msg_cb);

int tcpclient_send(tcpclient* cli);

void tcpclient_run(event_loop* loop);

================================================
FILE: src/testcase/test_buffer.c
================================================
#include<stdio.h>
#include<stdlib.h>

#include "../buffer.h"

int main()  
{
    socket_buffer* sb = socket_buffer_new();

    buffer_push_data(sb, "123456", 6);
    buffer_push_data(sb, "abcdef", 6);
    buffer_push_data(sb, "xyzmnl", 6);
    
    int size = 0;
    char* msg = buffer_read_spec(sb, 28, NULL);
    printf("read %s, %d\n", msg, size);
    printf("aft read sb->size is %d\n\n", sb->size);

    msg = buffer_read_spec(sb, 18, &size);
    printf("read %s, %d\n", msg, size);
    printf("aft read sb->size is %d\n\n", sb->size);

    msg = buffer_read_all(sb, &size);
    printf("read %s, %d\n", msg, size);
    printf("aft read sb->size is %d\n\n", sb->size);

    socket_buffer_free(sb);
    return 0;
}

================================================
FILE: src/testcase/test_timer.c
================================================
#include <stdio.h>

#include "../timer.h"



int main()
{
    timer_manager* t = timer_manager_create();

    timer* t1 = timer_new(500);
    timer* t2 = timer_new(250);
    timer* t3 = timer_new(360);
    timer* t4 = timer_new(180);
    timer* t5 = timer_new(300);
    timer* t6 = timer_new(180);
    
    timer_manager_push(t, *t1);
    timer_manager_push(t, *t2);
    timer_manager_push(t, *t3);
    timer_manager_push(t, *t4);
    timer_manager_push(t, *t5);
    timer_manager_push(t, *t6);

    //timer* top = timer_manager_get_top(t);

    //printf("t top is %d\n", top->time_out);

    timer top = timer_manager_pop(t);
    printf("t top is %d\n", top.time_out);
    top = timer_manager_pop(t);
    printf("t top is %d\n", top.time_out);
    top = timer_manager_pop(t);
    printf("t top is %d\n", top.time_out);
    top = timer_manager_pop(t);
    printf("t top is %d\n", top.time_out);
    top = timer_manager_pop(t);
    printf("t top is %d\n", top.time_out);
    top = timer_manager_pop(t);
    printf("t top is %d\n", top.time_out);


    timer_manager_push(t, *t3);
    timer_manager_push(t, *t3);
    timer_manager_push(t, *t3);
    top = timer_manager_pop(t);
    printf("t top is %d\n", top.time_out);

    timer_manager_free(t);

    return 0;
}

================================================
FILE: src/timer.c
================================================

#include <string.h>
#include "timer.h"
#include "config.h"


timer_manager* timer_manager_create()
{
    int size = sizeof(timer_manager);
    timer_manager* m = (timer_manager*)mu_malloc(size);
    if (NULL == m)  {
        return NULL;
    }

    memset(m, 0, size);
    m->cap = MAX_TIMER_EVENT;

    m->queue0 = (timer**)mu_malloc(size * m->cap);
    m->queue1 = (timer**)mu_malloc(size * m->cap);
    memset(m->queue0, 0, size * m->cap);
    memset(m->queue1, 0, size * m->cap);
    return m;
}

void timer_manager_free(timer_manager* m)
{
    if (m)  {
        timer** queue = m->queue0;
        if (m->index == 1)  {
            queue = m->queue1;
        }
        int i = 0;
        for (; i < m->cap ; i++)  {
            if (queue[i])  {
                mu_free(queue[i]);
            }
            else  {
                break;
            }
        }

        if(m->queue0) mu_free(m->queue0);
        if(m->queue1) mu_free(m->queue1);
    }
}


timer* timer_new(int utime)
{
    timer* t = (timer*)malloc(sizeof(timer));
    memset(t, 0, sizeof(timer));
    t->time_out = utime;
    return t;
}


void timer_manager_push(timer_manager* manager, timer ti)
{
    int size = manager->size;
    if (size >= manager->cap)  {
        timer** temp0 = manager->queue0;
        timer** temp1 = manager->queue1;
        int size_of_ptr = sizeof(timer*);
        manager->queue0 = (timer**)mu_malloc(size_of_ptr * manager->cap * 2);
        manager->queue1 = (timer**)mu_malloc(size_of_ptr * manager->cap * 2);

        memset(manager->queue0, 0, size_of_ptr * manager->cap * 2);
        memset(manager->queue1, 0, size_of_ptr * manager->cap * 2);

        //memcpy(manager->queue0, temp0, manager->cap);
        //memcpy(manager->queue1, temp1, manager->cap);

        if (manager->index == 0)  {
            int i = 0;
            for (; i < manager->size; i++)  {
                manager->queue0[i] = temp0[i];
            }
        }
        else  {
            int i = 0;
            for (; i < manager->size; i++)  {
                manager->queue1[i] = temp1[i];
            }
        }

        mu_free(temp0);
        mu_free(temp1);
        manager->cap *= 2;
    }
    ti.time_left = ti.time_out;
    timer* pti = (timer*)mu_malloc(sizeof(timer));
    *pti = ti;
    if (manager->top)  {   
        if (pti->time_left < manager->top->time_left)  {   //替换最小的
            manager->top = pti;
            manager->top_index = size;
        }
    }
    else  {
        manager->top = pti;
    }

    if (manager->index == 0)  {
        manager->queue0[manager->size++] = pti;
    }
    else  {
        manager->queue1[manager->size++] = pti;
    }
}


timer timer_manager_pop(timer_manager* manager)
{
    timer ti;
    ti.time_out = 0;
    if (manager == NULL)  {
        return ti;
    }
    if (manager->size <= 0)  {
        return ti;
    }
    timer ret = *manager->top;
    if (manager->size == 1)  {
        manager->top = NULL;
        manager->size = 0;
        return ret;
    }
    mu_free(manager->top);
    manager->top = NULL;
    int top_index = manager->top_index;
    if (manager->size > 1) {
        timer* top = NULL;
        timer** queue0;
        timer** queue1;
        if (manager->index == 0)  {
            queue0 = manager->queue0;
            queue1 = manager->queue1;
        }
        else  {
            queue0 = manager->queue1;
            queue1 = manager->queue0;
        }
        manager->index = (manager->index + 1) % 2; 
        int i = 0;
        int j = 0;
        for (; i < manager->cap; i++)  {
            if (i < manager->size)  {
                if (i == top_index)  {
                    continue;
                }
                queue1[j] = queue0[i];
                if (top == NULL)  {
                    top = queue0[i];
                    manager->top_index = 0;
                }
                else  {
                    if (queue0[i]->time_left < top->time_left)  {
                        top = queue0[i];
                        manager->top_index = j;
                    }
                }
                j++; 
            }
            else  {
                queue0[i] = NULL;
                queue1[i] = NULL;
            }   
        }
        manager->top = top;
    }
    manager->size -= 1;
    return ret;
}

timer timer_manager_get_top(timer_manager* manager)
{
    return *manager->top;
}

void timer_manager_update(timer_manager* manager, int timeout)
{
    timer** queue = NULL;
    if (manager->index == 0)  {
        queue = manager->queue0;
    }
    else  {
        queue = manager->queue1;
    }

    int i = 0;
    for (; i < manager->size; i++)  {
        timer* ti = queue[i];
        ti->time_left -= timeout;
    }
}


================================================
FILE: src/timer.h
================================================
#pragma once 


typedef void (*timeout_callback_pt)(void *arg);


enum TimerOptions {
    TIMER_OPT_NONE,		// 超时不处理 
	TIMER_OPT_ONCE,		// 超时处理一次 
	TIMER_OPT_REPEAT	// 超时重复处理 
};


struct timer_  {
    int time_out;        //单位毫秒
    int time_left;
    enum TimerOptions type;
    timeout_callback_pt callback;
    void* arg;
};

typedef struct timer_ timer;

struct timer_manager_t  {
    timer* top;
    timer** queue0;
    timer** queue1;
    int index;
    int size;
    int cap;
    int top_index;
};


typedef struct timer_manager_t timer_manager;

timer_manager* timer_manager_create();

void timer_manager_free(timer_manager* m);

timer* timer_new(int utime);

void timer_manager_push(timer_manager* manager, timer ti);

timer timer_manager_pop(timer_manager* manager);

timer timer_manager_get_top(timer_manager* manager);

void timer_manager_update(timer_manager* manager, int timeout);
Download .txt
gitextract_05tbt9ce/

├── README.md
└── src/
    ├── buffer.c
    ├── buffer.h
    ├── config.h
    ├── connection.c
    ├── connection.h
    ├── epoll.c
    ├── epoll.h
    ├── event.c
    ├── event.h
    ├── event_loop.c
    ├── event_loop.h
    ├── example/
    │   ├── echo/
    │   │   ├── echosvr
    │   │   ├── echosvr.c
    │   │   └── run.sh
    │   └── timer/
    │       ├── run.sh
    │       ├── test_timer
    │       └── test_timer.c
    ├── listener.c
    ├── listener.h
    ├── logger.c
    ├── logger.h
    ├── makefile
    ├── ring_buffer.c
    ├── ring_buffer.h
    ├── servermanager.c
    ├── servermanager.h
    ├── tcpclient.c
    ├── tcpclient.h
    ├── testcase/
    │   ├── test_buffer.c
    │   └── test_timer.c
    ├── timer.c
    └── timer.h
Download .txt
SYMBOL INDEX (119 symbols across 25 files)

FILE: src/buffer.c
  function socket_buffer (line 7) | socket_buffer* socket_buffer_new()
  function socket_buffer_free (line 19) | void socket_buffer_free(socket_buffer* sb)
  function buffer_node (line 30) | buffer_node* new_buffer_node(int size)
  function buffer_push_data (line 47) | int buffer_push_data(socket_buffer* sb, char* msg, int sz)     //写数据到缓冲池...
  function buffer_node_release (line 86) | void buffer_node_release(socket_buffer* sb)    //返回给缓冲池
  function buffer_get_size (line 184) | int buffer_get_size(socket_buffer* sb)

FILE: src/buffer.h
  type buffer_node_t (line 3) | struct buffer_node_t {
  type buffer_pool_t (line 13) | struct buffer_pool_t {
  type socket_buffer_t (line 19) | struct socket_buffer_t {
  type buffer_node (line 30) | typedef struct buffer_node_t   buffer_node;
  type socket_buffer (line 31) | typedef struct socket_buffer_t socket_buffer;
  type buffer_pool (line 32) | typedef struct buffer_pool_t   buffer_pool;

FILE: src/connection.c
  function connection (line 30) | connection* connection_create(int connfd, message_callback_pt msg_cb)
  function connection_start (line 57) | void connection_start(connection* conn, event_loop* loop)
  function read_buffer (line 70) | static int read_buffer(int fd, connection* conn)       //使用了readv但是好像并没有...
  function event_readable_callback (line 109) | static void event_readable_callback(int fd, event* ev, void* arg)
  function event_writable_callback (line 121) | static void event_writable_callback(int fd, event* ev, void* arg)
  function connection_passive_close (line 142) | static void connection_passive_close(connection* conn)
  function connection_established (line 148) | void connection_established(connection* conn)
  function connection_active_close (line 154) | void connection_active_close(connection* conn)
  function connection_set_disconnect_callback (line 160) | void connection_set_disconnect_callback(connection* conn, connection_cal...
  function connection_disconnect (line 165) | static void connection_disconnect(connection* conn)
  function connection_free (line 177) | void connection_free(connection* conn)
  function connection_send (line 196) | void connection_send(connection *conn, char *buf, size_t len)  //外部调用来发送数据
  function connection_send_buffer (line 209) | int connection_send_buffer(connection *conn)                 //外部调用来发送数据

FILE: src/connection.h
  type connection (line 4) | typedef struct connection_t connection;
  type event (line 9) | typedef struct event_t event;
  type event_loop (line 11) | typedef struct event_loop_t event_loop;
  type socket_buffer (line 13) | typedef struct socket_buffer_t socket_buffer;
  type ring_buffer (line 14) | typedef struct ring_buffer_t   ring_buffer;
  type buffer_pool (line 15) | typedef struct buffer_pool_t   buffer_pool;
  type connection_t (line 22) | struct connection_t  {

FILE: src/epoll.c
  function epoller_create (line 13) | int epoller_create()
  function epoll_free (line 23) | void epoll_free(int fd)
  function epoller_add (line 28) | void epoller_add(int epoll_fd, event* e)
  function epoller_del (line 39) | void epoller_del(int epoll_fd, event* e)
  function epoller_modify (line 49) | void epoller_modify(int epoll_fd, event* e)
  function epoller_dispatch (line 61) | struct timeval epoller_dispatch(int epoll_fd, int timeout)

FILE: src/epoll.h
  type event (line 4) | typedef struct event_t event;
  type timeval (line 13) | struct timeval

FILE: src/event.c
  function event_error_handler (line 11) | static void event_error_handler(event* ev)
  function event_handler (line 16) | void event_handler(event* ev)
  function event (line 35) | event* event_create(int fd, short event_flag, event_callback_pt read_cb,
  function event_free (line 56) | void event_free(event* ev)
  function event_add_io (line 63) | void event_add_io(int epoll_fd, event* ev)
  function event_modify_flag (line 70) | void event_modify_flag(event* ev, int new_flag)
  function event_add_flag (line 80) | void event_add_flag(event* ev, int add_flag, int plus)
  function event_enable_writing (line 89) | void event_enable_writing(event* ev)
  function event_disable_writing (line 94) | void event_disable_writing(event* ev)
  function event_stop (line 100) | void event_stop(event *ev)

FILE: src/event.h
  type event (line 5) | typedef struct event_t event;
  type server_manager (line 6) | typedef struct server_manager_t server_manager;
  type event_t (line 10) | struct event_t {

FILE: src/event_loop.c
  function event_loop (line 9) | event_loop* event_loop_create()
  function event_loop_run (line 27) | void event_loop_run(event_loop* loop)

FILE: src/event_loop.h
  type event_loop_t (line 3) | struct event_loop_t  {
  type event_loop (line 7) | typedef struct event_loop_t event_loop;

FILE: src/example/echo/echosvr.c
  function onMessage (line 9) | void onMessage(connection *conn)
  function onConnection (line 21) | void onConnection(connection* conn)
  function main (line 26) | int main(int argc, char* argv[])

FILE: src/example/timer/test_timer.c
  function timer_cb (line 10) | static void timer_cb(void* arg)
  function timer_cb1 (line 15) | static void timer_cb1(void* arg)
  function timer_cb_once (line 20) | static void timer_cb_once(void* arg)
  function main (line 26) | int main(int argc, char* argv[])

FILE: src/listener.c
  function inet_address (line 22) | inet_address addr_create(const char *ip, int port)
  function default_disconnected_callback (line 41) | static void default_disconnected_callback(connection* conn)
  function event_accept_callback (line 46) | static void event_accept_callback(int listenfd, event* ev, void* arg)
  function listener (line 105) | listener* listener_create(server_manager* manager, inet_address ls_addr,

FILE: src/listener.h
  type inet_address (line 8) | typedef struct inet_addr_t {
  type connection (line 14) | typedef struct connection_t connection;
  type listener (line 20) | typedef struct listener_t listener;
  type listener_t (line 22) | struct listener_t  {
  type server_manager (line 27) | typedef struct server_manager_t server_manager;

FILE: src/logger.c
  function debug_ret (line 18) | void debug_ret(const char *fmt, ...)
  function debug_sys (line 30) | void debug_sys(const char *fmt, ...)
  function debug_quit (line 43) | void debug_quit(const char *fmt, ...)
  function debug_msg (line 54) | void debug_msg(const char *fmt, ...)
  function debug_print (line 64) | static void debug_print(int errnoflag, const char *fmt, va_list ap)

FILE: src/ring_buffer.c
  function ring_buffer (line 6) | ring_buffer* ring_buffer_new()
  function ring_buffer_free (line 14) | void ring_buffer_free(ring_buffer* rb)
  function ring_buffer_push_data (line 23) | void ring_buffer_push_data(ring_buffer* rb, char* msg, int size)
  function ring_buffer_readable_bytes (line 77) | int ring_buffer_readable_bytes(ring_buffer* rb)
  function ring_buffer_available_bytes (line 83) | int ring_buffer_available_bytes(ring_buffer* rb)
  function ring_buffer_release_bytes (line 88) | void ring_buffer_release_bytes(ring_buffer* rb, int size)

FILE: src/ring_buffer.h
  type ring_buffer_t (line 3) | struct ring_buffer_t   {
  type ring_buffer (line 12) | typedef struct ring_buffer_t ring_buffer;

FILE: src/servermanager.c
  function server_manager (line 30) | server_manager* server_manager_create(int port, int thread_num)
  function server_manager_time_event (line 74) | void server_manager_time_event(server_manager* manager, int timeout)
  function calc_timeout (line 98) | bool calc_timeout(server_manager* manager, int* timeout)
  function server_manager_add_timer (line 110) | void server_manager_add_timer(server_manager* manager, timer ti)
  function server_manager_run (line 122) | void server_manager_run(server_manager* manager)

FILE: src/servermanager.h
  type connection (line 4) | typedef struct connection_t connection;
  type event_loop (line 9) | typedef struct event_loop_t event_loop;
  type timer (line 11) | typedef struct timer_ timer;
  type timer_manager (line 13) | typedef struct timer_manager_t timer_manager;
  type server_manager_t (line 16) | struct server_manager_t {
  type server_manager (line 30) | typedef struct server_manager_t server_manager;

FILE: src/tcpclient.c
  function tcpclient (line 16) | tcpclient* tcpclient_create(const char* ip, short port)
  function default_disconnect_callback (line 33) | static void default_disconnect_callback(connection* conn)
  function tcpclient_connect (line 39) | int tcpclient_connect(tcpclient* cli, connected_callback_pt connected_cb...
  function tcpclient_run (line 65) | void tcpclient_run(event_loop* loop)

FILE: src/tcpclient.h
  type event_loop (line 3) | typedef struct event_loop_t event_loop;
  type connection (line 4) | typedef struct connection_t connection;
  type tcpclient_t (line 7) | struct tcpclient_t  {
  type tcpclient (line 17) | typedef struct tcpclient_t tcpclient;

FILE: src/testcase/test_buffer.c
  function main (line 6) | int main()

FILE: src/testcase/test_timer.c
  function main (line 7) | int main()

FILE: src/timer.c
  function timer_manager (line 7) | timer_manager* timer_manager_create()
  function timer_manager_free (line 25) | void timer_manager_free(timer_manager* m)
  function timer (line 48) | timer* timer_new(int utime)
  function timer_manager_push (line 57) | void timer_manager_push(timer_manager* manager, timer ti)
  function timer (line 112) | timer timer_manager_pop(timer_manager* manager)
  function timer (line 175) | timer timer_manager_get_top(timer_manager* manager)
  function timer_manager_update (line 180) | void timer_manager_update(timer_manager* manager, int timeout)

FILE: src/timer.h
  type TimerOptions (line 7) | enum TimerOptions {
  type timer_ (line 14) | struct timer_  {
  type timer (line 22) | typedef struct timer_ timer;
  type timer_manager_t (line 24) | struct timer_manager_t  {
  type timer_manager (line 35) | typedef struct timer_manager_t timer_manager;
Condensed preview — 33 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (57K chars).
[
  {
    "path": "README.md",
    "chars": 647,
    "preview": "#### C语言版muduo,对muduo的部分设计做了优化\n#### 之前用buffer队列实现的缓冲区,效果不是很好,后来使用了环形缓冲区\n\n#### 下面是和muduo的部分性能对比测试,测试标准参考陈硕大佬自己的标准 https:/"
  },
  {
    "path": "src/buffer.c",
    "chars": 5109,
    "preview": "#include <stdlib.h>\r\n#include <string.h>\r\n#include \"buffer.h\"\r\n#include \"config.h\"\r\n\r\n\r\nsocket_buffer* socket_buffer_new"
  },
  {
    "path": "src/buffer.h",
    "chars": 891,
    "preview": "#pragma once\r\n\r\nstruct buffer_node_t {\r\n    char* msg;\r\n    int sz;\r\n    struct buffer_node_t* next;\r\n\r\n    char* buf;\r\n"
  },
  {
    "path": "src/config.h",
    "chars": 511,
    "preview": "#pragma once \r\n#include <stdlib.h>\r\n\r\n#ifndef bool\r\n    #define bool int \r\n#endif\r\n\r\n#ifndef true\r\n    #define true 1\r\n#"
  },
  {
    "path": "src/connection.c",
    "chars": 6738,
    "preview": "#include <unistd.h>\r\n#include <stdlib.h>\r\n#include <stdio.h>\r\n#include <time.h>\r\n#include <sys/epoll.h>\r\n#include <sys/i"
  },
  {
    "path": "src/connection.h",
    "chars": 1392,
    "preview": "\r\n#pragma once\r\n\r\ntypedef struct connection_t connection;\r\n\r\ntypedef void (*message_callback_pt) (connection* conn);\r\nty"
  },
  {
    "path": "src/epoll.c",
    "chars": 2054,
    "preview": "#include <sys/time.h>\r\n#include <sys/epoll.h>\r\n#include <errno.h>\r\n#include <unistd.h>\r\n#include <stdlib.h>\r\n#include <s"
  },
  {
    "path": "src/epoll.h",
    "chars": 270,
    "preview": "#pragma once\r\n\r\n\r\ntypedef struct event_t event;\r\n\r\nint epoller_create();\r\nvoid epoller_free();\r\n\r\nvoid epoller_add(int f"
  },
  {
    "path": "src/event.c",
    "chars": 2399,
    "preview": "#include <sys/epoll.h>\r\n#include <stdlib.h>\r\n#include <unistd.h>\r\n#include <stdio.h>\r\n#include \"event.h\"\r\n#include \"serv"
  },
  {
    "path": "src/event.h",
    "chars": 866,
    "preview": "#pragma once\r\n#include <sys/time.h>\r\n\r\n\r\ntypedef struct event_t event;\r\ntypedef struct server_manager_t server_manager;\r"
  },
  {
    "path": "src/event_loop.c",
    "chars": 764,
    "preview": "#include <stdlib.h>\r\n#include <stdio.h>\r\n#include \"logger.h\"\r\n#include \"event_loop.h\"\r\n#include \"config.h\"\r\n#include \"ep"
  },
  {
    "path": "src/event_loop.h",
    "chars": 178,
    "preview": "#pragma once\r\n\r\nstruct event_loop_t  {\r\n    int epoll_fd;\r\n};\r\n\r\ntypedef struct event_loop_t event_loop;\r\n\r\nevent_loop* "
  },
  {
    "path": "src/example/echo/echosvr.c",
    "chars": 1074,
    "preview": "\r\n#include <stdio.h>\r\n#include \"servermanager.h\"\r\n#include \"connection.h\"\r\n#include \"listener.h\"\r\n#include \"ring_buffer."
  },
  {
    "path": "src/example/echo/run.sh",
    "chars": 67,
    "preview": "rm -f echosvr\n\ngcc -o echosvr *.c ../../*.c -lpthread -g -I ../../ "
  },
  {
    "path": "src/example/timer/run.sh",
    "chars": 97,
    "preview": "   \nrm  test_timer   \necho \"rm\"\ngcc -o test_timer test_timer.c ../../*.c -lpthread  -g -I ../../ "
  },
  {
    "path": "src/example/timer/test_timer.c",
    "chars": 1274,
    "preview": "#include<stdio.h>\r\n#include \"config.h\"\r\n#include \"connection.h\"\r\n#include \"servermanager.h\"\r\n#include \"listener.h\"\r\n#inc"
  },
  {
    "path": "src/listener.c",
    "chars": 4651,
    "preview": "#include <stdlib.h>\r\n#include <unistd.h>\r\n#include <errno.h>\r\n#include <sys/epoll.h>\r\n#include <fcntl.h>\r\n#include <stri"
  },
  {
    "path": "src/listener.h",
    "chars": 757,
    "preview": "#pragma once\r\n#include <sys/socket.h>\r\n#include <netinet/in.h>\r\n\r\n\r\n\r\n/* 封装的IPv4地址和port */\r\ntypedef struct inet_addr_t {"
  },
  {
    "path": "src/logger.c",
    "chars": 1284,
    "preview": "\r\n#include <stdarg.h>\r\n#include <stdio.h>\r\n#include <string.h>\r\n#include <errno.h>\r\n#include <stdlib.h>\r\n\r\n\r\n#define MAX"
  },
  {
    "path": "src/logger.h",
    "chars": 173,
    "preview": "\r\n#pragma once\r\n\r\nvoid debug_ret(const char *fmt, ...);\r\nvoid debug_sys(const char *fmt, ...);\r\nvoid debug_msg(const cha"
  },
  {
    "path": "src/makefile",
    "chars": 324,
    "preview": "src = $(wildcard ./*c)\r\nobj = $(patsubst ./%.c, ./%.o, $(src))\r\n\r\nLIB = libmuevent.a\r\nCC = gcc\r\nCFLAGS := -g -lpthread \r"
  },
  {
    "path": "src/ring_buffer.c",
    "chars": 2187,
    "preview": "#include <string.h>\r\n#include <stdlib.h>\r\n#include \"ring_buffer.h\"\r\n#include \"config.h\"\r\n\r\nring_buffer* ring_buffer_new("
  },
  {
    "path": "src/ring_buffer.h",
    "chars": 588,
    "preview": "#pragma once\r\n\r\nstruct ring_buffer_t   {\r\n    int start;\r\n    int end;\r\n    int cap;\r\n    \r\n    char* msg;\r\n\r\n};\r\n\r\ntype"
  },
  {
    "path": "src/servermanager.c",
    "chars": 3473,
    "preview": "#include <unistd.h>\r\n#include <pthread.h>\r\n#include <signal.h>\r\n#include <stdlib.h>\r\n#include <sys/time.h>\r\n#include \"se"
  },
  {
    "path": "src/servermanager.h",
    "chars": 798,
    "preview": "#pragma once \r\n\r\n\r\ntypedef struct connection_t connection;\r\n\r\ntypedef void (*connection_callback_pt)(connection *conn);\r"
  },
  {
    "path": "src/tcpclient.c",
    "chars": 1824,
    "preview": "#include <sys/epoll.h>\r\n#include <fcntl.h>\r\n#include <arpa/inet.h>\r\n#include <signal.h>\r\n#include <stdlib.h>\r\n#include <"
  },
  {
    "path": "src/tcpclient.h",
    "chars": 647,
    "preview": "#pragma once\r\n\r\ntypedef struct event_loop_t event_loop;\r\ntypedef struct connection_t connection;\r\ntypedef void (*message"
  },
  {
    "path": "src/testcase/test_buffer.c",
    "chars": 745,
    "preview": "#include<stdio.h>\r\n#include<stdlib.h>\r\n\r\n#include \"../buffer.h\"\r\n\r\nint main()  \r\n{\r\n    socket_buffer* sb = socket_buffe"
  },
  {
    "path": "src/testcase/test_timer.c",
    "chars": 1313,
    "preview": "#include <stdio.h>\r\n\r\n#include \"../timer.h\"\r\n\r\n\r\n\r\nint main()\r\n{\r\n    timer_manager* t = timer_manager_create();\r\n\r\n    "
  },
  {
    "path": "src/timer.c",
    "chars": 4916,
    "preview": "\r\n#include <string.h>\r\n#include \"timer.h\"\r\n#include \"config.h\"\r\n\r\n\r\ntimer_manager* timer_manager_create()\r\n{\r\n    int si"
  },
  {
    "path": "src/timer.h",
    "chars": 943,
    "preview": "#pragma once \r\n\r\n\r\ntypedef void (*timeout_callback_pt)(void *arg);\r\n\r\n\r\nenum TimerOptions {\r\n    TIMER_OPT_NONE,\t\t// 超时不"
  }
]

// ... and 2 more files (download for full content)

About this extraction

This page contains the full source code of the shonm520/mu_event GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 33 files (47.8 KB), approximately 13.9k tokens, and a symbol index with 119 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!