libevent源码解析(五)evbuffer增删拷贝接口函数

一.前言

  本篇分析evbuffer以及evbuffer_chain的相关增删、拷贝相关的接口函数,更多的如读写、查找等放在下一篇讲解。源码在buffer.c中,由于接口函数众多,这里仅介绍部分相对比较复杂的,还有很多几行以内实现的就不做介绍了。

二.接口函数解析

evbuffer_new

/*新建evbuffer*/
struct evbuffer *
evbuffer_new(void)
{
    struct evbuffer *buffer;

    /*分配内存空间*/
    buffer = mm_calloc(1, sizeof(struct evbuffer));
    if (buffer == NULL)
        return (NULL);

    /*指针初始化*/
    LIST_INIT(&buffer->callbacks);
    buffer->refcnt = 1;
    buffer->last_with_datap = &buffer->first;

    return (buffer);
}

evbuffer_chain_new

/*新建链表项*/
static struct evbuffer_chain *
evbuffer_chain_new(size_t size)
{
    struct evbuffer_chain *chain;
    size_t to_alloc;

    /*异常检测*/
    if (size > EVBUFFER_CHAIN_MAX - EVBUFFER_CHAIN_SIZE)
        return (NULL);

    /* 所需的大小size 再 加上evbuffer_chain结构体本身所需  
     * 的内存大小。这样做的原因是,evbuffer_chain本身是管理  
     * buffer的结构体。但buffer内存就分配在evbuffer_chain结构体存储  
     * 内存的后面。所以要申请多一些内存。*/
    size += EVBUFFER_CHAIN_SIZE;

    /* 获取最大内存:按512的倍数来
     * get the next largest memory that can hold the buffer 
     */
    if (size < EVBUFFER_CHAIN_MAX / 2) {
        to_alloc = MIN_BUFFER_SIZE;
        while (to_alloc < size) {
            to_alloc <<= 1;
        }
    } else {
        to_alloc = size;
    }

    /* 分配内存 we get everything in one chunk */
    if ((chain = mm_malloc(to_alloc)) == NULL)
        return (NULL);

    /*初始化*/
    memset(chain, 0, EVBUFFER_CHAIN_SIZE);

    /*缓冲区大小赋值*/
    chain->buffer_len = to_alloc - EVBUFFER_CHAIN_SIZE;

    /* this way we can manipulate the buffer to different addresses,
     * which is required for mmap for example.
     */
    chain->buffer = EVBUFFER_CHAIN_EXTRA(unsigned char, chain);

    chain->refcnt = 1;

    return (chain);
}

evbuffer_chain_insert

/* 尾部插入 Add a single chain 'chain' to the end of 'buf', freeing trailing empty
 * chains as necessary.  Requires lock.  Does not schedule callbacks.
 */
static void
evbuffer_chain_insert(struct evbuffer *buf,
    struct evbuffer_chain *chain)
{
    ASSERT_EVBUFFER_LOCKED(buf);

    /*若链表为空,则该chain既是头也是尾,否则在尾部插入*/
    if (*buf->last_with_datap == NULL) {
        /* There are no chains data on the buffer at all. */
        EVUTIL_ASSERT(buf->last_with_datap == &buf->first);
        EVUTIL_ASSERT(buf->first == NULL);
        buf->first = buf->last = chain;
    } else {
        struct evbuffer_chain **chp;
        chp = evbuffer_free_trailing_empty_chains(buf);
        *chp = chain;
        if (chain->off)
            buf->last_with_datap = chp;
        buf->last = chain;
    }
    buf->total_len += chain->off;
}

/* 1.调用new新建evbuffer_chain
 * 2.调用insert出入链表
 */
static inline struct evbuffer_chain *
evbuffer_chain_insert_new(struct evbuffer *buf, size_t datlen)
{
    struct evbuffer_chain *chain;
    if ((chain = evbuffer_chain_new(datlen)) == NULL)
        return NULL;
    evbuffer_chain_insert(buf, chain);
    return chain;
}

