summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2017-08-31 23:17:47 +0200
committerRichard Braun <rbraun@sceen.net>2017-08-31 23:17:47 +0200
commitb9ec5cca6f6e3fd571b2e534d36e2498e488164c (patch)
treeeb3053068ba3451e41d655f883a9fcee8efff238
parent4e0b9efa25b58f7fcaf485349f66bd694390080a (diff)
kern/timer: improve access synchronization
-rw-r--r--kern/timer.c7
-rw-r--r--kern/timer.h3
-rw-r--r--kern/timer_i.h26
3 files changed, 24 insertions, 12 deletions
diff --git a/kern/timer.c b/kern/timer.c
index 365b2fa4..ba148d5f 100644
--- a/kern/timer.c
+++ b/kern/timer.c
@@ -76,9 +76,6 @@ struct timer_bucket {
* The hash table bucket matching the last time member has already been
* processed, and the next periodic event resumes from the next bucket.
*
- * The cpu member is used to determine which lock serializes access to
- * the structure. It must be accessed atomically.
- *
* Locking order: interrupts -> timer_cpu_data.
*/
struct timer_cpu_data {
@@ -242,13 +239,13 @@ timer_set_canceled(struct timer *timer)
static void
timer_set_time(struct timer *timer, uint64_t ticks)
{
- timer->ticks = ticks;
+ atomic_store(&timer->ticks, ticks, ATOMIC_RELAXED);
}
static bool
timer_occurred(const struct timer *timer, uint64_t ref)
{
- return clock_time_occurred(timer->ticks, ref);
+ return clock_time_occurred(timer_get_time(timer), ref);
}
static uintptr_t
diff --git a/kern/timer.h b/kern/timer.h
index 46616686..a082c538 100644
--- a/kern/timer.h
+++ b/kern/timer.h
@@ -23,6 +23,7 @@
#include <stdint.h>
+#include <kern/atomic.h>
#include <kern/init.h>
/*
@@ -47,7 +48,7 @@ typedef void (*timer_fn_t)(struct timer *);
static inline uint64_t
timer_get_time(const struct timer *timer)
{
- return timer->ticks; /* TODO atomic */
+ return atomic_load(&timer->ticks, ATOMIC_RELAXED);
}
/*
diff --git a/kern/timer_i.h b/kern/timer_i.h
index 4ed01f22..40e97f1b 100644
--- a/kern/timer_i.h
+++ b/kern/timer_i.h
@@ -24,18 +24,32 @@
#include <kern/hlist.h>
#include <kern/work.h>
+/*
+ * Locking keys :
+ * (c) cpu_data
+ * (a) atomic
+ *
+ * (*) The ticks member represents the expiration date. It may be read without
+ * locking the timer, in which case it must be accessed atomically. It
+ * may only be updated when the timer is locked though, so reads at such
+ * times don't need to be atomic.
+ *
+ * (**) The cpu member is used to determine which lock serializes access to
+ * the structure. It must be accessed atomically, but updated while the
+ * timer is locked.
+ */
struct timer {
union {
- struct hlist_node node;
+ struct hlist_node node; /* (c) */
struct work work;
};
- uint64_t ticks;
+ uint64_t ticks; /* (c,a,*) */
timer_fn_t fn;
- unsigned int cpu;
- unsigned short state;
- unsigned short flags;
- struct thread *joiner;
+ unsigned int cpu; /* (c,a,**) */
+ unsigned short state; /* (c) */
+ unsigned short flags; /* (c) */
+ struct thread *joiner; /* (c) */
};
#endif /* _KERN_TIMER_I_H */