static int tcpconn_recv(int s, void *buf, size_t len, int64_t deadline) {
    struct tcpconn *conn = bsockdata(s, tcpconn_type);
    if(dill_slow(!conn)) return -1;
    /* If there's enough data in the buffer use it. */
    if(dill_fast(len <= conn->ilen)) {
        memcpy(buf, conn->ibuf, len);
        memmove(conn->ibuf, conn->ibuf + len, conn->ilen - len);
        conn->ilen -= len;
        return 0;
    }
    /* If there's not enough data in the buffer, yet the message is small,
       read whole chunk of data to avoid excessive system calls. */
    if(len <= BATCHSIZE) {
        /* First try a non-blocking batch read. */
        size_t recvd = BATCHSIZE - conn->ilen;
        /* TODO: Make sure that deadline of 0 works as intended! */
        dsrecv(conn->fd, conn->ibuf + conn->ilen, &recvd, 0);
        conn->ilen += recvd;
        if(dill_fast(len <= conn->ilen)) {
            memcpy(buf, conn->ibuf, len);
            memmove(conn->ibuf, conn->ibuf + len, conn->ilen - len);
            conn->ilen -= len;
            return 0;
        }
    }
    /* Either message is big or we weren't able to read it in non-blocking
       fashion. In both cases let's try to read the missing data directly
       to the user's buffer. If the operation fails we'll copy the data that
       was already read to the input buffer. To make sure that the operation
       is atomic even in face of memory shortage let's resize the buffer first
       do receiving second. */
    if(dill_slow(len > conn->ilen)) {
        char *newbuf = realloc(conn->ibuf, len);
        if(dill_slow(!newbuf)) {errno = ENOMEM; return -1;}
        conn->ibuf = newbuf;
        conn->icap = len;
    }
    /* Read the missing part directly into user's buffer. */
    size_t recvd = len - conn->ilen;
    int rc = dsrecv(conn->fd, ((char*)buf) + conn->ilen, &recvd, deadline);
    /* If succesfull copy the first part of the message from input buffer. */
    if(dill_fast(rc == 0)) {
        memcpy(buf, conn->ibuf, conn->ilen);
        conn->ilen = 0;
        return 0;
    }
    /* If not successful, store the aready received data into input buffer. */
    int err = errno;
    memcpy(conn->ibuf + conn->ilen, ((char*)buf) + conn->ilen, recvd);
    conn->ibuf += recvd;
    errno = err;
    return -1;
}
static int tcpconn_send(int s, const void *buf, size_t len, int64_t deadline) {
    struct tcpconn *conn = bsockdata(s, tcpconn_type);
    if(dill_slow(!conn)) return -1;
    /* If the data fit into the buffer without exceeding the BATCHSIZE
       we can store it and be done with it. That way sending a lot of little
       messages won't result in lot of system calls. */
    if(dill_fast(conn->olen + len <= BATCHSIZE)) {
        memcpy(conn->obuf + conn->olen, buf, len);
        conn->olen += len;
        return 0;
    }
    /* Message won't fit into buffer, so let's try to flush the buffer first. */
    int rc = tcpconn_flush(s, deadline);
    if(dill_slow(rc < 0)) return -1;
    /* Try to fit the message into buffer again. */
    if(dill_fast(len <= BATCHSIZE)) {
        dill_assert(conn->olen == 0);
        memcpy(conn->obuf, buf, len);
        conn->olen = len;
        return 0;
    }
    /* Resize the buffer so that it can hold the message if needed. By doing
       this in advance we won't be faced with ugly non-atomic case when only
       part of the message is sent to the network but there's no buffer space
       to buffer the remaining data. */
    if(dill_slow(len > conn->olen)) {
        char *newbuf = realloc(conn->obuf, len);
        if(dill_slow(!newbuf)) {errno = ENOMEM; return -1;}
        conn->obuf = newbuf;
        conn->ocap = len;
    }
    /* Try to send the message directly from the user's buffer. */
    size_t sent = len;
    rc = dssend(conn->fd, buf, &sent, deadline);
    if(dill_fast(rc >= 0)) return 0;
    int err = errno;
    /* Store the remainder of the message into the output buffer. */
    dill_assert(conn->olen == 0);
    memcpy(conn->obuf, ((char*)buf) + sent, len - sent);
    conn->olen = len - sent;
    /* ETIMEDOUT can be ignored. The send operation have already completed
       successfully so there's no point in reporting the error. */
    if(dill_slow(err == ETIMEDOUT)) return 0;
    /* Other errors, such as ECONNRESET or ECANCELED are fatal so we can report
       them straight away even though message data were buffered. */
    errno = err;
    return -1;
}
示例#3
0
文件: timer.c 项目: zbanks/libdill
int64_t now(void) {
#if (defined __GNUC__ || defined __clang__) && \
      (defined __i386__ || defined __x86_64__)
    /* Get the timestamp counter. This is time since startup, expressed in CPU
       cycles. Unlike gettimeofday() or similar function, it's extremely fast -
       it takes only few CPU cycles to evaluate. */
    uint32_t low;
    uint32_t high;
    __asm__ volatile("rdtsc" : "=a" (low), "=d" (high));
    int64_t tsc = (int64_t)((uint64_t)high << 32 | low);
    /* These global variables are used to hold the last seen timestamp counter
       and last seen time measurement. We'll initilise them the first time
       this function is called. */
    static int64_t last_tsc = -1;
    static int64_t last_now = -1;
    if(dill_slow(last_tsc < 0)) {
        last_tsc = tsc;
        last_now = dill_now();
    }   
    /* If TSC haven't jumped back or progressed more than 1/2 ms, we can use
       the cached time value. */
    if(dill_fast(tsc - last_tsc <= (DILL_CLOCK_PRECISION / 2) &&
          tsc >= last_tsc))
        return last_now;
    /* It's more than 1/2 ms since we've last measured the time.
       We'll do a new measurement now. */
    last_tsc = tsc;
    last_now = dill_now();
    return last_now;
#else
    return dill_now();
#endif
}
示例#4
0
文件: udp.c 项目: reqshark/libdill
int udp_sendl_(struct msock_vfs *mvfs, const struct ipaddr *addr,
      struct iolist *first, struct iolist *last) {
    struct udp_sock *obj = dill_cont(mvfs, struct udp_sock, mvfs);
    /* If no destination IP address is provided, fall back to the stored one. */
    const struct ipaddr *dstaddr = addr;
    if(!dstaddr) {
        if(dill_slow(!obj->hasremote)) {errno = EINVAL; return -1;}
        dstaddr = &obj->remote;
    }
    struct msghdr hdr;
    memset(&hdr, 0, sizeof(hdr));
    hdr.msg_name = (void*)ipaddr_sockaddr(dstaddr);
    hdr.msg_namelen = ipaddr_len(dstaddr);
    /* Make a local iovec array. */
    /* TODO: This is dangerous, it may cause stack overflow.
       There should probably be a on-heap per-socket buffer for that. */
    size_t niov;
    int rc = iol_check(first, last, &niov, NULL);
    if(dill_slow(rc < 0)) return -1;
    struct iovec iov[niov];
    iol_toiov(first, iov);
    hdr.msg_iov = (struct iovec*)iov;
    hdr.msg_iovlen = niov;
    ssize_t sz = sendmsg(obj->fd, &hdr, 0);
    if(dill_fast(sz >= 0)) return 0;
    if(errno == EAGAIN || errno == EWOULDBLOCK) return 0;
    return -1;
}
示例#5
0
文件: ctx.c 项目: raedwulf/libdill
struct dill_ctx *dill_getctx_(void) {
    int rc = pthread_once(&dill_keyonce, dill_makekey);
    dill_assert(rc == 0);
    struct dill_ctx *ctx = pthread_getspecific(dill_key);
    if(dill_fast(ctx)) return ctx;
    ctx = malloc(sizeof(struct dill_ctx));
    dill_assert(ctx);
    rc = dill_ctx_now_init(&ctx->now);
    dill_assert(rc == 0);
    rc = dill_ctx_cr_init(&ctx->cr);
    dill_assert(rc == 0);
    rc = dill_ctx_handle_init(&ctx->handle);
    dill_assert(rc == 0);
    rc = dill_ctx_stack_init(&ctx->stack);
    dill_assert(rc == 0);
    rc = dill_ctx_pollset_init(&ctx->pollset);
    dill_assert(rc == 0);
    if(dill_ismain()) {
        dill_main = ctx;
        rc = atexit(dill_ctx_atexit);
        dill_assert(rc == 0);
    }
    rc = pthread_setspecific(dill_key, ctx);
    dill_assert(rc == 0);
    return ctx;
}
static int sf_send(int s, const void *buf, size_t len, int64_t deadline) {
    struct sf *conn = msockdata(s, sf_type);
    if(dill_slow(!conn)) return -1;
    if(dill_slow(conn->res != SF_ACTIVE)) {errno = ECONNRESET; return -1;}
    /* Create a message object. */
    struct msg msg;
    msg.buf = malloc(len);
    if(dill_slow(!msg.buf)) {errno = ENOMEM; return -1;}
    memcpy(msg.buf, buf, len);
    msg.len = len;
    /* Send it to the worker. */
    int rc = chsend(conn->ochan, &msg, sizeof(msg), deadline);
    if(dill_fast(rc >= 0)) return 0;
    /* Closed pipe means that the connection was terminated. */
    if(errno == EPIPE) {
        dill_assert(conn->ores == SF_RESET);
        conn->res = SF_RESET;
        errno = ECONNRESET;
    }
    /* Clean up. */
    int err = errno;
    free(msg.buf);
    errno = err;
    return -1;
}
int tcppeer(int s, ipaddr *addr) {
    struct tcpconn *conn = bsockdata(s, tcpconn_type);
    if(dill_slow(!conn)) return -1;
    if(dill_fast(addr))
        *addr = conn->addr;
    return 0;
}
示例#8
0
/* Get memory page size. The query is done once only. The value is cached. */
static size_t dill_page_size(void) {
    static long pgsz = 0;
    if(dill_fast(pgsz))
        return (size_t)pgsz;
    pgsz = sysconf(_SC_PAGE_SIZE);
    dill_assert(pgsz > 0);
    return (size_t)pgsz;
}
示例#9
0
文件: prefix.c 项目: jimjag/libdill
static void dill_prefix_hclose(struct dill_hvfs *hvfs) {
    struct dill_prefix_sock *self = (struct dill_prefix_sock*)hvfs;
    if(dill_fast(self->u >= 0)) {
        int rc = dill_hclose(self->u);
        dill_assert(rc == 0);
    }
    if(!self->mem) free(self);
}
示例#10
0
文件: tls.c 项目: jimjag/libdill
static void dill_tls_hclose(struct dill_hvfs *hvfs) {
    struct dill_tls_sock *self = (struct dill_tls_sock*)hvfs;
    SSL_free(self->ssl);
    SSL_CTX_free(self->ctx);
    if(dill_fast(self->u >= 0)) {
        int rc = dill_hclose(self->u);
        dill_assert(rc == 0);
    }
    if(!self->mem) free(self);
}
示例#11
0
文件: tcp.c 项目: jimjag/libdill
static int dill_tcp_bsendl(struct dill_bsock_vfs *bvfs,
      struct dill_iolist *first, struct dill_iolist *last, int64_t deadline) {
    struct dill_tcp_conn *self = dill_cont(bvfs, struct dill_tcp_conn, bvfs);
    if(dill_slow(self->sbusy)) {errno = EBUSY; return -1;}
    if(dill_slow(self->outdone)) {errno = EPIPE; return -1;}
    if(dill_slow(self->outerr)) {errno = ECONNRESET; return -1;}
    self->sbusy = 1;
    ssize_t sz = dill_fd_send(self->fd, first, last, deadline);
    self->sbusy = 0;
    if(dill_fast(sz >= 0)) return sz;
    self->outerr = 1;
    return -1;
}
示例#12
0
文件: tcp.c 项目: jimjag/libdill
static int dill_tcp_brecvl(struct dill_bsock_vfs *bvfs,
      struct dill_iolist *first, struct dill_iolist *last, int64_t deadline) {
    struct dill_tcp_conn *self = dill_cont(bvfs, struct dill_tcp_conn, bvfs);
    if(dill_slow(self->rbusy)) {errno = EBUSY; return -1;}
    if(dill_slow(self->indone)) {errno = EPIPE; return -1;}
    if(dill_slow(self->inerr)) {errno = ECONNRESET; return -1;}
    self->rbusy = 1;
    int rc = dill_fd_recv(self->fd, &self->rxbuf, first, last, deadline);
    self->rbusy = 0;
    if(dill_fast(rc == 0)) return 0;
    if(errno == EPIPE) self->indone = 1;
    else self->inerr = 1;
    return -1;
}
示例#13
0
文件: ctx.c 项目: jimjag/libdill
struct dill_ctx *dill_getctx_(void) {
    int rc = pthread_once(&dill_keyonce, dill_makekey);
    dill_assert(rc == 0);
    struct dill_ctx *ctx = pthread_getspecific(dill_key);
    if(dill_fast(ctx)) return ctx;
    ctx = calloc(1, sizeof(struct dill_ctx));
    dill_assert(ctx);
    dill_ctx_init_(ctx);
    if(dill_ismain()) {
        dill_main = ctx;
        rc = atexit(dill_ctx_atexit);
        dill_assert(rc == 0);
    }
    rc = pthread_setspecific(dill_key, ctx);
    dill_assert(rc == 0);
    return ctx;
}
int dsaccept(int s, struct sockaddr *addr, socklen_t *addrlen,
      int64_t deadline) {
    int as;
    while(1) {
        /* Try to accept new connection synchronously. */
        as = accept(s, addr, addrlen);
        if(dill_fast(as >= 0))
            break;
        if(dill_slow(errno != EAGAIN && errno != EWOULDBLOCK)) return -1;
        /* Operation is in progress. Wait till new connection is available. */
        int rc = fdin(s, deadline);
        if(dill_slow(rc < 0)) return -1;
    }
    int rc = dsunblock(as);
    dill_assert(rc == 0);
    return as;
}
static int tcpconn_flush(int s, int64_t deadline) {
    struct tcpconn *conn = bsockdata(s, tcpconn_type);
    if(dill_slow(!conn)) return -1;
    /* Try to send the buffered data. */
    if(conn->olen == 0) return 0;
    size_t sent = conn->olen;
    int rc = dssend(conn->fd, conn->obuf, &sent, deadline);
    if(dill_fast(rc == 0)) {
        conn->olen = 0;
        return 0;
    }
    /* Drop sent data from the buffer. */
    int err = errno;
    memmove(conn->obuf, conn->obuf + sent, conn->olen - sent);
    conn->olen -= sent;
    errno = err;
    return -1;
}
示例#16
0
文件: cr.c 项目: jimjag/libdill
static void *dill_cr_query(struct dill_hvfs *vfs, const void *type) {
    struct dill_cr *cr = dill_cont(vfs, struct dill_cr, vfs);
    if(dill_fast(type == dill_cr_type)) return cr;
    errno = ENOTSUP;
    return NULL;
}
示例#17
0
文件: cr.c 项目: jimjag/libdill
static void *dill_bundle_query(struct dill_hvfs *vfs, const void *type) {
    if(dill_fast(type == dill_bundle_type)) return vfs;
    errno = ENOTSUP;
    return NULL;
}