evbuffer_add

/* 向缓冲区添加数据 Adds data to an event buffer */
int
evbuffer_add(struct evbuffer *buf, const void *data_in, size_t datlen)
{
    struct evbuffer_chain *chain, *tmp;
    const unsigned char *data = data_in;
    size_t remain, to_alloc;
    int result = -1;

    EVBUFFER_LOCK(buf);

    /*禁止尾部添加数据则直接跳转done*/
    if (buf->freeze_end) {
        goto done;
    }

    /* 异常处理:数据过多 Prevent buf->total_len overflow */
    if (datlen > EV_SIZE_MAX - buf->total_len) {
        goto done;
    }

    /*空链表则初始化*/
    if (*buf->last_with_datap == NULL) {
        chain = buf->last;
    } else {
        chain = *buf->last_with_datap;
    }

    /* 对空链表调用new和insert 
     * If there are no chains allocated for this buffer, allocate one
     * big enough to hold all the data. */
    if (chain == NULL) {
        chain = evbuffer_chain_new(datlen);
        if (!chain)
            goto done;
        evbuffer_chain_insert(buf, chain);
    }

    /*EVBUFFER_IMMUTABLE 是 read-only chain, remain赋值0*/
    if ((chain->flags & EVBUFFER_IMMUTABLE) == 0) {
        /* Always true for mutable buffers */
        EVUTIL_ASSERT(chain->misalign >= 0 &&
            (ev_uint64_t)chain->misalign <= EVBUFFER_CHAIN_MAX);

        /* 计算可用空间,足够则拷贝数据完成add函数跳转out
         * 不够则尝试加上misalignment空间是否够,够则完成拷贝并跳转out
         */
        remain = chain->buffer_len - (size_t)chain->misalign - chain->off;
        if (remain >= datlen) {
            /* there's enough space to hold all the data in the
             * current last chain */
            memcpy(chain->buffer + chain->misalign + chain->off,
                data, datlen);
            chain->off += datlen;
            buf->total_len += datlen;
            buf->n_add_for_cb += datlen;
            goto out;
        } else if (!CHAIN_PINNED(chain) &&
            evbuffer_chain_should_realign(chain, datlen)) {
            /* we can fit the data into the misalignment */
            evbuffer_chain_align(chain);

            memcpy(chain->buffer + chain->off, data, datlen);
            chain->off += datlen;
            buf->total_len += datlen;
            buf->n_add_for_cb += datlen;
            goto out;
        }
    } else {
        /* we cannot write any data to the last chain */
        remain = 0;
    }

    /* 空间不足则需要增加chain
     * we need to add another chain 
     */
    to_alloc = chain->buffer_len;
    if (to_alloc <= EVBUFFER_CHAIN_MAX_AUTO_SIZE/2)
        to_alloc <<= 1;
    if (datlen > to_alloc)
        to_alloc = datlen;

    /*新建链表项*/
    tmp = evbuffer_chain_new(to_alloc);
    if (tmp == NULL)
        goto done;

    /* 进入这里则表明是可写buffer并且可用空间不足,
     * 因此需要扩展链表,但是先填满链表最后那个节点
     */
    if (remain) {
        memcpy(chain->buffer + chain->misalign + chain->off,
            data, remain);
        chain->off += remain;
        buf->total_len += remain;
        buf->n_add_for_cb += remain;
    }

    data += remain;
    datlen -= remain;

    /*填充数据,插入链表*/
    memcpy(tmp->buffer, data, datlen);
    tmp->off = datlen;
    evbuffer_chain_insert(buf, tmp);
    buf->n_add_for_cb += datlen;

out:
    evbuffer_invoke_callbacks_(buf);
    result = 0;
done:
    EVBUFFER_UNLOCK(buf);
    return result;
}

evbuffer_prepend

