static void tcplistener_close(int s) {
    struct tcplistener *lst = hdata(s, tcplistener_type);
    dill_assert(lst);
    int rc = dsclose(lst->fd);
    dill_assert(rc == 0);
    free(lst);
}
Example #2
0
File: tls.c Project: jimjag/libdill
/* Do the follow up work after calling a SSL function.
   Returns 0 if the SSL function has to be restarted, 1 is we are done.
   In the latter case, error code is in errno.
   In the case of success errno is set to zero. */
static int dill_tls_followup(struct dill_tls_sock *self, int rc) {
    int err;
    char errstr[120];
    int code = SSL_get_error(self->ssl, rc);
    switch(code) {
	  case SSL_ERROR_NONE:
        /* Operation finished. */
        errno = 0;
        return 1;
	  case SSL_ERROR_ZERO_RETURN:
        /* Connection terminated by peer. */
        errno = EPIPE;
        return 1;
    case SSL_ERROR_SYSCALL:
        /* Error from our custom BIO. */
        dill_assert(rc == -1);
        if(errno == 0) return 0;
        return 1;
    case SSL_ERROR_SSL:        
        dill_tls_process_errors();
        return 1;
    case SSL_ERROR_WANT_READ:
    case SSL_ERROR_WANT_WRITE:
        /* These two should never happen -- our custom BIO is blocking. */
        dill_assert(0);
    default:
        /* Unexpected error. Let's at least print out current error queue
           for debugging purposes. */
        fprintf(stderr, "SSL error code: %d\n", code);
        dill_tls_process_errors();
        dill_assert(0);
    }
}
Example #3
0
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;
}
Example #4
0
File: ctx.c Project: jimjag/libdill
struct dill_ctx *dill_ctx_init(void) {
    dill_ctx_init_(&dill_ctx_);
    int rc = pthread_once(&dill_keyonce, dill_makekey);
    dill_assert(rc == 0);
    if(dill_ismain()) {
        dill_main = &dill_ctx_;
        rc = atexit(dill_ctx_atexit);
        dill_assert(rc == 0);
    }
    rc = pthread_setspecific(dill_key, &dill_ctx_);
    dill_assert(rc == 0);
    return &dill_ctx_;
}
static void dill_proc_close(int h) {
    struct dill_proc *proc = hdata(h, dill_proc_type);
    dill_assert(proc);
    /* This may happen if forking failed. */
    if(dill_slow(proc->pid < 0)) {free(proc); return;}
    /* There is a child running. Let's send it a kill signal. */
    int rc = close(proc->closepipe);
    dill_assert(rc == 0);
    /* Wait till it finishes. */
    /* TODO: For how long can this block? */
    rc = waitpid(proc->pid, NULL, 0);
    dill_assert(rc >= 0);
    free(proc);
}
Example #6
0
struct dill_ctx *dill_ctx_init(void) {
    int rc = dill_ctx_cr_init(&dill_ctx_.cr);
    dill_assert(rc == 0);
    rc = dill_ctx_handle_init(&dill_ctx_.handle);
    dill_assert(rc == 0);
    rc = dill_ctx_stack_init(&dill_ctx_.stack);
    dill_assert(rc == 0);
    rc = dill_ctx_pollset_init(&dill_ctx_.pollset);
    dill_assert(rc == 0);
    rc = atexit(dill_ctx_atexit);
    dill_assert(rc == 0);
    dill_ctx_.initialized = 1;
    return &dill_ctx_;
}
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;
}
int tcpconnect(const ipaddr *addr, int64_t deadline) {
    int err;
    /* Open a socket. */
    int s = socket(ipfamily(addr), SOCK_STREAM, 0);
    if(dill_slow(s < 0)) return -1;
    tcptune(s);
    /* Connect to the remote endpoint. */
    int rc = dsconnect(s, ipsockaddr(addr), iplen(addr), deadline);
    if(dill_slow(rc < 0)) return -1;
    /* Create the object. */
    struct tcpconn *conn = tcpconn_create();
    if(dill_slow(!conn)) {err = errno; goto error1;}
    conn->fd = s;
    conn->addr = *addr;
    /* Bind the object to a sock handle. */
    int bs = bsock(tcpconn_type, conn, &tcpconn_vfptrs);
    if(dill_slow(bs < 0)) {err = errno; goto error2;}
    return bs;
error2:
    tcpconn_destroy(conn);
error1:
    rc = dsclose(s);
    dill_assert(rc == 0);
    errno = err;
    return -1;
}
static void tcptune(int s) {
    /* Make the socket non-blocking. */
    int rc = dsunblock(s);
    dill_assert(rc == 0);
    /*  Allow re-using the same local address rapidly. */
    int opt = 1;
    rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt));
    dill_assert(rc == 0);
    /* If possible, prevent SIGPIPE signal when writing to the connection
        already closed by the peer. */
