factor/native/iomux.c

276 lines
4.9 KiB
C
Raw Normal View History

#include "factor.h"
2004-08-13 01:38:15 -04:00
void init_io_tasks(fd_set* fdset, IO_TASK* io_tasks)
{
int i;
FD_ZERO(fdset);
for(i = 0; i < FD_SETSIZE; i++)
{
2004-08-15 21:50:44 -04:00
io_tasks[i].port = F;
io_tasks[i].callback = F;
2004-08-13 01:38:15 -04:00
}
}
void init_iomux(void)
{
2004-08-13 01:38:15 -04:00
read_fd_count = 0;
init_io_tasks(&read_fd_set,read_io_tasks);
write_fd_count = 0;
init_io_tasks(&write_fd_set,write_io_tasks);
}
2004-08-15 21:50:44 -04:00
IO_TASK* add_io_task(
2004-08-13 02:19:22 -04:00
IO_TASK_TYPE type,
2004-08-13 01:38:15 -04:00
PORT* port,
CELL callback,
IO_TASK* io_tasks,
int* fd_count)
{
2004-08-13 18:43:03 -04:00
int fd = port->fd;
2004-08-13 01:38:15 -04:00
2004-08-15 21:50:44 -04:00
/* if(io_tasks[fd].port != F)
critical_error("Adding I/O task twice",fd); */
2004-08-13 18:43:03 -04:00
io_tasks[fd].type = type;
io_tasks[fd].port = tag_object(port);
io_tasks[fd].callback = callback;
2004-08-13 18:43:03 -04:00
if(fd >= *fd_count)
*fd_count = fd + 1;
2004-08-13 01:38:15 -04:00
2004-08-13 18:43:03 -04:00
return &io_tasks[fd];
2004-08-13 01:38:15 -04:00
}
2004-08-15 21:50:44 -04:00
void primitive_add_read_line_io_task(void)
2004-08-13 01:38:15 -04:00
{
2004-08-15 21:50:44 -04:00
PORT* port = untag_port(dpop());
CELL callback = dpop();
add_io_task(IO_TASK_READ_LINE,port,callback,
read_io_tasks,&read_fd_count);
2004-08-13 01:38:15 -04:00
}
2004-08-15 21:50:44 -04:00
void primitive_add_write_io_task(void)
{
PORT* port = untag_port(dpop());
CELL callback = dpop();
add_io_task(IO_TASK_WRITE,port,callback,
write_io_tasks,&write_fd_count);
}
void primitive_add_accept_io_task(void)
{
PORT* port = untag_port(dpop());
CELL callback = dpop();
add_io_task(IO_TASK_ACCEPT,port,callback,
read_io_tasks,&read_fd_count);
}
2004-08-15 21:50:44 -04:00
void remove_io_task(
2004-08-13 02:19:22 -04:00
IO_TASK_TYPE type,
2004-08-13 01:38:15 -04:00
PORT* port,
IO_TASK* io_tasks,
int* fd_count)
{
2004-08-13 18:43:03 -04:00
int fd = port->fd;
2004-08-13 01:38:15 -04:00
2004-08-13 18:43:03 -04:00
io_tasks[fd].port = F;
io_tasks[fd].callback = F;
if(fd == *fd_count - 1)
*fd_count = *fd_count - 1;
2004-08-13 01:38:15 -04:00
}
2004-08-15 21:50:44 -04:00
void remove_io_tasks(PORT* port)
2004-08-13 01:38:15 -04:00
{
2004-08-15 21:50:44 -04:00
remove_io_task(IO_TASK_READ_LINE,port,
read_io_tasks,&read_fd_count);
remove_io_task(IO_TASK_WRITE,port,
write_io_tasks,&write_fd_count);
}
bool set_up_fd_set(fd_set* fdset, int fd_count, IO_TASK* io_tasks)
{
bool retval = false;
int i;
FD_ZERO(fdset);
for(i = 0; i < fd_count; i++)
2004-08-13 02:19:22 -04:00
{
2004-08-15 21:50:44 -04:00
if(typep(PORT_TYPE,io_tasks[i].port))
{
retval = true;
FD_SET(i,fdset);
}
}
return retval;
}
bool perform_read_line_io_task(PORT* port)
{
if(port->line == F)
port->line = tag_object(sbuf(LINE_SIZE));
else
untag_sbuf(port->line)->top = 0;
2004-08-15 21:50:44 -04:00
if(port->buf_pos >= port->buf_fill)
{
if(!read_step(port))
return false;
}
if(port->buf_fill == 0)
{
/* EOF */
port->line = F;
return true;
2004-08-13 02:19:22 -04:00
}
2004-08-15 21:50:44 -04:00
else
return read_line_step(port);
2004-08-13 01:38:15 -04:00
}
2004-08-15 21:50:44 -04:00
bool perform_write_io_task(PORT* port)
2004-08-13 01:38:15 -04:00
{
2004-08-15 21:50:44 -04:00
if(write_step(port))
{
if(port->buf_pos == port->buf_fill)
{
/* All written */
port->buf_pos = 0;
port->buf_fill = 0;
return true;
}
}
return false;
}
2004-08-13 02:19:22 -04:00
2004-08-15 21:50:44 -04:00
CELL perform_io_task(IO_TASK* task)
{
PORT* port = untag_port(task->port);
CELL callback = task->callback;
2004-08-13 02:19:22 -04:00
switch(task->type)
{
case IO_TASK_READ_LINE:
2004-08-15 21:50:44 -04:00
remove_io_task(IO_TASK_READ_LINE,port,
read_io_tasks,&read_fd_count);
if(perform_read_line_io_task(port))
return callback;
else
{
add_io_task(IO_TASK_READ_LINE,port,
callback,read_io_tasks,
&read_fd_count);
return F;
}
2004-08-13 02:19:22 -04:00
case IO_TASK_WRITE:
2004-08-15 21:50:44 -04:00
remove_io_task(IO_TASK_WRITE,port,
write_io_tasks,&write_fd_count);
if(perform_write_io_task(port))
return callback;
else
{
add_io_task(IO_TASK_WRITE,port,
callback,write_io_tasks,
&write_fd_count);
return F;
}
case IO_TASK_ACCEPT:
remove_io_task(IO_TASK_ACCEPT,port,
read_io_tasks,&read_fd_count);
if(accept_connection(port))
return callback;
else
{
add_io_task(IO_TASK_ACCEPT,port,
callback,read_io_tasks,
&read_fd_count);
return F;
}
2004-08-13 02:19:22 -04:00
default:
critical_error("Bad I/O task",task->type);
2004-08-15 21:50:44 -04:00
return F;
2004-08-13 02:19:22 -04:00
}
2004-08-13 01:38:15 -04:00
}
2004-08-15 21:50:44 -04:00
CELL perform_io_tasks(fd_set* fdset, int fd_count, IO_TASK* io_tasks)
2004-08-13 18:43:03 -04:00
{
int i;
2004-08-15 21:50:44 -04:00
CELL callback;
for(i = 0; i < fd_count; i++)
2004-08-13 18:43:03 -04:00
{
2004-08-15 21:50:44 -04:00
if(FD_ISSET(i,fdset))
2004-08-13 18:43:03 -04:00
{
2004-08-15 21:50:44 -04:00
if(io_tasks[i].port == F)
critical_error("select() returned fd for non-existent task",i);
else
{
callback = perform_io_task(&io_tasks[i]);
if(callback != F)
return callback;
}
2004-08-13 18:43:03 -04:00
}
}
2004-08-15 21:50:44 -04:00
return F;
2004-08-13 18:43:03 -04:00
}
2004-08-13 01:38:15 -04:00
/* Wait for I/O and return a callback. */
2004-08-15 21:50:44 -04:00
CELL next_io_task(void)
2004-08-13 01:38:15 -04:00
{
2004-08-15 21:50:44 -04:00
bool reading = set_up_fd_set(&read_fd_set,
read_fd_count,read_io_tasks);
bool writing = set_up_fd_set(&write_fd_set,
write_fd_count,write_io_tasks);
CELL callback;
2004-08-13 18:43:03 -04:00
if(!reading && !writing)
2004-08-15 21:50:44 -04:00
critical_error("next_io_task() called with no IO tasks",0);
2004-08-13 02:19:22 -04:00
2004-08-13 18:43:03 -04:00
select(read_fd_count > write_fd_count
? read_fd_count : write_fd_count,
(reading ? &read_fd_set : NULL),
(writing ? &write_fd_set : NULL),
NULL,NULL);
2004-08-15 21:50:44 -04:00
callback = perform_io_tasks(&read_fd_set,read_fd_count,read_io_tasks);
if(callback != F)
return callback;
2004-08-13 02:19:22 -04:00
2004-08-15 21:50:44 -04:00
return perform_io_tasks(&write_fd_set,write_fd_count,write_io_tasks);
}
2004-08-13 02:19:22 -04:00
2004-08-15 21:50:44 -04:00
void primitive_next_io_task(void)
{
CELL callback;
for(;;)
{
callback = next_io_task();
if(callback != F)
break;
}
dpush(callback);
}
2004-08-13 02:19:22 -04:00
void collect_io_tasks(void)
{
int i;
for(i = 0; i < FD_SETSIZE; i++)
{
copy_object(&read_io_tasks[i].port);
copy_object(&read_io_tasks[i].callback);
}
for(i = 0; i < FD_SETSIZE; i++)
{
copy_object(&write_io_tasks[i].port);
copy_object(&write_io_tasks[i].callback);
}
}