/*链表前添加数据*/
int
evbuffer_prepend(struct evbuffer *buf, const void *data, size_t datlen)
{
    struct evbuffer_chain *chain, *tmp;
    int result = -1;

    EVBUFFER_LOCK(buf);

    /*链表首部无法修改则跳转done*/
    if (buf->freeze_start) {
        goto done;
    }
    /*数据过多则跳转至done*/
    if (datlen > EV_SIZE_MAX - buf->total_len) {
        goto done;
    }

    chain = buf->first;

    /*空链表则执行new和insert*/
    if (chain == NULL) {
        chain = evbuffer_chain_new(datlen);
        if (!chain)
            goto done;
        evbuffer_chain_insert(buf, chain);
    }

    /* we cannot touch immutable buffers */
    if ((chain->flags & EVBUFFER_IMMUTABLE) == 0) {
        /* Always true for mutable buffers */
        EVUTIL_ASSERT(chain->misalign >= 0 &&
            (ev_uint64_t)chain->misalign <= EVBUFFER_CHAIN_MAX);

        /* 和尾部插入不同,这里首先是考虑在misalign中插入,即头部插入
         * If this chain is empty, we can treat it as
         * 'empty at the beginning' rather than 'empty at the end' */
        if (chain->off == 0)
            chain->misalign = chain->buffer_len;

        if ((size_t)chain->misalign >= datlen) {
            /* we have enough space to fit everything */
            memcpy(chain->buffer + chain->misalign - datlen,
                data, datlen);
            chain->off += datlen;
            chain->misalign -= datlen;
            buf->total_len += datlen;
            buf->n_add_for_cb += datlen;
            goto out;
        } else if (chain->misalign) {
            /* misalign只能放部分数据 we can only fit some of the data. */
            memcpy(chain->buffer,
                (char*)data + datlen - chain->misalign,
                (size_t)chain->misalign);
            chain->off += (size_t)chain->misalign;
            buf->total_len += (size_t)chain->misalign;
            buf->n_add_for_cb += (size_t)chain->misalign;
            datlen -= (size_t)chain->misalign;
            chain->misalign = 0;
        }
    }

    /* 增加新的链表项 we need to add another chain */
    if ((tmp = evbuffer_chain_new(datlen)) == NULL)
        goto done;
    buf->first = tmp;

    /*仅有一项,则头即是尾*/
    if (buf->last_with_datap == &buf->first)
        buf->last_with_datap = &tmp->next;

    /*链表头部插入以及数据拷贝*/
    tmp->next = chain;

    tmp->off = datlen;
    EVUTIL_ASSERT(datlen <= tmp->buffer_len);
    tmp->misalign = tmp->buffer_len - datlen;

    memcpy(tmp->buffer + tmp->misalign, data, datlen);
    buf->total_len += datlen;
    buf->n_add_for_cb += datlen;

out:
    evbuffer_invoke_callbacks_(buf);
    result = 0;
done:
    EVBUFFER_UNLOCK(buf);
    return result;
}

evbuffer_expand_singlechain

/* 扩展ebuffer
 * Expands the available space in the event buffer to at least datlen, all in
 * a single chunk.  Return that chunk. */
