commit 2feb45fcfff34bb9499d4d56cfeb0ebab12dc295
parent 6b7bff0facdbf85b0cd9bf672b53a838e40984f4
Author: Ambroise Vincent <ambroise.vincent@arm.com>
Date: Tue, 14 May 2019 16:40:23 +0100
[dev] Improve shared resources management
Add locks to channels and mount points.
Change-Id: Ief2b7f6a0e8016ede7b52d94d8922948b414124a
Signed-off-by: Ambroise Vincent <ambroise.vincent@arm.com>
Diffstat:
4 files changed, 98 insertions(+), 48 deletions(-)
diff --git a/drivers/dev.c b/drivers/dev.c
@@ -10,14 +10,25 @@
#define NR_MPOINTS 4
+/*
+ * Lock policy:
+ * The channels are locked when accessed from the raw fdset array, which is
+ * currently done by newchan() and fd2chan().
+ * The channels are propagated through the functions in a locked state.
+ * When a channel is done being used, it needs to be unlocked. This is either
+ * done when the channel is closed by delchan(), or directly with a call to
+ * unlock() when inside of dev.c.
+ * The use of mutexes is then transparent for the drivers.
+ */
+
struct mpoint {
Chan *new;
Chan *old;
+ mutex_t mutex;
};
static Chan fdset[NR_CHANS];
static Chan slash;
-static mutex_t chanlock;
static struct mpoint mpoints[NR_MPOINTS];
Chan *
@@ -26,29 +37,51 @@ newchan(unsigned char type)
Chan *c = NULL;
int i;
- lock(&chanlock);
for (i = 0; i < NR_CHANS; i++) {
- if (fdset[i].type == NODEV) {
- c = &fdset[i];
+ c = &fdset[i];
+ if (trylock(&c->mutex) < 0)
+ continue;
+ if (c->type == NODEV) {
c->type = type;
break;
}
+ unlock(&c->mutex);
}
- unlock(&chanlock);
if (!c)
errno = ENOMEM;
return c;
}
+void
+delchan(Chan *c)
+{
+ c->qid = 0;
+ c->dev = 0;
+ c->offset = 0;
+ c->type = NODEV;
+ unlock(&c->mutex);
+}
+
static Chan *
fd2chan(int fd)
{
- if (fd < 0 || fd >= NR_CHANS || fdset[fd].type == NODEV) {
- errno = EBADF;
- return NULL;
- }
- return &fdset[fd];
+ Chan *c;
+
+ if (fd < 0 || fd >= NR_CHANS)
+ goto badfd;
+
+ c = &fdset[fd];
+ lock(&c->mutex);
+ if (fdset[fd].type == NODEV)
+ goto ubadfd;
+ return c;
+
+ubadfd:
+ unlock(&c->mutex);
+badfd:
+ errno = EBADF;
+ return NULL;
}
static int
@@ -111,15 +144,6 @@ devtype(int c)
return i;
}
-void
-delchan(Chan *c)
-{
- c->qid = 0;
- c->dev = 0;
- c->offset = 0;
- c->type = NODEV;
-}
-
int
buf2chan(Chan *c, void *dst, void *src, int nbytes, long len)
{
@@ -145,10 +169,16 @@ mntpoint(int type, Qid qid)
struct mpoint *mp;
for (mp = mpoints; mp < &mpoints[NR_MPOINTS]; mp++) {
- if ((cn = mp->new) == NULL)
+ lock(&mp->mutex);
+ if ((cn = mp->new) == NULL) {
+ unlock(&mp->mutex);
continue;
- if (cn->type == type && cn->qid == qid)
+ }
+ if (cn->type == type && cn->qid == qid) {
+ unlock(&mp->mutex);
return mp->old;
+ }
+ unlock(&mp->mutex);
}
return NULL;
@@ -340,12 +370,16 @@ int
open(const char *fname, int mode)
{
Chan *c;
+ int r;
if (!validmode(mode))
return -1;
+
c = namec(fname, mode);
- return chan2fd(c);
+ r = chan2fd(c);
+ unlock(&c->mutex);
+ return r;
}
int
@@ -441,73 +475,81 @@ int
read(int fd, void *buf, int n)
{
Chan *c;
+ int r = -1;
if ((c = fd2chan(fd)) == NULL)
return -1;
- if ((c->qid & CHDIR) && (n < DIRLEN)) {
+ if ((c->qid & CHDIR) && (n < DIRLEN))
errno = EINVAL;
- return -1;
- }
+ else
+ r = devtab[c->type]->read(c, buf, n);
- return devtab[c->type]->read(c, buf, n);
+ unlock(&c->mutex);
+ return r;
}
int
write(int fd, void *buf, int n)
{
Chan *c;
+ int r = -1;
if ((c = fd2chan(fd)) == NULL)
return -1;
- if (c->qid & CHDIR) {
+ if (c->qid & CHDIR)
errno = EISDIR;
- return -1;
- }
+ else
+ r = devtab[c->type]->write(c, buf, n);
- return devtab[c->type]->write(c, buf, n);
+ unlock(&c->mutex);
+ return r;
}
int
seek(int fd, long off, int whence)
{
Chan *c;
+ int r = -1;
if ((c = fd2chan(fd)) == NULL)
return -1;
- if (c->qid & CHDIR) {
+ if (c->qid & CHDIR)
errno = EISDIR;
- return -1;
- }
+ else
+ r = devtab[c->type]->seek(c, off, whence);
- return devtab[c->type]->seek(c, off, whence);
+ unlock(&c->mutex);
+ return r;
}
int
fsync(int fd)
{
Chan *c;
+ int r = -1;
if ((c = fd2chan(fd)) == NULL)
return -1;
- if (c->qid & CHDIR) {
- errno = EISDIR;
- return -1;
- }
+ if (c->qid & CHDIR)
+ errno = EISDIR;
+ else
+ r = devtab[c->type]->sync(c, SYNCDEV);
- return devtab[c->type]->sync(c, SYNCDEV);
+ unlock(&c->mutex);
+ return r;
}
void
sync(void)
{
Chan *c;
- Dev * const *dp;
+ Dev * const *dp;
- for (dp = devtab; *dp; ++dp) {
+ for (dp = devtab; *dp; ++dp) {
c = attach((*dp)->id, 0);
devtab[c->type]->sync(c, SYNCALL);
delchan(c);
@@ -575,8 +617,10 @@ addmntpoint(Chan *c, char *new)
for (i = NR_MPOINTS-1; i >= 0; i--) {
mp = &mpoints[i];
+ lock(&mp->mutex);
if (!mp->new)
break;
+ unlock(&mp->mutex);
}
if (i < 0) {
@@ -586,6 +630,7 @@ addmntpoint(Chan *c, char *new)
mp->new = cn;
mp->old = c;
+ unlock(&mp->mutex);
return 0;
@@ -607,6 +652,7 @@ bind(char *old, char *new)
delchan(c);
return -1;
}
+ unlock(&c->mutex);
return 0;
}
@@ -620,19 +666,18 @@ mount(char *srv, char *where, char *spec)
goto err0;
c = devtab[cs->type]->mount(cs, spec);
+ delchan(cs);
if (!c)
- goto err1;
+ goto err0;
if (addmntpoint(c, where) < 0)
- goto err2;
- delchan(cs);
+ goto err1;
+ unlock(&c->mutex);
return 0;
-err2:
- delchan(c);
err1:
- delchan(cs);
+ delchan(c);
err0:
return -1;
}
diff --git a/drivers/dev.h b/drivers/dev.h
@@ -43,6 +43,7 @@ struct chan {
unsigned char type;
unsigned char dev;
unsigned char mode;
+ mutex_t mutex;
};
struct attr {
diff --git a/include/rcode/rcode.h b/include/rcode/rcode.h
@@ -104,6 +104,7 @@ extern uint16_t outm16(uint16_t, void *addr);
extern uint32_t outm32(uint32_t, void *addr);
extern void lock(mutex_t *m);
extern void unlock(mutex_t *m);
+extern int trylock(mutex_t *m);
/* dlang.c */
extern unsigned in_debug;
diff --git a/target/native/arch.s b/target/native/arch.s
@@ -6,7 +6,7 @@
.globl outm8,outm16,outm32
.globl invdcachesetway,invicache,vectbl,doswtch
.globl inm8,inm16,inm32,outm8,outm16,outm32
- .globl lock,unlock
+ .globl lock,unlock,trylock
intr:
cmp x0,#0
@@ -86,6 +86,9 @@ unlock:
sev
ret
+trylock:
+ ret // TODO
+
dohalt:
msr daifset,#15
wfe