Moves resource requests to procdata (XCC)
[akaros.git] / kern / include / atomic.h
index 3825236..279daa2 100644 (file)
@@ -1,19 +1,85 @@
+/* Copyright (c) 2009-2011 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Kernel atomics and locking functions.
+ *
+ * The extern inline declarations are arch-dependent functions.  We do this
+ * so that each arch can either static inline or just have a regular function,
+ * whichever is appropriate. The actual implementation usually will be in
+ * arch/atomic.h (for inlines).
+ *
+ * The static inlines are defined farther down in the file (as always). */
+
 #ifndef ROS_KERN_ATOMIC_H
 #define ROS_KERN_ATOMIC_H
 
 #include <ros/common.h>
 #include <ros/atomic.h>
 #include <arch/mmu.h>
-#include <arch/atomic.h>
 #include <arch/arch.h>
 #include <assert.h>
 
-static inline void
-(SLOCK(0) spin_lock_irqsave)(spinlock_t RACY*SAFE lock);
-static inline void
-(SUNLOCK(0) spin_unlock_irqsave)(spinlock_t RACY*SAFE lock);
-static inline bool spin_lock_irq_enabled(spinlock_t *SAFE lock);
+/* Atomics */
+extern inline void atomic_init(atomic_t *number, long val);
+extern inline long atomic_read(atomic_t *number);
+extern inline void atomic_set(atomic_t *number, long val);
+extern inline void atomic_add(atomic_t *number, long val);
+extern inline void atomic_inc(atomic_t *number);
+extern inline void atomic_dec(atomic_t *number);
+extern inline long atomic_fetch_and_add(atomic_t *number, long val);
+extern inline void atomic_and(atomic_t *number, long mask);
+extern inline void atomic_or(atomic_t *number, long mask);
+extern inline long atomic_swap(atomic_t *addr, long val);
+extern inline bool atomic_cas(atomic_t *addr, long exp_val, long new_val);
+extern inline bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val);
+extern inline bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val,
+                                  uint32_t new_val);
+extern inline bool atomic_add_not_zero(atomic_t *number, long val);
+extern inline bool atomic_sub_and_test(atomic_t *number, long val);
+
+/* Spin locks */
+struct spinlock {
+       volatile uint32_t RACY rlock;
+#ifdef __CONFIG_SPINLOCK_DEBUG__
+       void *call_site;        
+       uint32_t calling_core;
+#endif
+};
+typedef struct spinlock spinlock_t;
+#define SPINLOCK_INITIALIZER {0}
+
+extern inline void spinlock_init(spinlock_t *lock);
+extern inline bool spin_locked(spinlock_t *lock);
+extern inline void spin_lock(spinlock_t *lock);
+extern inline void spin_unlock(spinlock_t *lock);
+extern inline void spinlock_debug(spinlock_t *lock);
 
+static inline void spin_lock_irqsave(spinlock_t *lock);
+static inline void spin_unlock_irqsave(spinlock_t *lock);
+static inline bool spin_lock_irq_enabled(spinlock_t *lock);
+
+/* Hash locks (array of spinlocks).  Most all users will want the default one,
+ * so point your pointer to one of them, though you could always kmalloc a
+ * bigger one.  In the future, they might be growable, etc, which init code may
+ * care about. */
+struct hashlock {
+       unsigned int            nr_entries;
+       struct spinlock         locks[];
+};
+#define HASHLOCK_DEFAULT_SZ 53         /* nice prime, might be a bit large */
+struct small_hashlock {
+       unsigned int            nr_entries;
+       struct spinlock         locks[HASHLOCK_DEFAULT_SZ];
+};
+
+void hashlock_init(struct hashlock *hl, unsigned int nr_entries);
+void hash_lock(struct hashlock *hl, long key);
+void hash_unlock(struct hashlock *hl, long key);
+void hash_lock_irqsave(struct hashlock *hl, long key);
+void hash_unlock_irqsave(struct hashlock *hl, long key);
+
+/* Seq locks */
 /* An example seq lock, built from the counter.  I don't particularly like this,
  * since it forces you to use a specific locking type.  */
 typedef struct seq_lock {
@@ -28,6 +94,21 @@ static inline void write_sequnlock(seqlock_t *lock);
 static inline seq_ctr_t read_seqbegin(seqlock_t *lock);
 static inline bool read_seqretry(seqlock_t *lock, seq_ctr_t ctr);
 
+/* Arch-specific implementations / declarations go here */
+#include <arch/atomic.h>
+
+#define MAX_SPINS 1000000000
+
+/* Will spin for a little while, but not deadlock if it never happens */
+#define spin_on(x)                                                             \
+       for (int i = 0; (x); i++) {                                                \
+               cpu_relax();                                                           \
+               if (i == MAX_SPINS) {                                                  \
+                       printk("Probably timed out/failed.\n");                            \
+                       break;                                                             \
+               }                                                                      \
+       }
+
 /*********************** Checklist stuff **********************/
 typedef struct checklist_mask {
        // only need an uint8_t, but we need the bits[] to be word aligned
@@ -129,6 +210,9 @@ static inline void __seq_start_write(seq_ctr_t *seq_ctr)
        assert(*seq_ctr % 2 == 0);
 #endif
        (*seq_ctr)++;
+       /* We're the only writer, so we need to prevent the compiler (and some
+        * arches) from reordering writes before this point. */
+       wmb();
 }
 
 static inline void __seq_end_write(seq_ctr_t *seq_ctr)
@@ -136,6 +220,9 @@ static inline void __seq_end_write(seq_ctr_t *seq_ctr)
 #ifdef _CONFIG_SEQLOCK_DEBUG_
        assert(*seq_ctr % 2 == 1);
 #endif
+       /* Need to prevent the compiler (and some arches) from reordering older
+        * stores */
+       wmb();
        (*seq_ctr)++;
 }
 
@@ -156,7 +243,9 @@ static inline void write_sequnlock(seqlock_t *lock)
 
 static inline seq_ctr_t read_seqbegin(seqlock_t *lock)
 {
-       return lock->r_ctr;
+       seq_ctr_t retval = lock->r_ctr;
+       rmb();  /* don't want future reads to come before our ctr read */
+       return retval;
 }
 
 static inline bool read_seqretry(seqlock_t *lock, seq_ctr_t ctr)
@@ -164,4 +253,4 @@ static inline bool read_seqretry(seqlock_t *lock, seq_ctr_t ctr)
        return seqctr_retry(lock->r_ctr, ctr);
 }
 
-#endif /* !ROS_KERN_ATOMIC_H */
+#endif /* ROS_KERN_ATOMIC_H */