static struct evbuffer_chain *
evbuffer_expand_singlechain(struct evbuffer *buf, size_t datlen)
{
    struct evbuffer_chain *chain, **chainp;
    struct evbuffer_chain *result = NULL;
    ASSERT_EVBUFFER_LOCKED(buf);

    chainp = buf->last_with_datap;

    /* chainp指向最后一个有数据的链表项
     * 当最后一个有数据的evbuffer_chain还有空闲空间时  
     * chainp就指向之。否则*chainp指向最后一个有数据的evbuffer_chain的next。
     * XXX If *chainp is no longer writeable, but has enough space in its
     * misalign, this might be a bad idea: we could still use *chainp, not
     * (*chainp)->next. */
    if (*chainp && CHAIN_SPACE_LEN(*chainp) == 0)
        chainp = &(*chainp)->next;

    /* 'chain' now points to the first chain with writable space (if any)
     * We will either use it, realign it, replace it, or resize it. */
    chain = *chainp;

    /*若不可修改则出入新的chain*/
    if (chain == NULL ||
        (chain->flags & (EVBUFFER_IMMUTABLE|EVBUFFER_MEM_PINNED_ANY))) {
        /* We can't use the last_with_data chain at all.  Just add a
         * new one that's big enough. */
        goto insert_new;
    }

    /* 若大小足够则不需要扩张
     * If we can fit all the data, then we don't have to do anything 
     */
    if (CHAIN_SPACE_LEN(chain) >= datlen) {
        result = chain;
        goto ok;
    }

    /* If the chain is completely empty, just replace it by adding a new
     * empty chain. */
    if (chain->off == 0) {
        goto insert_new;
    }

    /* 预留空间够用,则使用misaligment空间而不需要扩张
     * If the misalignment plus the remaining space fulfills our data
     * needs, we could just force an alignment to happen.  Afterwards, we
     * have enough space.  But only do this if we're saving a lot of space
     * and not moving too much data.  Otherwise the space savings are
     * probably offset by the time lost in copying.
     */
    if (evbuffer_chain_should_realign(chain, datlen)) {
        evbuffer_chain_align(chain);
        result = chain;
        goto ok;
    }

    /* 上述情况均不符合则一定要扩展空间了,这里提供了两个思路:
     * 1.重新在已有内存块上增加空间
     * 2.新申请一块空间
     * At this point, we can either resize the last chunk with space in
     * it, use the next chunk after it, or   If we add a new chunk, we waste
     * CHAIN_SPACE_LEN(chain) bytes in the former last chunk.  If we
     * resize, we have to copy chain->off bytes.
     */

    /* 空闲空间小于总空间的1/8 或者已有的数据量大于MAX_TO_COPY_IN_EXPAND(4096)则选择方案2
     * 否则选择方案1
     * Would expanding this chunk be affordable and worthwhile? 
     */
    if (CHAIN_SPACE_LEN(chain) < chain->buffer_len / 8 ||
        chain->off > MAX_TO_COPY_IN_EXPAND ||
        datlen >= (EVBUFFER_CHAIN_MAX - chain->off)) {
        /* It's not worth resizing this chain. Can the next one be
         * used? */
        if (chain->next && CHAIN_SPACE_LEN(chain->next) >= datlen) {
            /* Yes, we can just use the next chain (which should
             * be empty. */
            result = chain->next;
            goto ok;
        } else {
            /* No; append a new chain (which will free all
             * terminal empty chains.) */
            goto insert_new;
        }
    } else {
        /* Okay, we're going to try to resize this chain: Not doing so
         * would waste at least 1/8 of its current allocation, and we
         * can do so without having to copy more than
         * MAX_TO_COPY_IN_EXPAND bytes. */
        /* figure out how much space we need */
        size_t length = chain->off + datlen;
        struct evbuffer_chain *tmp = evbuffer_chain_new(length);
        if (tmp == NULL)
            goto err;

        /* 数据迁移 copy the data over that we had so far */
        tmp->off = chain->off;
        memcpy(tmp->buffer, chain->buffer + chain->misalign,
            chain->off);
        /* fix up the list */
        EVUTIL_ASSERT(*chainp == chain);
        result = *chainp = tmp;

        if (buf->last == chain)
            buf->last = tmp;

        tmp->next = chain->next;
        evbuffer_chain_free(chain);
        goto ok;
    }

insert_new:
    result = evbuffer_chain_insert_new(buf, datlen);
    if (!result)
        goto err;
ok:
    EVUTIL_ASSERT(result);
    EVUTIL_ASSERT(CHAIN_SPACE_LEN(result) >= datlen);
err:
    return result;
}

evbuffer_expand_fast_

/* 用最多不超过n个节点就提供datlen大小的空闲空间
 * Make sure that datlen bytes are available for writing in the last n
 * chains.  Never copies or moves data. */