#ifdef SO_NOSIGPIPE
    opt = 1;
    rc = setsockopt (s, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof (opt));
    dill_assert (rc == 0 || errno == EINVAL);
#endif
}
Example #10
0
File: tcp.c Project: jimjag/libdill
int dill_tcp_close(int s, int64_t deadline) {
    int err;
    /* Listener socket needs no special treatment. */
    if(dill_hquery(s, dill_tcp_listener_type)) {
        return dill_hclose(s);
    }
    struct dill_tcp_conn *self = dill_hquery(s, dill_tcp_type);
    if(dill_slow(!self)) return -1;
    if(dill_slow(self->inerr || self->outerr)) {err = ECONNRESET; goto error;}
    /* If not done already, flush the outbound data and start the terminal
       handshake. */
    if(!self->outdone) {
        int rc = dill_tcp_done(s, deadline);
        if(dill_slow(rc < 0)) {err = errno; goto error;}
    }
    /* Now we are going to read all the inbound data until we reach end of the
       stream. That way we can be sure that the peer either received all our
       data or consciously closed the connection without reading all of it. */
    int rc = dill_tcp_brecvl(&self->bvfs, NULL, NULL, deadline);
    dill_assert(rc < 0);
    if(dill_slow(errno != EPIPE)) {err = errno; goto error;}
    dill_tcp_hclose(&self->hvfs);
    return 0;
error:
    dill_tcp_hclose(&self->hvfs);
    errno = err;
    return -1;
}
Example #11
0
int dill_term_detach(int s, int64_t deadline) {
    int err;
    struct dill_term_sock *self = dill_hquery(s, dill_term_type);
    if(dill_slow(!self)) return -1;
    if(!self->outdone) {
        int rc = dill_term_done(s, deadline);
        if(dill_slow(rc < 0)) {err = errno; goto error;}
    }
    if(!self->indone) {
        while(1) {
            struct dill_iolist iol = {NULL, SIZE_MAX, NULL, 0};
            ssize_t sz = dill_term_mrecvl(&self->mvfs, &iol, &iol, deadline);
            if(sz < 0) {
                if(errno == EPIPE) break;
                err = errno;
                goto error;
            }
        }
    }
    int u = self->u;
    if(!self->mem) free(self);
    return u;
error:;
    int rc = dill_hclose(s);
    dill_assert(rc == 0);
    errno = err;
    return -1;
}
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 tcpaccept(int s, int64_t deadline) {
    int err;
    struct tcplistener *lst = hdata(s, tcplistener_type);
    if(dill_slow(!lst)) return -1;
    /* Try to get new connection in a non-blocking way. */
    ipaddr addr;
    socklen_t addrlen;
    int as = dsaccept(lst->fd, (struct sockaddr*)&addr, &addrlen, deadline);
    if(dill_slow(as < 0)) return -1;
    tcptune(as);
    /* Create the object. */
    struct tcpconn *conn = tcpconn_create();
    if(dill_slow(!conn)) {err = errno; goto error1;}
    conn->fd = as;
    conn->addr = addr;
    /* Bind the object to a handle. */
    int hndl = bsock(tcpconn_type, conn, &tcpconn_vfptrs);
    if(dill_slow(hndl < 0)) {err = errno; goto error2;}
    return hndl;
error2:
    tcpconn_destroy(conn);
error1:;
    int rc = dsclose(s);
    dill_assert(rc == 0);
    errno = err;
    return -1;
}
Example #14
0
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);
}
Example #15
0
File: cr.c Project: jimjag/libdill
/* Gets called when coroutine handle is closed. */
static void dill_cr_close(struct dill_hvfs *vfs) {
    struct dill_ctx_cr *ctx = &dill_getctx->cr;
    struct dill_cr *cr = dill_cont(vfs, struct dill_cr, vfs);
    /* If the coroutine has already finished, we are done. */
    if(!cr->done) {
        /* No blocking calls from this point on. */
        cr->no_blocking1 = 1;
        /* Resume the coroutine if it was blocked. */
        if(!cr->ready.next)
            dill_cancel(cr, ECANCELED);
        /* Wait for the coroutine to stop executing. With no clauses added,
           the only mechanism to resume is through dill_cancel(). This is not
           really a blocking call, although it looks like one. Given that the
           coroutine that is being shut down is not permitted to block, we
           should get control back pretty quickly. */
        cr->closer = ctx->r;
        int rc = dill_wait();
        /* This assertion triggers when coroutine tries to close a bundle that
           it is part of. There's no sane way to handle that so let's just
           crash the process. */
        dill_assert(!(rc == -1 && errno == ECANCELED));
        dill_assert(rc == -1 && errno == 0);
    }
#if defined DILL_CENSUS
    /* Find the first overwritten byte on the stack.
       Determine stack usage based on that. */
    uint8_t *bottom = ((uint8_t*)cr) - cr->stacksz;
    int i;
    for(i = 0; i != cr->stacksz; ++i) {
        if(bottom[i] != 0xa0 + (i % 13)) {
            /* dill_cr is located on the stack so we have to take that into
               account. Also, it may be necessary to align the top of the stack
               to a 16-byte boundary, so add 16 bytes to account for that. */
            size_t used = cr->stacksz - i - sizeof(struct dill_cr) + 16;
            if(used > cr->census->max_stack)
                cr->census->max_stack = used;
            break;
        }
    }
#endif
#if defined DILL_VALGRIND
    VALGRIND_STACK_DEREGISTER(cr->sid);
#endif
    /* Now that the coroutine is finished, deallocate it. */
    if(!cr->mem) dill_freestack(cr + 1);
}
Example #16
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;
}
Example #17
0
File: ctx.c Project: 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 sfdetach(int s, int64_t deadline) {
    int err = 0;
    struct sf *conn = msockdata(s, sf_type);
    if(dill_slow(!conn)) return -1;
    /* If connection is broken don't even try to do termination handshake. */
    if(conn->res == SF_RESET) {err = ECONNRESET; goto dealloc;}
    /* Ask oworker to exit. */
    struct msg msg = {NULL, 0};
    int rc = chsend(conn->ochan, &msg, sizeof(msg), deadline);
    if(dill_slow(rc < 0 && errno == EPIPE)) {err = ECONNRESET; goto dealloc;}
    if(dill_slow(rc < 0)) {err = errno; goto dealloc;}
    /* Given that there's no way for oworker to receive this message,
       the function only exits when it closes the channel. */
    rc = chsend(conn->ochan, &msg, sizeof(msg), deadline);
    dill_assert(rc < 0);
    if(dill_slow(errno != EPIPE)) {err = errno; goto dealloc;}
    if(dill_slow(conn->ores == SF_RESET)) {err = ECONNRESET; goto dealloc;}
    dill_assert(conn->ores == SF_DONE);
    /* Now that oworker have exited send the termination sequence. */
    rc = bsend(conn->u, &sf_termsequence, sizeof(sf_termsequence), -1);
    if(dill_slow(rc < 0)) {err = errno; goto dealloc;}
    rc = bflush(conn->u, deadline);
    if(dill_slow(rc < 0)) {err = errno; goto dealloc;} 
    /* Read and drop any pending inbound messages. By doing this we'll ensure
       that reading on the underlying socket will continue from the first byte
       following the sf termination sequence. */
    if(conn->res == SF_ACTIVE) {
        while(1) {
            struct msg msg;
            rc = chrecv(conn->ichan, &msg, sizeof(msg), deadline);
            if(rc < 0) break;
            free(msg.buf);
        }
        if(dill_slow(errno != EPIPE)) {err = errno; goto dealloc;}
        if(dill_slow(conn->ires == SF_RESET)) {err = ECONNRESET; goto dealloc;}
        dill_assert(conn->ires == SF_DONE);
    }
dealloc:
    /* Deallocate the object. */
    rc = hclose(conn->iworker);
    dill_assert(rc == 0);
    rc = hclose(conn->oworker);
    dill_assert(rc == 0);
    rc = hclose(conn->ichan);
    dill_assert(rc == 0);
    rc = hclose(conn->ochan);
    dill_assert(rc == 0);
    int u = conn->u;
    free(conn);
    if(err == 0) return u;
    rc = hclose(u);
    dill_assert(rc == 0);
    errno = err;
    return -1;
}
Example #19
0
File: tls.c Project: jimjag/libdill
static void dill_tls_init(void) {
    static int init = 0;
    if(dill_slow(!init)) {
        SSL_library_init();
        SSL_load_error_strings();
        /* Create our own custom BIO type. */
        int idx = BIO_get_new_index();
        dill_tls_cbio = BIO_meth_new(idx, "bsock");
        dill_assert(dill_tls_cbio);
        int rc = BIO_meth_set_create(dill_tls_cbio, dill_tls_cbio_create);
        dill_assert(rc == 1);
        rc = BIO_meth_set_destroy(dill_tls_cbio, dill_tls_cbio_destroy);
        dill_assert(rc == 1);
        rc = BIO_meth_set_write(dill_tls_cbio, dill_tls_cbio_write);
        dill_assert(rc == 1);
        rc = BIO_meth_set_read(dill_tls_cbio, dill_tls_cbio_read);
        dill_assert(rc == 1);
        rc = BIO_meth_set_ctrl(dill_tls_cbio, dill_tls_cbio_ctrl);
        dill_assert(rc == 1);
        /* Deallocate the method once the process exits. */
        rc = atexit(dill_tls_term);
        dill_assert(rc == 0);
        init = 1;
    }
}
int sfattach(int s) {
    int err;
    int rc;
    /* This will ensure that s is actually a bytestream. */
    rc = bflush(s, -1);
    if(dill_slow(rc < 0)) return -1;
    /* Create a sf socket. */
    struct sf *conn = malloc(sizeof(struct sf));
    if(dill_slow(!conn)) {err = ENOMEM; goto error1;}
    conn->u = s;
    conn->ochan = channel(sizeof(struct msg), 0);
    if(dill_slow(conn->ochan < 0)) {err = errno; goto error2;}
    conn->ores = SF_ACTIVE;
    conn->ichan = channel(sizeof(struct msg), 0);
    if(dill_slow(conn->ichan < 0)) {err = errno; goto error3;}
    conn->ires = SF_ACTIVE;
    conn->oworker = go(sf_oworker(conn));
    if(dill_slow(conn->oworker < 0)) {err = errno; goto error4;}
    conn->iworker = go(sf_iworker(conn));
    if(dill_slow(conn->iworker < 0)) {err = errno; goto error5;}
    conn->res = SF_ACTIVE;
    /* Bind the object to a handle. */
    int h = msock(sf_type, conn, &sf_vfptrs);
    if(dill_slow(h < 0)) {err = errno; goto error6;}
    return h;
error6:
    rc = hclose(conn->iworker);
    dill_assert(rc == 0);
error5:
    rc = hclose(conn->oworker);
    dill_assert(rc == 0);
error4:
    rc = hclose(conn->ichan);
    dill_assert(rc == 0);
error3:
    rc = hclose(conn->ochan);
    dill_assert(rc == 0);
error2:
    free(conn);
error1:
    errno = err;
    return -1;
}
Example #21
0
File: tls.c Project: 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);
}
Example #22
0
File: ctx.c Project: jimjag/libdill
static void dill_ctx_term_(struct dill_ctx *ctx) {
    dill_assert(ctx->initialized == 1);
    dill_ctx_fd_term(&ctx->fd);
    dill_ctx_pollset_term(&ctx->pollset);
    dill_ctx_stack_term(&ctx->stack);
    dill_ctx_handle_term(&ctx->handle);
    dill_ctx_cr_term(&ctx->cr);
    dill_ctx_now_term(&ctx->now);
    ctx->initialized = 0;
}
Example #23
0
File: tls.c Project: jimjag/libdill
static long dill_tls_cbio_ctrl(BIO *bio, int cmd, long larg, void *parg) {
    switch(cmd) {
    case BIO_CTRL_FLUSH:
        return 1;
    case BIO_CTRL_PUSH:
    case BIO_CTRL_POP:
        return 0;
    default:
        dill_assert(0);
    }
}
static coroutine void sf_iworker(struct sf *conn) {
    struct msg msg = {NULL, 0};
    while(1) {
        uint64_t hdr;
        int rc = brecv(conn->u, &hdr, sizeof(hdr), -1);
        CHECKRC(ires)
        if(dill_slow(hdr == sf_termsequence)) {conn->ires = SF_DONE; break;}
        msg.len = (size_t)dill_getll((uint8_t*)&hdr);
        msg.buf = malloc(msg.len);
        dill_assert(msg.buf);
        rc = brecv(conn->u, msg.buf, msg.len, -1);
        CHECKRC(ires)
        rc = chsend(conn->ichan, &msg, sizeof(msg), -1);
        if(dill_slow(rc < 0 && errno == ECANCELED)) break;
        dill_assert(rc == 0);
        msg.buf = NULL;
        msg.len = 0;
    }
    free(msg.buf);
    int rc = chdone(conn->ichan);
    dill_assert(rc == 0);
}
Example #25
0
File: tcp.c Project: jimjag/libdill
int dill_tcp_done(int s, int64_t deadline) {
    struct dill_tcp_conn *self = dill_hquery(s, dill_tcp_type);
    if(dill_slow(!self)) return -1;
    if(dill_slow(self->outdone)) {errno = EPIPE; return -1;}
    if(dill_slow(self->outerr)) {errno = ECONNRESET; return -1;}
    /* Flushing the tx buffer is done asynchronously on kernel level. */
    int rc = shutdown(self->fd, SHUT_WR);
    if(dill_slow(rc < 0)) {
        if(errno == ENOTCONN) {self->outerr = 1; errno = ECONNRESET; return -1;}
        if(errno == ENOBUFS) {self->outerr = 1; errno = ENOMEM; return -1;}
        dill_assert(rc == 0);
    }
    self->outdone = 1;
    return 0;
}
static coroutine void sf_oworker(struct sf *conn) {
    struct msg msg = {NULL, 0};
    while(1) {
        int rc = chrecv(conn->ochan, &msg, sizeof(msg), -1);
        if(dill_slow(rc < 0 && errno == ECANCELED)) break;
        dill_assert(rc == 0);
        /* User requests that the coroutine stops. */
        if(!msg.buf) {conn->ores = SF_DONE; break;}
        uint64_t hdr;
        dill_putll((uint8_t*)&hdr, msg.len);
        rc = bsend(conn->u, &hdr, sizeof(hdr), -1);
        CHECKRC(ores)
        rc = bsend(conn->u, msg.buf, msg.len, -1);
        CHECKRC(ores)
        free(msg.buf);
        msg.buf = NULL;
        msg.len = 0;
        rc = bflush(conn->u, -1);
        CHECKRC(ores)
    }
    free(msg.buf);
    int rc = chdone(conn->ochan);
    dill_assert(rc == 0);
}
Example #27
0
void dill_ctx_stack_term(struct dill_ctx_stack *ctx) {
    /* Deallocate leftover coroutines. */
    struct dill_qlist *it;
    while((it = dill_qlist_pop(&ctx->cache)) != &ctx->cache) {
#if (HAVE_POSIX_MEMALIGN && HAVE_MPROTECT) & !defined DILL_NOGUARD
        void *ptr = ((uint8_t*)(it + 1)) - dill_stack_size - dill_page_size();
        int rc = mprotect(ptr, dill_page_size(), PROT_READ|PROT_WRITE);
        dill_assert(rc == 0);
        free(ptr);
#else
        void *ptr = ((uint8_t*)(it + 1)) - dill_stack_size;
        free(ptr);
#endif
    }
}
Example #28
0
int dill_msleep(int64_t deadline, const char *where) {
    /* Return ECANCELED if shutting down. */
    int rc = dill_canblock();
    if(dill_slow(rc < 0)) return -1;
    /* Trivial case. No waiting, but we do want a context switch. */
    if(dill_slow(deadline == 0)) return yield();
    /* Actual waiting. */
    struct dill_tmcl tmcl;
    if(deadline > 0)
        dill_timer(&tmcl, 1, deadline);
    int id = dill_wait(where);
    if(dill_slow(id < 0)) return -1;
    dill_assert(id == 1);
    return 0;
}
Example #29
0
File: tls.c Project: jimjag/libdill
int dill_tls_done(int s, int64_t deadline) {
    struct dill_tls_sock *self = dill_hquery(s, dill_tls_type);
    if(dill_slow(!self)) return -1;
    if(dill_slow(self->outerr)) {errno = ECONNRESET; return -1;}
    if(dill_slow(self->outdone)) {errno = EPIPE; return -1;}
    while(1) {
        ERR_clear_error();
        int rc = SSL_shutdown(self->ssl);
        if(rc == 0) {self->outdone = 1; return 0;}
        if(rc == 1) {self->outdone = 1; self->indone = 1; return 0;}
        if(dill_tls_followup(self, rc)) break;
    }
    dill_assert(errno != 0);
    self->outerr = 1;
    return -1;
}
Example #30
0
void dill_timer_add(struct dill_timer *timer, int64_t deadline) {
    dill_assert(deadline >= 0);
    timer->expiry = deadline;
    /* Move the timer into the right place in the ordered list
       of existing timers. TODO: This is an O(n) operation! */
    struct dill_list_item *it = dill_list_begin(&dill_timers);
    while(it) {
        struct dill_timer *tm = dill_cont(it, struct dill_timer, item);
        /* If multiple timers expire at the same momemt they will be fired
           in the order they were created in (> rather than >=). */
        if(tm->expiry > timer->expiry)
            break;
        it = dill_list_next(it);
    }
    dill_list_insert(&dill_timers, &timer->item, it);
}