forked from ElementsProject/lightning
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathio_lock.c
87 lines (77 loc) · 2.17 KB
/
io_lock.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include "io_lock.h"
#include <assert.h>
#include <ccan/io/io_plan.h>
struct io_lock {
bool locked;
};
/* Struct to hold information while we wait for the lock to be freed */
struct io_lock_waiter {
struct io_plan *(*next)(struct io_conn *conn, void *next_arg);
void *arg;
struct io_lock *lock;
enum io_direction dir;
};
struct io_lock *io_lock_new(const tal_t *ctx)
{
struct io_lock *lock = tal(ctx, struct io_lock);
lock->locked = false;
return lock;
}
static struct io_plan *io_lock_try_acquire(struct io_conn *conn,
struct io_lock_waiter *waiter)
{
/* Destructure waiter, since we might be freeing it below */
struct io_plan *(*next)(struct io_conn *, void *) = waiter->next;
void *next_arg = waiter->arg;
if (!waiter->lock->locked) {
waiter->lock->locked = true;
tal_free(waiter);
return next(conn, next_arg);
} else {
switch (waiter->dir) {
case IO_IN:
return io_wait(conn, waiter->lock, io_lock_try_acquire,
waiter);
case IO_OUT:
return io_out_wait(conn, waiter->lock,
io_lock_try_acquire, waiter);
}
/* Should not happen if waiter->dir is a valid enum
* value */
abort();
}
}
static struct io_plan *io_lock_acquire_dir(
struct io_conn *conn, struct io_lock *lock, enum io_direction dir,
struct io_plan *(*next)(struct io_conn *, void *), void *arg)
{
/* FIXME: We can avoid one allocation if we lock and call next here directly */
struct io_lock_waiter *waiter = tal(lock, struct io_lock_waiter);
waiter->next = next;
waiter->arg = arg;
waiter->lock = lock;
waiter->dir = dir;
return io_lock_try_acquire(conn, waiter);
}
struct io_plan *
io_lock_acquire_out_(struct io_conn *conn, struct io_lock *lock,
struct io_plan *(*next)(struct io_conn *, void *), void *arg)
{
return io_lock_acquire_dir(conn, lock, IO_OUT, next, arg);
}
struct io_plan *
io_lock_acquire_in_(struct io_conn *conn, struct io_lock *lock,
struct io_plan *(*next)(struct io_conn *, void *), void *arg)
{
return io_lock_acquire_dir(conn, lock, IO_IN, next, arg);
}
void io_lock_release(struct io_lock *lock)
{
assert(lock->locked);
lock->locked = false;
io_wake(lock);
}
bool io_lock_taken(const struct io_lock *lock)
{
return lock->locked;
}