int
evbuffer_expand_fast_(struct evbuffer *buf, size_t datlen, int n)
{
    struct evbuffer_chain *chain = buf->last, *tmp, *next;
    size_t avail;
    int used;

    ASSERT_EVBUFFER_LOCKED(buf);
    /*要求n大于等于2*/
    EVUTIL_ASSERT(n >= 2);

    /*若链表为空或者不可修改,则直接新建链表并插入*/
    if (chain == NULL || (chain->flags & EVBUFFER_IMMUTABLE)) {
        /* There is no last chunk, or we can't touch the last chunk.
         * Just add a new chunk. */
        chain = evbuffer_chain_new(datlen);
        if (chain == NULL)
            return (-1);

        evbuffer_chain_insert(buf, chain);
        return (0);
    }

    used = 0; /* number of chains we're using space in. */
    avail = 0; /* how much space they have. */
    /* How many bytes can we stick at the end of buffer as it is?  Iterate
     * over the chains at the end of the buffer, tring to see how much
     * space we have in the first n. */
    for (chain = *buf->last_with_datap; chain; chain = chain->next) {
        /*先试用已有链表项剩余空间*/
        if (chain->off) {
            size_t space = (size_t) CHAIN_SPACE_LEN(chain);
            EVUTIL_ASSERT(chain == *buf->last_with_datap);
            if (space) {
                avail += space;
                ++used;
            }
        } else {
            /* No data in chain; realign it. */
            chain->misalign = 0;
            avail += chain->buffer_len;
            ++used;
        }
        if (avail >= datlen) {
            /* There is already enough space.  Just return */
            return (0);
        }
        if (used == n)
            break;
    }

    /* 运行到这里时,就说明还没找到空闲空间。一般是因为链表后面的off等于0  
     * 的节点已经被用完了都还不能满足datlen
     * There wasn't enough space in the first n chains with space in
     * them. Either add a new chain with enough space, or replace all
     * empty chains with one that has enough space, depending on n. */
    if (used < n) {
        /* The loop ran off the end of the chains before it hit n
         * chains; we can add another. */
        EVUTIL_ASSERT(chain == NULL);

        tmp = evbuffer_chain_new(datlen - avail);
        if (tmp == NULL)
            return (-1);

        buf->last->next = tmp;
        buf->last = tmp;
        /* (we would only set last_with_data if we added the first
         * chain. But if the buffer had no chains, we would have
         * just allocated a new chain earlier) */
        return (0);
    } else {

        /* 不能完成n次任务,则删除已有链表,新建链表
         * Nuke _all_ the empty chains. 
         */
        int rmv_all = 0; /* True iff we removed last_with_data. */
        chain = *buf->last_with_datap;
        if (!chain->off) {
            EVUTIL_ASSERT(chain == buf->first);
            rmv_all = 1;
            avail = 0;
        } else {
            /* can't overflow, since only mutable chains have
             * huge misaligns. */
            avail = (size_t) CHAIN_SPACE_LEN(chain);
            chain = chain->next;
        }

        /*删除全部*/
        for (; chain; chain = next) {
            next = chain->next;
            EVUTIL_ASSERT(chain->off == 0);
            evbuffer_chain_free(chain);
        }

        EVUTIL_ASSERT(datlen >= avail);

        /*新建链表:降低长度,扩大大小*/
        tmp = evbuffer_chain_new(datlen - avail);
        if (tmp == NULL) {
            if (rmv_all) {
                ZERO_CHAIN(buf);
            } else {
                buf->last = *buf->last_with_datap;
                (*buf->last_with_datap)->next = NULL;
            }
            return (-1);
        }

        if (rmv_all) {
            buf->first = buf->last = tmp;
            buf->last_with_datap = &buf->first;
        } else {
            (*buf->last_with_datap)->next = tmp;
            buf->last = tmp;
        }
        return (0);
    }
}

evbuffer_drain


