2017-03-21 12:41:01 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* machinarium.
|
|
|
|
*
|
|
|
|
* cooperative multitasking engine.
|
|
|
|
*/
|
|
|
|
|
2017-03-21 12:55:23 +00:00
|
|
|
#include <machinarium_private.h>
|
|
|
|
#include <machinarium.h>
|
2017-03-21 12:41:01 +00:00
|
|
|
|
|
|
|
static void
|
2017-04-12 13:22:41 +00:00
|
|
|
mm_read_timer_cb(mm_timer_t *handle)
|
2017-03-21 12:41:01 +00:00
|
|
|
{
|
2017-04-12 13:22:41 +00:00
|
|
|
mm_io_t *io = handle->arg;
|
2017-03-21 12:41:01 +00:00
|
|
|
io->read_timedout = 1;
|
2017-04-12 13:22:41 +00:00
|
|
|
io->read_status = ETIMEDOUT;
|
2017-03-21 12:41:01 +00:00
|
|
|
mm_scheduler_wakeup(io->read_fiber);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
mm_read_cancel_cb(void *obj, void *arg)
|
|
|
|
{
|
|
|
|
(void)obj;
|
|
|
|
mm_io_t *io = arg;
|
|
|
|
io->read_timedout = 0;
|
2017-04-12 13:22:41 +00:00
|
|
|
io->read_status = ECANCELED;
|
2017-03-21 12:41:01 +00:00
|
|
|
mm_scheduler_wakeup(io->read_fiber);
|
|
|
|
}
|
|
|
|
|
2017-04-12 13:22:41 +00:00
|
|
|
static int
|
|
|
|
mm_read_cb(mm_fd_t *handle)
|
2017-03-21 12:41:01 +00:00
|
|
|
{
|
2017-04-12 13:22:41 +00:00
|
|
|
mm_io_t *io = handle->on_read_arg;
|
|
|
|
mm_t *machine = machine = io->machine;
|
2017-04-14 14:53:55 +00:00
|
|
|
int left = io->read_size - io->read_pos;
|
|
|
|
int rc;
|
|
|
|
while (left > 0)
|
2017-04-12 13:22:41 +00:00
|
|
|
{
|
2017-04-14 14:53:55 +00:00
|
|
|
rc = mm_socket_read(io->fd, io->read_buf + io->read_pos, left);
|
|
|
|
if (rc == -1) {
|
2017-04-12 13:22:41 +00:00
|
|
|
if (errno == EAGAIN ||
|
2017-04-14 14:53:55 +00:00
|
|
|
errno == EWOULDBLOCK)
|
2017-04-12 13:22:41 +00:00
|
|
|
return 0;
|
|
|
|
if (errno == EINTR)
|
|
|
|
continue;
|
|
|
|
io->read_status = errno;
|
2017-04-14 14:53:55 +00:00
|
|
|
mm_scheduler_wakeup(io->read_fiber);
|
|
|
|
return 0;
|
2017-03-21 12:41:01 +00:00
|
|
|
}
|
2017-04-14 14:53:55 +00:00
|
|
|
io->read_pos += rc;
|
|
|
|
left = io->read_size - io->read_pos;
|
|
|
|
assert(left >= 0);
|
|
|
|
if (rc == 0) {
|
|
|
|
/* eof */
|
|
|
|
io->read_eof = 1;
|
2017-04-12 13:22:41 +00:00
|
|
|
io->read_status = 0;
|
2017-04-14 14:53:55 +00:00
|
|
|
mm_scheduler_wakeup(io->read_fiber);
|
|
|
|
return 0;
|
2017-03-21 12:41:01 +00:00
|
|
|
}
|
|
|
|
}
|
2017-04-14 14:53:55 +00:00
|
|
|
io->read_status = 0;
|
|
|
|
mm_scheduler_wakeup(io->read_fiber);
|
2017-04-12 13:22:41 +00:00
|
|
|
return 0;
|
2017-03-21 12:41:01 +00:00
|
|
|
}
|
|
|
|
|
2017-03-28 10:31:14 +00:00
|
|
|
int
|
|
|
|
mm_read(mm_io_t *io, char *buf, int size, uint64_t time_ms)
|
2017-03-21 12:41:01 +00:00
|
|
|
{
|
2017-04-12 13:22:41 +00:00
|
|
|
mm_t *machine = machine = io->machine;
|
2017-03-21 12:41:01 +00:00
|
|
|
mm_fiber_t *current = mm_scheduler_current(&io->machine->scheduler);
|
2017-03-29 11:58:27 +00:00
|
|
|
mm_io_set_errno(io, 0);
|
|
|
|
if (mm_fiber_is_cancelled(current)) {
|
|
|
|
mm_io_set_errno(io, ECANCELED);
|
2017-03-21 12:41:01 +00:00
|
|
|
return -1;
|
2017-03-29 11:58:27 +00:00
|
|
|
}
|
|
|
|
if (io->read_fiber) {
|
|
|
|
mm_io_set_errno(io, EINPROGRESS);
|
|
|
|
return -1;
|
|
|
|
}
|
2017-04-14 14:53:55 +00:00
|
|
|
if (! io->connected) {
|
|
|
|
mm_io_set_errno(io, ENOTCONN);
|
2017-03-29 11:58:27 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2017-03-21 12:41:01 +00:00
|
|
|
io->read_status = 0;
|
|
|
|
io->read_timedout = 0;
|
2017-04-14 14:53:55 +00:00
|
|
|
io->read_eof = 0;
|
2017-03-21 12:41:01 +00:00
|
|
|
io->read_fiber = NULL;
|
2017-04-14 14:53:55 +00:00
|
|
|
io->read_size = size;
|
|
|
|
io->read_pos = 0;
|
|
|
|
io->read_buf = buf;
|
2017-03-21 12:41:01 +00:00
|
|
|
|
2017-04-14 14:53:55 +00:00
|
|
|
/* subscribe for read event */
|
2017-03-21 12:41:01 +00:00
|
|
|
int rc;
|
2017-04-12 13:22:41 +00:00
|
|
|
rc = mm_loop_read(&machine->loop, &io->handle, mm_read_cb, io, 1);
|
|
|
|
if (rc == -1) {
|
|
|
|
mm_io_set_errno(io, errno);
|
|
|
|
return -1;
|
2017-03-21 12:41:01 +00:00
|
|
|
}
|
2017-04-12 13:22:41 +00:00
|
|
|
|
|
|
|
/* wait for timedout, cancel or execution status */
|
|
|
|
mm_timer_start(&machine->loop.clock,
|
|
|
|
&io->read_timer,
|
|
|
|
mm_read_timer_cb, io, time_ms);
|
2017-03-21 12:41:01 +00:00
|
|
|
mm_call_begin(¤t->call, mm_read_cancel_cb, io);
|
2017-04-12 13:22:41 +00:00
|
|
|
io->read_fiber = current;
|
|
|
|
mm_scheduler_yield(&machine->scheduler);
|
|
|
|
io->read_fiber = NULL;
|
2017-03-21 12:41:01 +00:00
|
|
|
mm_call_end(¤t->call);
|
2017-04-12 13:22:41 +00:00
|
|
|
mm_timer_stop(&io->read_timer);
|
2017-03-21 12:41:01 +00:00
|
|
|
|
2017-04-14 14:53:55 +00:00
|
|
|
rc = mm_loop_read(&machine->loop, &io->handle, NULL, NULL, 0);
|
|
|
|
if (rc == -1) {
|
|
|
|
mm_io_set_errno(io, errno);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = io->read_status;
|
|
|
|
if (rc == 0) {
|
|
|
|
if (io->read_pos != size) {
|
|
|
|
mm_io_set_errno(io, ECONNRESET);
|
|
|
|
return -1;
|
2017-03-24 12:18:12 +00:00
|
|
|
}
|
2017-03-29 11:58:27 +00:00
|
|
|
return 0;
|
2017-03-21 12:41:01 +00:00
|
|
|
}
|
2017-04-12 13:22:41 +00:00
|
|
|
mm_io_set_errno(io, rc);
|
2017-03-29 11:58:27 +00:00
|
|
|
return -1;
|
2017-03-21 12:41:01 +00:00
|
|
|
}
|
|
|
|
|
2017-03-28 10:31:14 +00:00
|
|
|
MACHINE_API int
|
|
|
|
machine_read(machine_io_t obj, char *buf, int size, uint64_t time_ms)
|
|
|
|
{
|
|
|
|
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-03-21 12:41:01 +00:00
|
|
|
MACHINE_API int
|
|
|
|
machine_read_timedout(machine_io_t obj)
|
|
|
|
{
|
|
|
|
mm_io_t *io = obj;
|
|
|
|
return io->read_timedout;
|
|
|
|
}
|