Skip to content

Commit

Permalink
Introduce IoReq to track I/O operation in progress.
Browse files Browse the repository at this point in the history
  • Loading branch information
cahirwpz committed Mar 16, 2021
1 parent acd5074 commit c5d3702
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 81 deletions.
15 changes: 8 additions & 7 deletions drivers/memdev.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#include <string.h>
#include <device.h>
#include <ioreq.h>
#include <memdev.h>

static int MemoryRead(Device_t *, off_t, void *, size_t, ssize_t *);
static int MemoryRead(Device_t *, IoReq_t *);

static DeviceOps_t MemoryOps = {.read = MemoryRead};

Expand All @@ -17,11 +18,11 @@ int AddMemoryDev(const char *name, const void *buf, size_t size) {
return 0;
}

static int MemoryRead(Device_t *dev, off_t offset, void *buf, size_t nbyte,
ssize_t *donep) {
if (offset + (ssize_t)nbyte > dev->size)
nbyte = dev->size - offset;
memcpy(buf, dev->data + offset, nbyte);
*donep = nbyte;
static int MemoryRead(Device_t *dev, IoReq_t *req) {
size_t n = req->left;
if (req->offset + (ssize_t)req->left > dev->size)
n = dev->size - req->offset;
memcpy(req->rbuf, dev->data + req->offset, n);
req->left -= n;
return 0;
}
27 changes: 9 additions & 18 deletions drivers/serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <libkern.h>
#include <serial.h>
#include <ring.h>
#include <ioreq.h>
#include <device.h>

#define CLOCK 3546895
Expand All @@ -18,8 +19,8 @@ static Ring_t *RxBuf = &RING(BUFLEN);
static TaskHandle_t TxWaiter;
static TaskHandle_t RxWaiter;

static int SerialRead(Device_t *, off_t, void *, size_t, ssize_t *);
static int SerialWrite(Device_t *, off_t, const void *, size_t, ssize_t *);
static int SerialRead(Device_t *, IoReq_t *);
static int SerialWrite(Device_t *, IoReq_t *);

static DeviceOps_t SerialOps = {
.read = SerialRead,
Expand Down Expand Up @@ -78,10 +79,7 @@ void SerialKill(void) {
kprintf("[Serial] Driver deactivated!\n");
}

static int SerialWrite(Device_t *dev __unused, off_t offset __unused,
const void *data, size_t len, ssize_t *donep) {
size_t done = 0;

static int SerialWrite(Device_t *dev __unused, IoReq_t *req) {
xSemaphoreTake(TxLock, portMAX_DELAY);
taskENTER_CRITICAL();
{
Expand All @@ -90,9 +88,9 @@ static int SerialWrite(Device_t *dev __unused, off_t offset __unused,
CauseIRQ(INTF_TBE);

/* Write all bytes to transmit buffer. */
while (1) {
done += RingWrite(TxBuf, data + done, len - done);
if (done == len)
for (;;) {
RingWrite(TxBuf, req);
if (!req->left)
break;
TxWaiter = xTaskGetCurrentTaskHandle();
xTaskNotifyWait(0, 0, NULL, portMAX_DELAY);
Expand All @@ -101,28 +99,21 @@ static int SerialWrite(Device_t *dev __unused, off_t offset __unused,
taskEXIT_CRITICAL();
xSemaphoreGive(TxLock);

if (donep)
*donep = done;
return 0;
}

static int SerialRead(Device_t *dev __unused, off_t offset __unused, void *data,
size_t len, ssize_t *donep) {
size_t done;

static int SerialRead(Device_t *dev __unused, IoReq_t *req) {
xSemaphoreTake(RxLock, portMAX_DELAY);
taskENTER_CRITICAL();
{
while (RingEmpty(RxBuf)) {
RxWaiter = xTaskGetCurrentTaskHandle();
xTaskNotifyWait(0, 0, NULL, portMAX_DELAY);
}
done = RingRead(RxBuf, data, len);
RingRead(RxBuf, req);
}
taskEXIT_CRITICAL();
xSemaphoreGive(RxLock);

if (donep)
*donep = done;
return 0;
}
17 changes: 15 additions & 2 deletions kernel/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <libkern.h>
#include <string.h>
#include <device.h>
#include <ioreq.h>
#include <sys/errno.h>

static int DevRead(File_t *, void *, size_t, long *);
Expand Down Expand Up @@ -97,12 +98,24 @@ int OpenDevice(const char *name, File_t **fp) {

static int DevRead(File_t *f, void *buf, size_t len, long *donep) {
DeviceRead_t read = f->device->ops->read;
return read ? read(f->device, f->offset, buf, len, donep) : ENOSYS;
if (!read)
return ENOSYS;

IoReq_t req = IOREQ_READ(f->offset, buf, len);
int error = read(f->device, &req);
*donep = len - req.left;
return error;
}

static int DevWrite(File_t *f, const void *buf, size_t len, long *donep) {
DeviceWrite_t write = f->device->ops->write;
return write ? write(f->device, f->offset, buf, len, donep) : ENOSYS;
if (!write)
return ENOSYS;

IoReq_t req = IOREQ_WRITE(f->offset, buf, len);
int error = write(f->device, &req);
*donep = len - req.left;
return error;
}

static int DevSeek(File_t *f, long offset, int whence) {
Expand Down
7 changes: 3 additions & 4 deletions kernel/include/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@
#include <sys/queue.h>

typedef struct File File_t;
typedef struct IoReq IoReq_t;
typedef struct Device Device_t;
typedef struct DeviceOps DeviceOps_t;

typedef int (*DeviceRead_t)(Device_t *dev, off_t offset, void *buf, size_t len,
ssize_t *donep);
typedef int (*DeviceWrite_t)(Device_t *dev, off_t offset, const void *buf,
size_t len, ssize_t *donep);
typedef int (*DeviceRead_t)(Device_t *dev, IoReq_t *req);
typedef int (*DeviceWrite_t)(Device_t *dev, IoReq_t *req);

struct DeviceOps {
DeviceRead_t read;
Expand Down
23 changes: 23 additions & 0 deletions kernel/include/ioreq.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include <sys/types.h>

/* Tracks progress of I/O operation. */
typedef struct IoReq {
off_t offset;
union {
char *rbuf;
const char *wbuf;
};
size_t left;
} IoReq_t;

#define IOREQ_READ(_offset, _buf, _len) \
(IoReq_t) { \
.offset = (_offset), .rbuf = (_buf), .left = (_len), \
}

#define IOREQ_WRITE(_offset, _buf, _len) \
(IoReq_t) { \
.offset = (_offset), .wbuf = (_buf), .left = (_len), \
}
7 changes: 5 additions & 2 deletions kernel/include/ring.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include <sys/types.h>

typedef struct IoReq IoReq_t;

typedef struct Ring {
size_t head; /*!< producing data moves head forward */
size_t tail; /*!< consuming data moves tail forward */
Expand All @@ -26,5 +28,6 @@ static inline bool RingFull(Ring_t *buf) {

void RingPutByte(Ring_t *buf, uint8_t byte);
int RingGetByte(Ring_t *buf);
size_t RingRead(Ring_t *buf, void *data, size_t len);
size_t RingWrite(Ring_t *buf, const void *data, size_t len);

void RingRead(Ring_t *buf, IoReq_t *req);
void RingWrite(Ring_t *buf, IoReq_t *req);
31 changes: 15 additions & 16 deletions kernel/ring.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <ioreq.h>
#include <ring.h>
#include <string.h>

Expand Down Expand Up @@ -30,34 +31,32 @@ int RingGetByte(Ring_t *buf) {
return byte;
}

size_t RingRead(Ring_t *buf, void *data, size_t len) {
size_t done = 0;
void RingRead(Ring_t *buf, IoReq_t *req) {
/* repeat when used space is split into two parts */
while (done < len && !RingEmpty(buf)) {
while (req->left && !RingEmpty(buf)) {
/* used space is either [tail, head) or [tail, size) */
size_t size =
(buf->tail < buf->head) ? buf->head - buf->tail : buf->size - buf->tail;
if (size > len)
size = len;
memcpy(data + done, buf->data + buf->tail, size);
if (size > req->left)
size = req->left;
memcpy(req->rbuf, buf->data + buf->tail, size);
req->rbuf += size;
req->left -= size;
RingConsume(buf, size);
done += size;
}
return done;
}

size_t RingWrite(Ring_t *buf, const void *data, size_t len) {
size_t done = 0;
void RingWrite(Ring_t *buf, IoReq_t *req) {
/* repeat when free space is split into two parts */
while (done < len && !RingFull(buf)) {
while (req->left && !RingFull(buf)) {
/* free space is either [head, tail) or [head, size) */
size_t size =
(buf->head < buf->tail) ? buf->tail - buf->head : buf->size - buf->head;
if (size > len)
size = len;
memcpy(buf->data + buf->head, data + done, size);
if (size > req->left)
size = req->left;
memcpy(buf->data + buf->head, req->wbuf, size);
req->wbuf += size;
req->left -= size;
RingProduce(buf, size);
done += size;
}
return done;
}
56 changes: 24 additions & 32 deletions kernel/tty.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <tty.h>
#include <device.h>
#include <ioreq.h>
#include <libkern.h>
#include <sys/errno.h>

Expand All @@ -15,12 +16,10 @@ typedef struct TtyState {
Device_t *cons;
SemaphoreHandle_t writeLock;
SemaphoreHandle_t readLock;
char line[LINEBUF_SIZE];
size_t lineLength;
} TtyState_t;

static int TtyRead(Device_t *, off_t, void *, size_t, ssize_t *);
static int TtyWrite(Device_t *, off_t, const void *, size_t, ssize_t *);
static int TtyRead(Device_t *, IoReq_t *);
static int TtyWrite(Device_t *, IoReq_t *);

static DeviceOps_t TtyOps = {
.read = TtyRead,
Expand All @@ -37,68 +36,61 @@ int AddTtyDevice(const char *name, Device_t *cons) {
ts->cons = cons;
ts->readLock = xSemaphoreCreateMutex();
ts->writeLock = xSemaphoreCreateMutex();
ts->lineLength = 0;

if ((error = AddDevice(name, &TtyOps, &dev)))
return error;
dev->data = (void *)ts;
return 0;
}

static inline int ConsWrite(Device_t *cons, const char *data, size_t len) {
return cons->ops->write(cons, 0, data, len, NULL);
static inline int ConsPutChar(Device_t *cons, char data) {
return cons->ops->write(cons, &IOREQ_WRITE(0, &data, 1));
}

static int TtyWrite(Device_t *dev, off_t offset __unused, const void *data,
size_t len, ssize_t *donep) {
static int TtyWrite(Device_t *dev, IoReq_t *req) {
TtyState_t *tty = dev->data;
Device_t *cons = tty->cons;
const char *buf = data;
size_t done;
size_t n = req->left;
int error;

xSemaphoreTake(tty->writeLock, portMAX_DELAY);
for (done = 0; done < len; done++) {
char ch = buf[done];
while (req->left) {
char ch = *req->wbuf;
if (ch == '\n') {
/* Turn LF into CR + LF */
if ((error = ConsWrite(cons, "\r\n", 2)))
break;
} else {
/* Pass through all other characters. */
if ((error = ConsWrite(cons, buf + done, 1)))
if ((error = ConsPutChar(cons, '\r')))
break;
}
if ((error = ConsPutChar(cons, ch)))
break;
req->wbuf++;
req->left--;
}
xSemaphoreGive(tty->writeLock);

if (donep)
*donep = done;
return done ? 0 : error;
return req->left < n ? 0 : error;
}

static inline int ConsGetChar(Device_t *cons, char *data) {
return cons->ops->read(cons, 0, data, 1, NULL);
return cons->ops->read(cons, &IOREQ_READ(0, data, 1));
}

static int TtyRead(Device_t *dev, off_t offset __unused, void *data, size_t len,
ssize_t *donep) {
static int TtyRead(Device_t *dev, IoReq_t *req) {
TtyState_t *tty = dev->data;
Device_t *cons = tty->cons;
char *buf = data;
size_t done = 0;
size_t n = req->left;
int error;

xSemaphoreTake(tty->readLock, portMAX_DELAY);
while (done < len) {
if ((error = ConsGetChar(cons, buf + done)))
while (req->left) {
if ((error = ConsGetChar(cons, req->rbuf)))
break;
if (buf[done++] == '\n')
char ch = *req->rbuf++;
req->left--;
if (ch == '\n')
break;
}
xSemaphoreGive(tty->readLock);

if (donep)
*donep = done;
return done ? 0 : error;
return req->left < n ? 0 : error;
}

0 comments on commit c5d3702

Please sign in to comment.