/*删除buffer*/
int
evbuffer_drain(struct evbuffer *buf, size_t len)
{
    struct evbuffer_chain *chain, *next;
    size_t remaining, old_len;
    int result = 0;

    EVBUFFER_LOCK(buf);
    old_len = buf->total_len;

    if (old_len == 0)
        goto done;

    /*若头部不能修改则跳转done*/
    if (buf->freeze_start) {
        result = -1;
        goto done;
    }

    /*要删除的大于已有的数据量,则直接删除evbuffer即可*/
    if (len >= old_len && !HAS_PINNED_R(buf)) {
        len = old_len;
        for (chain = buf->first; chain != NULL; chain = next) {
            next = chain->next;
            evbuffer_chain_free(chain);
        }

        ZERO_CHAIN(buf);
    } else {
        if (len >= old_len)
            len = old_len;

        buf->total_len -= len;
        remaining = len;
        for (chain = buf->first;
             remaining >= chain->off;
             chain = next) {
            next = chain->next;
            remaining -= chain->off;

            /*最后一个等于第一个*/
            if (chain == *buf->last_with_datap) {
                buf->last_with_datap = &buf->first;
            }

            /*倒数第二个*/
            if (&chain->next == buf->last_with_datap)
                buf->last_with_datap = &buf->first;

            /*被固定无法删除的chain:跳过*/
            if (CHAIN_PINNED_R(chain)) {
                EVUTIL_ASSERT(remaining == 0);
                chain->misalign += chain->off;
                chain->off = 0;
                break;
            } else
                evbuffer_chain_free(chain);
        }

        buf->first = chain;
        EVUTIL_ASSERT(remaining <= chain->off);
        chain->misalign += remaining;
        chain->off -= remaining;
    }

    buf->n_del_for_cb += len;
    /* 调用回调函数
     * Tell someone about changes in this buffer 
     */
    evbuffer_invoke_callbacks_(buf);

done:
    EVBUFFER_UNLOCK(buf);
    return result;
}

evbuffer_remove

/* Reads data from an event buffer and drains the bytes read */
int
evbuffer_remove(struct evbuffer *buf, void *data_out, size_t datlen)
{
    ev_ssize_t n;
    EVBUFFER_LOCK(buf);
    /*复制数据之后删除而不是直接删除*/
    n = evbuffer_copyout_from(buf, NULL, data_out, datlen);
    if (n > 0) {
        if (evbuffer_drain(buf, n)<0)
            n = -1;
    }
    EVBUFFER_UNLOCK(buf);
    return (int)n;
}

evbuffer_copyout

/*复制evbuffer*/
ev_ssize_t
evbuffer_copyout(struct evbuffer *buf, void *data_out, size_t datlen)
{
    return evbuffer_copyout_from(buf, NULL, data_out, datlen);
}

ev_ssize_t
evbuffer_copyout_from(struct evbuffer *buf, const struct evbuffer_ptr *pos,
    void *data_out, size_t datlen)
{
    /*XXX fails badly on sendfile case. */
    struct evbuffer_chain *chain;
    char *data = data_out;
    size_t nread;
    ev_ssize_t result = 0;
    size_t pos_in_chain;

    EVBUFFER_LOCK(buf);

    /*pos是开始复制的位置的指针,为NULL则从头复制*/
    if (pos) {
        /*需要数据过多,无法复制*/
        if (datlen > (size_t)(EV_SSIZE_MAX - pos->pos)) {
            result = -1;
            goto done;
        }
        chain = pos->internal_.chain;
        pos_in_chain = pos->internal_.pos_in_chain;
        if (datlen + pos->pos > buf->total_len)
            datlen = buf->total_len - pos->pos;
    } else {
        chain = buf->first;
        pos_in_chain = 0;
        if (datlen > buf->total_len)
            datlen = buf->total_len;
    }


    /*没有数据则返回*/
    if (datlen == 0)
        goto done;

    /*禁止从头复制则失败*/
    if (buf->freeze_start) {
        result = -1;
        goto done;
    }

    nread = datlen;

    /*将数据复制入data中*/
    while (datlen && datlen >= chain->off - pos_in_chain) {
        size_t copylen = chain->off - pos_in_chain;
        memcpy(data,
            chain->buffer + chain->misalign + pos_in_chain,
            copylen);
        data += copylen;
        datlen -= copylen;

        chain = chain->next;
        pos_in_chain = 0;
        EVUTIL_ASSERT(chain || datlen==0);
    }

    if (datlen) {
        EVUTIL_ASSERT(chain);
        EVUTIL_ASSERT(datlen + pos_in_chain <= chain->off);

        memcpy(data, chain->buffer + chain->misalign + pos_in_chain,
            datlen);
    }

    /*返回读的字节数*/
    result = nread;
done:
    EVBUFFER_UNLOCK(buf);
    return result;
}

