device_initialize() function should be
called. Each I/O request has a tag indicating which I/O operation is
requested. In this main loop, only IO_MESG_OPEN for
device open request and IO_MESG_TERM for device server
shutdown request are acceptable.
Upon receiving an IO_MESG_OPEN request, a device server
process forks a child process in which actual I/O requests are
handled.
#include <score_device.h>
int main( int argc, char **argv ) {
struct sockaddr addr;
pid_t pid;
int addrsize;
int fd;
int tag;
int cell;
ioarg_t offset0, offset1;
if(device_initialize(argc, argv) < 0) device_terminate( 3 );
device_log("Device Initialized !!");
while(1) {
addrsize = sizeof(struct sockaddr);
if((fd = accept(fd_listen, &addr, &addrsize)) < 0) {
if(errno == EINTR) continue; /* in case of SIGCHLD */
device_log("Accept error");
device_terminate(1);
}
set_tcp_nodelay(fd);
if(read_device_op( &tag, &cell, &offset0, &offset1, fd ) != 0) {
device_log("Error in read device-op");
break;
}
switch(tag) {
case IO_MESG_OPEN:
if((pid = fork()) == 0) { /* if device process */
null_device(fd);
} else if (pid > 0) { /* if device server process */
if(write_device_ack(fd, NORMAL_END, cell) != 0) {
device_log("Error in write device ack");
}
close(fd);
} else { /* if error in fork() */
if(write_device_ack( fd, EIO, cell ) != 0) {
device_log("Error in write device ack");
}
device_log("Cannot fork device process");
}
break;
case IO_MESG_TERM:
device_log("device shutdown");
device_terminate(0);
break;
default:
device_log("Unknown I/O message tag (%d) (cell=%d,off=%d,wh=%d)",
tag, cell, offset, whence);
device_terminate(1);
break;
}
}
return(0);
}
IO_MESG_WRITE) is a no operation, and a
read request fills the corresponding I/O cell with zeros.
#include <score_device.h>
void null_device (int fd) {
int tag;
int cell;
ioarg_t offset0, offset1;
char pseudo_dev[IO_BUFFER_SIZE];
char *iobuf;
int length;
while(1) {
if(read_device_op( &tag, &cell, &offset0, &offset1, fd) != 0) {
device_log("Error in read device-op");
device_terminate(1);
}
switch(tag) {
case IO_MESG_WRITE:
length = get_iocell(cell, &iobuf);
/* actual write operation here */
if(write_device_ack(fd, NORMAL_END, cell) != 0) {
device_log("Error in write device ack");
}
break;
case IO_MESG_READ:
length = get_iocell(cell, &iobuf);
bzero(iobuf, length);
set_iocell_length(cell, length);
if(write_device_ack(fd, NORMAL_END, cell) != 0) {
device_log("Error in write device ack");
}
break;
case IO_MESG_CLOSE:
if(write_device_ack( fd, NORMAL_END, cell) != 0) {
device_log("Error in write device ack");
}
close(fd);
device_terminate(0);
break;
default:
device_log("Unknown I/O message tag");
device_terminate(1);
break;
}
}
}