A FILE implementation that uses sys_async

上级 d41ef66a
......@@ -18,6 +18,7 @@ UPROGS= \
usertests \
lockstat \
preadtest \
ftest \
perf
ifeq ($(HAVE_LWIP),y)
......
#include "types.h"
#include "stat.h"
#include "fcntl.h"
#include "user.h"
#include "lib.h"
#include "amd64.h"
#include "ipc.hh"
extern "C" {
#include "fstream.h"
}
#define FSIZE (64 << 10)
#define BSIZE 4096
static char wbuf[512];
static char rbuf[BSIZE];
static int check = 0;
int
main(int ac, char **av)
{
size_t count;
off_t off;
FILE *fp;
int fd;
int i;
memset(ipcctl, 0, sizeof(*ipcctl));
for (i = 0; i < sizeof(wbuf); i++)
wbuf[i] = i % 16;
unlink("ftest.x");
fd = open("ftest.x", O_CREATE|O_RDWR);
for (i = 0; i < FSIZE; ) {
count = MIN(sizeof(wbuf), FSIZE-i);
if (write(fd, wbuf, count) != count)
die("write failed");
i += count;
}
fp = fdopen(fd, "r");
if (fp == 0)
die("fdopen");
off = 0;
while ((count = fread(rbuf, 1, BSIZE, fp))) {
if (check) {
for (i = 0; i < count; i++)
if (rbuf[i] != (i+off)%16)
die("ftest %u: %u != %u", i, (int)(rbuf[i]), (off+i)%16);
off += count;
}
}
fclose(fp);
exit();
}
......@@ -7,9 +7,6 @@
#include "amd64.h"
#include "ipc.hh"
// XXX(sbw) add a memlayout.h?
#define KSHARED 0xFFFFF00000000000ull
#define FSIZE (64 << 10)
#define BSIZE 4096
#define PSIZE (4*BSIZE)
......@@ -18,8 +15,6 @@ static int use_async;
static char buf[BSIZE];
struct ipcctl *ipcctl = (struct ipcctl*)KSHARED;
struct {
u64 acount;
u64 atot;
......@@ -28,50 +23,6 @@ struct {
u64 ptot;
} stats;
static msgid_t
ipc_msg_alloc(void)
{
if (ipcctl->msghead - ipcctl->msgtail == IPC_NMSG)
return NULL_MSGID;
msgid_t i = ipcctl->msghead % IPC_NMSG;
ipcctl->msghead++;
return i;
}
static void
ipc_msg_free(int msgid)
{
msgid_t i;
i = ipcctl->msgtail % IPC_NMSG;
if (i != msgid)
die("ipc_free_msg: oops");
ipcctl->msgtail++;
}
static pageid_t
ipc_page_alloc(void)
{
if (ipcctl->pagehead - ipcctl->pagetail == IPC_NPAGE)
return NULL_PAGEID;
pageid_t i = ipcctl->pagehead % IPC_NPAGE;
ipcctl->pagehead++;
return i;
}
static void
ipc_page_free(pageid_t pageid)
{
pageid_t i;
i = ipcctl->pagetail % IPC_NPAGE;
if (i != pageid)
die("ipc_free_page: oops");
ipcctl->pagetail++;
}
static void
kernlet_pread(int fd, size_t count, off_t off)
{
......
typedef struct fstream {
int fd;
off_t off;
off_t poff;
struct stat stat;
int err:1;
int eof:1;
int pfill:1;
} FILE;
FILE *fdopen(int fd, const char *mode);
int fclose(FILE *fp);
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *fp);
int feof(FILE *fp);
int ferror(FILE *fp);
#define IPC_NMSG 16
typedef u32 msgid_t;
#define NULL_MSGID (-1)
// XXX(sbw) add a memlayout.h?
#define KSHARED 0xFFFFF00000000000ull
#define IPC_NPAGE ((KSHAREDSIZE/PGSIZE) - 1)
typedef u32 pageid_t;
typedef u32 msgid_t;
#define IPC_CTLSIZE 4096
#define IPC_PGSIZE 4096
#define IPC_NMSG 16
#define NULL_MSGID (-1)
#define NULL_PAGEID (-1)
#define IPC_NPAGE ((KSHAREDSIZE/IPC_PGSIZE) - 1)
struct ipcmsg {
volatile char done:1;
......@@ -16,10 +21,28 @@ struct ipcmsg {
};
struct ipcctl {
int msghead;
int msgtail;
volatile int msghead;
volatile int msgtail;
struct ipcmsg msg[IPC_NMSG];
int pagehead;
int pagetail;
volatile int pagehead;
volatile int pagetail;
};
extern struct ipcctl *ipcctl;
msgid_t ipc_msg_alloc(void);
void ipc_msg_free(int msgid);
pageid_t ipc_page_alloc(void);
void ipc_page_free(pageid_t pageid);
static inline struct ipcmsg*
getmsg(msgid_t id)
{
return &ipcctl->msg[id];
}
static inline char*
getpage(pageid_t id)
{
return (char*)(KSHARED+IPC_CTLSIZE+(id*IPC_PGSIZE));
}
ULIB = ulib.o usys.o printf.o umalloc.o uthread.o fmt.o
ULIB = ulib.o usys.o printf.o umalloc.o uthread.o fmt.o fstream.o ipc.o
ULIB := $(addprefix $(O)/lib/, $(ULIB))
.PRECIOUS: $(O)/lib/%.o
......
extern "C" {
#include "types.h"
#include "stat.h"
#include "user.h"
#include "fstream.h"
#include "lib.h"
#include "amd64.h"
}
#include "ipc.hh"
static const size_t pstride = 4096*4;
static ssize_t
fasync(FILE *fp, size_t count, off_t off)
{
struct ipcmsg *msg;
msgid_t msgid;
pageid_t pageid;
msgid = ipc_msg_alloc();
if (msgid == NULL_MSGID) {
fprintf(2, "fasync: ipc_msg_alloc failed\n");
return -1;
}
pageid = ipc_page_alloc();
if (pageid == NULL_PAGEID) {
fprintf(2, "fasync: ipc_alloc_page failed\n");
return -1;
}
msg = &ipcctl->msg[msgid];
msg->done = 0;
msg->pageid = pageid;
if (async(fp->fd, count, off, msgid, pageid) != 0) {
fprintf(2, "fasync: async failed\n");
return -1;
}
return count;
}
static void
fprefill(FILE *fp)
{
size_t target;
if (!fp->pfill)
return;
target = MIN(fp->off + pstride, fp->stat.size);
while (target - fp->poff >= IPC_PGSIZE)
{
size_t count;
int r;
count = MIN(target - fp->poff, IPC_PGSIZE);
r = fasync(fp, count, fp->poff);
if (r < 0)
return;
fp->poff += r;
}
}
FILE*
fdopen(int fd, const char *mode)
{
FILE *fp;
if (mode[0] != 'r')
return 0;
fp = (FILE*)malloc(sizeof(*fp));
if (fp == 0)
return 0;
if (fstat(fd, &fp->stat))
return 0;
fp->fd = fd;
fp->off = 0;
fp->poff = 0;
fp->pfill = mode[1] == 'p';
fprefill(fp);
return fp;
}
int
fclose(FILE *fp)
{
int r;
r = close(fp->fd);
free(fp);
return r;
// XXX(sbw) free ipcmsgs
}
static ssize_t
fpostfill(void *ptr, size_t count, FILE*fp)
{
struct ipcmsg *msg;
msgid_t msgid;
if (!fp->pfill)
return -2;
again:
msgid = ipcctl->msgtail % IPC_NMSG;
msg = getmsg(msgid);
if (!msg->submitted)
return -2;
while (msg->done == 0)
nop_pause(); // XXX(sbw) yield somewhere?
if (msg->result == -1)
return -1;
if (msg->off > fp->off) {
return -2;
} else if ((msg->off + msg->result) < fp->off) {
msg->submitted = 0;
ipc_page_free(msg->pageid);
ipc_msg_free(msgid);
goto again;
}
char *buf = getpage(msg->pageid);
off_t boff = fp->off - msg->off;
size_t bcount = MIN(count, msg->result-boff);
memmove(ptr, buf+boff, bcount);
msg->submitted = 0;
ipc_page_free(msg->pageid);
ipc_msg_free(msgid);
return bcount;
}
size_t
fread(void *ptr, size_t size, size_t nmemb, FILE *fp)
{
ssize_t r;
r = fpostfill(ptr, size*nmemb, fp);
if (r == -2)
r = pread(fp->fd, ptr, size*nmemb, fp->off);
if (r < 0) {
fp->err = 1;
return 0;
} else if (r == 0) {
fp->eof = 1;
return 0;
}
fp->off += r;
fprefill(fp);
return r;
}
int
feof(FILE *fp)
{
return fp->eof;
}
int
ferror(FILE *fp)
{
return fp->err;
}
#include "types.h"
#include "user.h"
#include "ipc.hh"
struct ipcctl *ipcctl = (struct ipcctl*)KSHARED;
msgid_t
ipc_msg_alloc(void)
{
if (ipcctl->msghead - ipcctl->msgtail == IPC_NMSG)
return NULL_MSGID;
msgid_t i = ipcctl->msghead % IPC_NMSG;
ipcctl->msghead++;
return i;
}
void
ipc_msg_free(int msgid)
{
msgid_t i;
i = ipcctl->msgtail % IPC_NMSG;
if (i != msgid)
die("ipc_free_msg: oops %u %u", i, msgid);
ipcctl->msgtail++;
}
pageid_t
ipc_page_alloc(void)
{
if (ipcctl->pagehead - ipcctl->pagetail == IPC_NPAGE)
return NULL_PAGEID;
pageid_t i = ipcctl->pagehead % IPC_NPAGE;
ipcctl->pagehead++;
return i;
}
void
ipc_page_free(pageid_t pageid)
{
pageid_t i;
i = ipcctl->pagetail % IPC_NPAGE;
if (i != pageid)
die("ipc_free_page: oops");
ipcctl->pagetail++;
}
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论