evbuffer_remove_buffer

/* 直接从src读数据到dst,减少memcpy
 * reads data from the src buffer to the dst buffer, avoids memcpy as
 * possible. */
/*  XXXX should return ev_ssize_t */
int
evbuffer_remove_buffer(struct evbuffer *src, struct evbuffer *dst,
    size_t datlen)
{
    /*XXX We should have an option to force this to be zero-copy.*/

    /*XXX can fail badly on sendfile case. */
    struct evbuffer_chain *chain, *previous;
    size_t nread = 0;
    int result;

    EVBUFFER_LOCK2(src, dst);

    chain = previous = src->first;

    /*没有数据或者源buffer和目的buffer相同自然不需要拷贝*/
    if (datlen == 0 || dst == src) {
        result = 0;
        goto done;
    }

    /*源buffer的头部禁止修改或目的buffer尾部禁止修改则返回*/
    if (dst->freeze_end || src->freeze_start) {
        result = -1;
        goto done;
    }

    /* 要读的数据超过了总数据量则读总数据量的数据并跳转done
     * short-cut if there is no more data buffered 
     */
    if (datlen >= src->total_len) {
        datlen = src->total_len;
        /*调用该函数实现数据的复制而不使用memcpy*/
        evbuffer_add_buffer(dst, src);
        result = (int)datlen; /*XXXX should return ev_ssize_t*/
        goto done;
    }

    /* 累计需要读的nread,用于remove链表
     * removes chains if possible 
     */
    while (chain->off <= datlen) {
        /* We can't remove the last with data from src unless we
         * remove all chains, in which case we would have done the if
         * block above */
        EVUTIL_ASSERT(chain != *src->last_with_datap);
        nread += chain->off;
        datlen -= chain->off;
        previous = chain;
        if (src->last_with_datap == &chain->next)
            src->last_with_datap = &src->first;
        chain = chain->next;
    }

    /*复制给dst*/
    if (nread) {
        /* we can remove the chain */
        struct evbuffer_chain **chp;
        chp = evbuffer_free_trailing_empty_chains(dst);

        if (dst->first == NULL) {
            dst->first = src->first;
        } else {
            *chp = src->first;
        }
        dst->last = previous;
        previous->next = NULL;
        src->first = chain;
        advance_last_with_data(dst);

        dst->total_len += nread;
        dst->n_add_for_cb += nread;
    }

    /* 数据存储到dst
     * we know that there is more data in the src buffer than
     * we want to read, so we manually drain the chain */
    evbuffer_add(dst, chain->buffer + chain->misalign, datlen);
    chain->misalign += datlen;
    chain->off -= datlen;
    nread += datlen;

    /* You might think we would want to increment dst->n_add_for_cb
     * here too.  But evbuffer_add above already took care of that.
     */
    src->total_len -= nread;
    src->n_del_for_cb += nread;

    if (nread) {
        evbuffer_invoke_callbacks_(dst);
        evbuffer_invoke_callbacks_(src);
    }
    result = (int)nread;/*XXXX should change return type */

done:
    EVBUFFER_UNLOCK2(src, dst);
    return result;
}

猜你喜欢

转载自blog.csdn.net/u013354486/article/details/80822250