2017-03-21 12:41:01 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* machinarium.
|
|
|
|
*
|
|
|
|
* cooperative multitasking engine.
|
|
|
|
*/
|
|
|
|
|
2017-03-21 12:55:23 +00:00
|
|
|
#include <machinarium.h>
|
2017-05-17 14:20:04 +00:00
|
|
|
#include <machinarium_private.h>
|
2017-03-21 12:41:01 +00:00
|
|
|
|
2017-04-19 13:38:00 +00:00
|
|
|
static void
|
2017-04-18 12:02:28 +00:00
|
|
|
mm_readahead_cb(mm_fd_t *handle)
|
|
|
|
{
|
|
|
|
mm_io_t *io = handle->on_read_arg;
|
2017-04-20 11:56:47 +00:00
|
|
|
mm_call_t *call = &io->read;
|
2017-04-20 12:12:41 +00:00
|
|
|
if (mm_call_is_aborted(call))
|
|
|
|
return;
|
2017-04-18 12:02:28 +00:00
|
|
|
|
|
|
|
int left = io->readahead_size - io->readahead_pos;
|
|
|
|
int rc;
|
|
|
|
while (left > 0)
|
|
|
|
{
|
|
|
|
rc = mm_socket_read(io->fd, io->readahead_buf.start + io->readahead_pos, left);
|
|
|
|
if (rc == -1) {
|
|
|
|
if (errno == EAGAIN ||
|
|
|
|
errno == EWOULDBLOCK)
|
|
|
|
break;
|
|
|
|
if (errno == EINTR)
|
|
|
|
continue;
|
2017-04-20 12:12:41 +00:00
|
|
|
io->readahead_status = errno;
|
2017-05-30 10:56:41 +00:00
|
|
|
io->connected = 0;
|
2017-04-21 11:52:16 +00:00
|
|
|
|
|
|
|
if (mm_call_is_active(call)) {
|
|
|
|
call->status = errno;
|
2017-05-24 10:11:03 +00:00
|
|
|
if (call->coroutine)
|
|
|
|
mm_scheduler_wakeup(&mm_self->scheduler, call->coroutine);
|
2017-04-21 11:52:16 +00:00
|
|
|
}
|
2017-04-19 13:38:00 +00:00
|
|
|
return;
|
2017-04-18 12:02:28 +00:00
|
|
|
}
|
|
|
|
io->readahead_pos += rc;
|
|
|
|
left = io->readahead_size - io->readahead_pos;
|
|
|
|
assert(left >= 0);
|
|
|
|
if (rc == 0) {
|
|
|
|
/* eof */
|
|
|
|
mm_readahead_stop(io);
|
2017-05-30 10:56:41 +00:00
|
|
|
io->connected = 0;
|
2017-04-18 12:02:28 +00:00
|
|
|
io->read_eof = 1;
|
2017-04-20 12:12:41 +00:00
|
|
|
io->readahead_status = 0;
|
2017-04-21 11:52:16 +00:00
|
|
|
if (mm_call_is_active(call))
|
|
|
|
call->status = 0;
|
2017-04-18 12:02:28 +00:00
|
|
|
break;
|
|
|
|
}
|
2017-04-18 13:05:17 +00:00
|
|
|
break;
|
2017-04-18 12:02:28 +00:00
|
|
|
}
|
2017-04-20 12:12:41 +00:00
|
|
|
io->readahead_status = 0;
|
2017-04-21 11:52:16 +00:00
|
|
|
|
|
|
|
if (mm_call_is_active(call)) {
|
|
|
|
call->status = 0;
|
2017-04-18 12:02:28 +00:00
|
|
|
int ra_left = io->readahead_pos - io->readahead_pos_read;
|
|
|
|
if (io->read_eof || ra_left >= io->read_size)
|
2017-05-24 10:11:03 +00:00
|
|
|
mm_scheduler_wakeup(&mm_self->scheduler, call->coroutine);
|
2017-04-18 12:02:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-18 10:43:43 +00:00
|
|
|
int mm_readahead_start(mm_io_t *io)
|
2017-04-18 12:02:28 +00:00
|
|
|
{
|
2017-05-18 10:31:25 +00:00
|
|
|
mm_machine_t *machine = mm_self;
|
2017-04-18 12:02:28 +00:00
|
|
|
int rc;
|
2017-05-30 12:34:00 +00:00
|
|
|
rc = mm_loop_read(&machine->loop, &io->handle, mm_readahead_cb, io);
|
2017-04-18 12:02:28 +00:00
|
|
|
if (rc == -1) {
|
2017-05-30 14:00:16 +00:00
|
|
|
mm_errno_set(errno);
|
2017-04-18 12:02:28 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-05-18 10:43:43 +00:00
|
|
|
int mm_readahead_stop(mm_io_t *io)
|
2017-04-18 12:02:28 +00:00
|
|
|
{
|
2017-05-18 10:31:25 +00:00
|
|
|
mm_machine_t *machine = mm_self;
|
2017-04-18 12:02:28 +00:00
|
|
|
int rc;
|
2017-05-30 12:34:00 +00:00
|
|
|
rc = mm_loop_read_stop(&machine->loop, &io->handle);
|
2017-04-18 12:02:28 +00:00
|
|
|
if (rc == -1) {
|
2017-05-30 14:00:16 +00:00
|
|
|
mm_errno_set(errno);
|
2017-04-18 12:02:28 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2017-05-24 13:01:55 +00:00
|
|
|
mm_readahead_read(mm_io_t *io, uint32_t time_ms)
|
2017-04-18 12:02:28 +00:00
|
|
|
{
|
|
|
|
if (io->read_size > io->readahead_size) {
|
2017-05-30 14:00:16 +00:00
|
|
|
mm_errno_set(EINVAL);
|
2017-04-18 12:02:28 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* try to use readahead first */
|
|
|
|
assert(io->readahead_pos >= io->readahead_pos_read);
|
|
|
|
int ra_left = io->readahead_pos - io->readahead_pos_read;
|
|
|
|
if (ra_left >= io->read_size) {
|
|
|
|
memcpy(io->read_buf, io->readahead_buf.start + io->readahead_pos_read,
|
|
|
|
io->read_size);
|
|
|
|
io->readahead_pos_read += io->read_size;
|
|
|
|
return 0;
|
|
|
|
}
|
2017-04-20 12:12:41 +00:00
|
|
|
if (io->readahead_status != 0) {
|
2017-05-30 14:00:16 +00:00
|
|
|
mm_errno_set(io->readahead_status);
|
2017-04-18 12:02:28 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2017-05-30 10:56:41 +00:00
|
|
|
if (io->read_eof || !io->connected) {
|
2017-05-30 14:00:16 +00:00
|
|
|
mm_errno_set(ECONNRESET);
|
2017-04-18 12:02:28 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-04-18 13:05:17 +00:00
|
|
|
/* copy readahead chunk */
|
2017-04-18 12:02:28 +00:00
|
|
|
int copy_pos = 0;
|
|
|
|
if (ra_left > 0) {
|
|
|
|
memcpy(io->read_buf,
|
|
|
|
io->readahead_buf.start + io->readahead_pos_read,
|
|
|
|
ra_left);
|
|
|
|
io->readahead_pos_read += ra_left;
|
|
|
|
io->read_size -= ra_left;
|
|
|
|
copy_pos = ra_left;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reset readahead position */
|
|
|
|
assert(io->readahead_pos_read == io->readahead_pos);
|
|
|
|
io->readahead_pos = 0;
|
|
|
|
io->readahead_pos_read = 0;
|
2017-05-30 14:51:15 +00:00
|
|
|
mm_buf_reset(&io->readahead_buf);
|
|
|
|
|
|
|
|
/* maybe allocate readahead buffer and-or start io */
|
|
|
|
int rc;
|
|
|
|
rc = mm_buf_ensure(&io->readahead_buf, io->readahead_size);
|
|
|
|
if (rc == -1) {
|
|
|
|
mm_errno_set(ENOMEM);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
rc = mm_readahead_start(io);
|
|
|
|
if (rc == -1)
|
|
|
|
return -1;
|
2017-04-18 12:02:28 +00:00
|
|
|
|
2017-04-20 11:56:47 +00:00
|
|
|
/* wait for completion */
|
2017-05-18 10:43:43 +00:00
|
|
|
mm_call(&io->read, time_ms);
|
2017-04-18 12:02:28 +00:00
|
|
|
|
2017-04-20 11:56:47 +00:00
|
|
|
rc = io->read.status;
|
2017-04-20 12:12:41 +00:00
|
|
|
if (rc == 0)
|
|
|
|
rc = io->readahead_status;
|
2017-04-20 11:56:47 +00:00
|
|
|
if (rc != 0) {
|
2017-05-30 14:00:16 +00:00
|
|
|
mm_errno_set(rc);
|
2017-04-20 11:56:47 +00:00
|
|
|
return -1;
|
2017-03-21 12:41:01 +00:00
|
|
|
}
|
2017-04-20 11:56:47 +00:00
|
|
|
ra_left = io->readahead_pos - io->readahead_pos_read;
|
|
|
|
if (ra_left < io->read_size) {
|
2017-05-30 14:00:16 +00:00
|
|
|
mm_errno_set(ECONNRESET);
|
2017-04-20 11:56:47 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(io->read_buf + copy_pos,
|
|
|
|
io->readahead_buf.start + io->readahead_pos_read,
|
|
|
|
io->read_size);
|
|
|
|
io->readahead_pos_read += io->read_size;
|
|
|
|
return 0;
|
2017-03-21 12:41:01 +00:00
|
|
|
}
|
|
|
|
|
2017-05-24 13:01:55 +00:00
|
|
|
int mm_read(mm_io_t *io, char *buf, int size, uint32_t time_ms)
|
2017-04-18 12:02:28 +00:00
|
|
|
{
|
2017-05-30 14:00:16 +00:00
|
|
|
mm_errno_set(0);
|
2017-04-20 11:56:47 +00:00
|
|
|
if (mm_call_is_active(&io->read)) {
|
2017-05-30 14:00:16 +00:00
|
|
|
mm_errno_set(EINPROGRESS);
|
2017-04-18 12:02:28 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2017-05-26 10:48:52 +00:00
|
|
|
if (! io->attached) {
|
2017-05-30 14:00:16 +00:00
|
|
|
mm_errno_set(ENOTCONN);
|
2017-05-26 10:48:52 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2017-04-20 11:56:47 +00:00
|
|
|
io->read_buf = buf;
|
|
|
|
io->read_size = size;
|
|
|
|
io->read_pos = 0;
|
2017-05-30 14:51:15 +00:00
|
|
|
return mm_readahead_read(io, time_ms);
|
2017-04-18 12:02:28 +00:00
|
|
|
}
|
|
|
|
|
2017-03-28 10:31:14 +00:00
|
|
|
MACHINE_API int
|
2017-05-24 13:01:55 +00:00
|
|
|
machine_read(machine_io_t obj, char *buf, int size, uint32_t time_ms)
|
2017-03-28 10:31:14 +00:00
|
|
|
{
|
|
|
|
mm_io_t *io = obj;
|
2017-03-28 11:51:57 +00:00
|
|
|
if (mm_tls_is_active(&io->tls))
|
|
|
|
return mm_tlsio_read(&io->tls, buf, size);
|
2017-03-28 10:31:14 +00:00
|
|
|
return mm_read(io, buf, size, time_ms);
|
|
|
|
}
|
|
|
|
|
2017-04-18 12:02:28 +00:00
|
|
|
MACHINE_API int
|
|
|
|
machine_set_readahead(machine_io_t obj, int size)
|
|
|
|
{
|
|
|
|
mm_io_t *io = obj;
|
2017-05-30 14:00:16 +00:00
|
|
|
mm_errno_set(0);
|
2017-04-18 12:02:28 +00:00
|
|
|
int rc;
|
|
|
|
rc = mm_buf_ensure(&io->readahead_buf, size);
|
|
|
|
if (rc == -1) {
|
2017-05-30 14:00:16 +00:00
|
|
|
mm_errno_set(ENOMEM);
|
2017-04-18 12:02:28 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
io->readahead_size = size;
|
|
|
|
return 0;
|
|
|
|
}
|