poll: use spinlocks rather than mutexes for use in higher IPLs

This commit is contained in:
Matheus
2024-04-07 16:34:40 -03:00
parent ae1186c835
commit e17583de1b
2 changed files with 29 additions and 21 deletions
+3 -4
View File
@@ -3,21 +3,20 @@
#include <kernel/scheduler.h> #include <kernel/scheduler.h>
#include <spinlock.h> #include <spinlock.h>
#include <mutex.h>
struct polldata; struct polldata;
typedef struct { typedef struct {
thread_t *thread; thread_t *thread;
spinlock_t lock; spinlock_t lock;
mutex_t eventlock; spinlock_t eventlock;
struct polldata *data; struct polldata *data;
struct polldata *event; struct polldata *event;
size_t size; size_t size;
} polldesc_t; } polldesc_t;
typedef struct { typedef struct {
mutex_t lock; spinlock_t lock;
struct polldata *data; struct polldata *data;
} pollheader_t; } pollheader_t;
@@ -31,7 +30,7 @@ typedef struct polldata {
} polldata_t; } polldata_t;
#define POLL_INITHEADER(x) \ #define POLL_INITHEADER(x) \
MUTEX_INIT(&(x)->lock); SPINLOCK_INIT((x)->lock);
int poll_initdesc(polldesc_t *, size_t size); int poll_initdesc(polldesc_t *, size_t size);
void poll_add(pollheader_t *, polldata_t *, int events); void poll_add(pollheader_t *, polldata_t *, int events);
+26 -17
View File
@@ -39,7 +39,7 @@ int poll_initdesc(polldesc_t *desc, size_t size) {
desc->thread = _cpu()->thread; desc->thread = _cpu()->thread;
desc->size = size; desc->size = size;
SPINLOCK_INIT(desc->lock); SPINLOCK_INIT(desc->lock);
MUTEX_INIT(&desc->eventlock); SPINLOCK_INIT(desc->eventlock);
for (uintmax_t i = 0; i < size; ++i) for (uintmax_t i = 0; i < size; ++i)
desc->data[i].desc = desc; desc->data[i].desc = desc;
__assert(spinlock_try(&desc->lock)); __assert(spinlock_try(&desc->lock));
@@ -48,11 +48,13 @@ int poll_initdesc(polldesc_t *desc, size_t size) {
} }
void poll_add(pollheader_t *header, polldata_t *data, int events) { void poll_add(pollheader_t *header, polldata_t *data, int events) {
MUTEX_ACQUIRE(&header->lock, false); bool intstate = interrupt_set(false);
spinlock_acquire(&header->lock);
data->events = events; data->events = events;
data->header = header; data->header = header;
insertinheader(header, data); insertinheader(header, data);
MUTEX_RELEASE(&header->lock); spinlock_release(&header->lock);
interrupt_set(intstate);
} }
void poll_leave(polldesc_t *desc) { void poll_leave(polldesc_t *desc) {
@@ -61,29 +63,35 @@ void poll_leave(polldesc_t *desc) {
if (header == NULL) if (header == NULL)
continue; continue;
MUTEX_ACQUIRE(&header->lock, false); bool intstate = interrupt_set(false);
spinlock_acquire(&header->lock);
removefromlist(&header->data, &desc->data[i]); removefromlist(&header->data, &desc->data[i]);
MUTEX_RELEASE(&header->lock); spinlock_release(&header->lock);
interrupt_set(intstate);
} }
} }
static void timeout(context_t *, dpcarg_t arg) { static void timeout(context_t *, dpcarg_t arg) {
polldesc_t *desc = arg; polldesc_t *desc = arg;
MUTEX_TRY(&desc->eventlock); bool intstate = interrupt_set(false);
spinlock_acquire(&desc->eventlock);
if (spinlock_try(&desc->lock)) if (spinlock_try(&desc->lock))
sched_wakeup(desc->thread, 1); sched_wakeup(desc->thread, 1);
MUTEX_RELEASE(&desc->eventlock); spinlock_release(&desc->eventlock);
interrupt_set(intstate);
} }
int poll_dowait(polldesc_t *desc, size_t ustimeout) { int poll_dowait(polldesc_t *desc, size_t ustimeout) {
timerentry_t sleepentry = {0}; timerentry_t sleepentry = {0};
MUTEX_ACQUIRE(&desc->eventlock, false); bool intstate = interrupt_set(false);
spinlock_acquire(&desc->eventlock);
if (desc->event) { if (desc->event) {
MUTEX_RELEASE(&desc->eventlock); spinlock_release(&desc->eventlock);
interrupt_set(intstate);
return 0; return 0;
} }
@@ -95,7 +103,7 @@ int poll_dowait(polldesc_t *desc, size_t ustimeout) {
} }
spinlock_release(&desc->lock); spinlock_release(&desc->lock);
MUTEX_RELEASE(&desc->eventlock); spinlock_release(&desc->eventlock);
int ret = sched_yield(); int ret = sched_yield();
// on return, the desc lock is REQUIRED to be left locked by the poll_event function. // on return, the desc lock is REQUIRED to be left locked by the poll_event function.
// XXX interruptible wait breaks this // XXX interruptible wait breaks this
@@ -106,13 +114,16 @@ int poll_dowait(polldesc_t *desc, size_t ustimeout) {
sched_targetcpu(NULL); sched_targetcpu(NULL);
} }
interrupt_set(intstate);
ret = ret == 1 ? 0 : ret; ret = ret == 1 ? 0 : ret;
return ret; return ret;
} }
void poll_event(pollheader_t *header, int events) { void poll_event(pollheader_t *header, int events) {
MUTEX_ACQUIRE(&header->lock, false); bool intstate = interrupt_set(false);
spinlock_acquire(&header->lock);
polldata_t *pending = header->data; polldata_t *pending = header->data;
header->data = NULL; header->data = NULL;
polldata_t *iterator = pending; polldata_t *iterator = pending;
@@ -120,7 +131,7 @@ void poll_event(pollheader_t *header, int events) {
while (iterator) { while (iterator) {
polldesc_t *desc = iterator->desc; polldesc_t *desc = iterator->desc;
polldata_t *next = iterator->next; polldata_t *next = iterator->next;
MUTEX_ACQUIRE(&desc->eventlock, false); spinlock_acquire(&desc->eventlock);
int revents = iterator->events & events; int revents = iterator->events & events;
if (spinlock_try(&desc->lock) == false) { if (spinlock_try(&desc->lock) == false) {
@@ -133,13 +144,11 @@ void poll_event(pollheader_t *header, int events) {
desc->event = iterator; desc->event = iterator;
} }
MUTEX_RELEASE(&desc->eventlock); spinlock_release(&desc->eventlock);
iterator = next; iterator = next;
} }
int ipl = interrupt_raiseipl(IPL_DPC);
iterator = pending; iterator = pending;
while (iterator) { while (iterator) {
polldata_t *next = iterator->next; polldata_t *next = iterator->next;
@@ -148,8 +157,8 @@ void poll_event(pollheader_t *header, int events) {
iterator = next; iterator = next;
} }
MUTEX_RELEASE(&header->lock); spinlock_release(&header->lock);
interrupt_loweripl(ipl); interrupt_set(intstate);
} }
void poll_destroydesc(polldesc_t *desc) { void poll_destroydesc(polldesc_t *desc) {