summaryrefslogtreecommitdiff
path: root/nest/locks.c
diff options
context:
space:
mode:
authorMaria Matejka <mq@ucw.cz>2023-01-24 11:01:34 +0100
committerMaria Matejka <mq@ucw.cz>2023-01-24 11:34:36 +0100
commitf7c2a886c9fb73b2749d5e270f15b79c44e72a62 (patch)
tree602486438a95ce8bd1d71d0461227e0138b54b95 /nest/locks.c
parent3ac628e0f0b7ffaa49c95688cc95954ece8f61fc (diff)
Object locks use events
Instead of calling custom hooks from object locks, we use standard event sending mechanism to inform protocols about object lock changes. As event sending is lockless, the unlocking protocol simply enqueues the appropriate event to the given loop when the locking is done.
Diffstat (limited to 'nest/locks.c')
-rw-r--r--nest/locks.c70
1 files changed, 38 insertions, 32 deletions
diff --git a/nest/locks.c b/nest/locks.c
index 812a6534..fb245cdc 100644
--- a/nest/locks.c
+++ b/nest/locks.c
@@ -37,7 +37,11 @@
#include "nest/iface.h"
static list olock_list;
-static event *olock_event;
+
+DEFINE_DOMAIN(attrs);
+static DOMAIN(attrs) olock_domain;
+#define OBJ_LOCK LOCK_DOMAIN(attrs, olock_domain)
+#define OBJ_UNLOCK UNLOCK_DOMAIN(attrs, olock_domain)
static inline int
olock_same(struct object_lock *x, struct object_lock *y)
@@ -54,35 +58,52 @@ olock_same(struct object_lock *x, struct object_lock *y)
static void
olock_free(resource *r)
{
- struct object_lock *q, *l = (struct object_lock *) r;
+ /* Called externally from rfree() */
+ struct object_lock *l = SKIP_BACK(struct object_lock, r, r);
node *n;
+ OBJ_LOCK;
DBG("olock: Freeing %p\n", l);
switch (l->state)
{
case OLOCK_STATE_FREE:
break;
case OLOCK_STATE_LOCKED:
- case OLOCK_STATE_EVENT:
+ /* Remove myself from the olock_list */
rem_node(&l->n);
+
+ /* Maybe the notification is still pending. */
+ ev_postpone(&l->event);
+
+ /* Get new lock candidate */
n = HEAD(l->waiters);
- if (n->next)
+ if (NODE_VALID(n))
{
- DBG("olock: -> %p becomes locked\n", n);
- q = SKIP_BACK(struct object_lock, n, n);
+ struct object_lock *q = SKIP_BACK(struct object_lock, n, n);
+
+ /* Remove this candidate from waiters list */
rem_node(n);
+
+ /* Move waiter lists */
+ DBG("olock: -> %p becomes locked\n", n);
add_tail_list(&q->waiters, &l->waiters);
- q->state = OLOCK_STATE_EVENT;
+
+ /* Add the new olock to olock_list */
add_head(&olock_list, n);
- ev_schedule(olock_event);
+
+ /* Inform */
+ q->state = OLOCK_STATE_LOCKED;
+ ev_send(q->target, &q->event);
}
break;
case OLOCK_STATE_WAITING:
+ /* Remove from the waiters list */
rem_node(&l->n);
break;
default:
ASSERT(0);
}
+ OBJ_UNLOCK;
}
static void
@@ -140,6 +161,8 @@ olock_acquire(struct object_lock *l)
node *n;
struct object_lock *q;
+ OBJ_LOCK;
+
WALK_LIST(n, olock_list)
{
q = SKIP_BACK(struct object_lock, n, n);
@@ -148,36 +171,19 @@ olock_acquire(struct object_lock *l)
l->state = OLOCK_STATE_WAITING;
add_tail(&q->waiters, &l->n);
DBG("olock: %p waits\n", l);
+
+ OBJ_UNLOCK;
return;
}
}
+
DBG("olock: %p acquired immediately\n", l);
- l->state = OLOCK_STATE_EVENT;
add_head(&olock_list, &l->n);
- ev_schedule(olock_event);
-}
-static void
-olock_run_event(void *unused UNUSED)
-{
- node *n;
- struct object_lock *q;
+ l->state = OLOCK_STATE_LOCKED;
+ ev_send(l->target, &l->event);
- DBG("olock: Processing events\n");
- for(;;)
- {
- n = HEAD(olock_list);
- if (!n->next)
- break;
- q = SKIP_BACK(struct object_lock, n, n);
- if (q->state != OLOCK_STATE_EVENT)
- break;
- DBG("olock: %p locked\n", q);
- q->state = OLOCK_STATE_LOCKED;
- rem_node(&q->n);
- add_tail(&olock_list, &q->n);
- q->hook(q);
- }
+ OBJ_UNLOCK;
}
/**
@@ -191,5 +197,5 @@ olock_init(void)
{
DBG("olock: init\n");
init_list(&olock_list);
- olock_event = ev_new_init(&root_pool, olock_run_event, NULL);
+ olock_domain = DOMAIN_NEW(attrs, "Object lock");
}