static apr_status_t writev_nonblocking(apr_socket_t *s,
                                       apr_bucket_brigade *bb,
                                       core_output_filter_ctx_t *ctx,
                                       apr_size_t bytes_to_write,
                                       apr_size_t nvec,
                                       conn_rec *c)
{
    apr_status_t rv;
    struct iovec *vec = ctx->vec;
    apr_size_t bytes_written = 0;
    apr_size_t i, offset = 0;

    do {
        apr_size_t n = 0;
        rv = apr_socket_sendv(s, vec + offset, nvec - offset, &n);
        bytes_written += n;

        for (i = offset; i < nvec; ) {
            apr_bucket *bucket = APR_BRIGADE_FIRST(bb);
            if (!bucket->length) {
                apr_bucket_delete(bucket);
            }
            else if (n >= vec[i].iov_len) {
                apr_bucket_delete(bucket);
                n -= vec[i++].iov_len;
                offset++;
            }
            else {
                if (n) {
                    apr_bucket_split(bucket, n);
                    apr_bucket_delete(bucket);
                    vec[i].iov_len -= n;
                    vec[i].iov_base = (char *) vec[i].iov_base + n;
                }
                break;
            }
        }
    } while (rv == APR_SUCCESS && bytes_written < bytes_to_write);

    if ((ap__logio_add_bytes_out != NULL) && (bytes_written > 0)) {
        ap__logio_add_bytes_out(c, bytes_written);
    }
    ctx->bytes_written += bytes_written;

    ap_log_cerror(APLOG_MARK, APLOG_TRACE6, rv, c,
                  "writev_nonblocking: %"APR_SIZE_T_FMT"/%"APR_SIZE_T_FMT,
                  bytes_written, bytes_to_write);
    return rv;
}