Updated GETTING_STARTED with busybox info
[akaros.git] / kern / include / atomic.h
index 0f1094b..dbe2c68 100644 (file)
@@ -41,20 +41,65 @@ 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;        
+#ifdef CONFIG_SPINLOCK_DEBUG
+       uintptr_t call_site;
        uint32_t calling_core;
+       bool irq_okay;
 #endif
 };
 typedef struct spinlock spinlock_t;
 #define SPINLOCK_INITIALIZER {0}
 
-extern inline void spinlock_init(spinlock_t *lock);
+#ifdef CONFIG_SPINLOCK_DEBUG
+#define SPINLOCK_INITIALIZER_IRQSAVE {0, .irq_okay = TRUE}
+#else
+#define SPINLOCK_INITIALIZER_IRQSAVE SPINLOCK_INITIALIZER
+#endif
+
+/* Arch dependent helpers/funcs: */
+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);
+extern inline void __spin_lock(spinlock_t *lock);
+extern inline void __spin_unlock(spinlock_t *lock);
+
+/* So we can inline a __spin_lock if we want.  Even though we don't need this
+ * if we're debugging, its helpful to keep the include at the same place for
+ * all builds. */
+#include <arch/atomic.h>
+
+#ifdef CONFIG_SPINLOCK_DEBUG
+/* Arch indep, in k/s/atomic.c */
+void spin_lock(spinlock_t *lock);
+bool spin_trylock(spinlock_t *lock);
+void spin_unlock(spinlock_t *lock);
+void spinlock_debug(spinlock_t *lock);
+
+#else
+/* Just inline the arch-specific __ versions */
+static inline void spin_lock(spinlock_t *lock)
+{
+       __spin_lock(lock);
+}
 
+static inline bool spin_trylock(spinlock_t *lock)
+{
+       return __spin_trylock(lock);
+}
+
+static inline void spin_unlock(spinlock_t *lock)
+{
+       __spin_unlock(lock);
+}
+
+static inline void spinlock_debug(spinlock_t *lock)
+{
+}
+
+#endif /* CONFIG_SPINLOCK_DEBUG */
+
+/* Inlines, defined below */
+static inline void spinlock_init(spinlock_t *lock);
+static inline void spinlock_init_irqsave(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);
@@ -74,6 +119,7 @@ struct small_hashlock {
 };
 
 void hashlock_init(struct hashlock *hl, unsigned int nr_entries);
+void hashlock_init_irqsave(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);
@@ -94,6 +140,23 @@ 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);
 
+/* Post work and poke synchronization.  This is a wait-free way to make sure
+ * some code is run, usually by the calling core, but potentially by any core.
+ * Under contention, everyone just posts work, and one core will carry out the
+ * work.  Callers post work (the meaning of which is particular to their
+ * subsystem), then call this function.  The function is not run concurrently
+ * with itself.
+ *
+ * In the future, this may send RKMs to LL cores to ensure the work is done
+ * somewhere, but not necessarily on the calling core.  Will reserve 'flags'
+ * for that. */
+struct poke_tracker {
+       atomic_t                        need_to_run;
+       atomic_t                        run_in_progress;
+       void                            (*func)(void *);
+};
+void poke(struct poke_tracker *tracker, void *arg);
+
 /* Arch-specific implementations / declarations go here */
 #include <arch/atomic.h>
 
@@ -128,7 +191,8 @@ typedef struct checklist RACY checklist_t;
 #define ZEROS_ARRAY(size) {[0 ... ((size)-1)] 0}
 
 #define DEFAULT_CHECKLIST_MASK(sz) {(sz), ZEROS_ARRAY(BYTES_FOR_BITMASK(sz))}
-#define DEFAULT_CHECKLIST(sz) {SPINLOCK_INITIALIZER, DEFAULT_CHECKLIST_MASK(sz)}
+#define DEFAULT_CHECKLIST(sz) {SPINLOCK_INITIALIZER_IRQSAVE,                   \
+                               DEFAULT_CHECKLIST_MASK(sz)}
 #define INIT_CHECKLIST(nm, sz) \
        checklist_t nm = DEFAULT_CHECKLIST(sz);
 #define INIT_CHECKLIST_MASK(nm, sz)    \
@@ -170,6 +234,26 @@ void waiton_barrier(barrier_t* barrier);
 /* Spinlock bit flags */
 #define SPINLOCK_IRQ_EN                        0x80000000
 
+static inline void spinlock_init(spinlock_t *lock)
+{
+       __spinlock_init(lock);
+#ifdef CONFIG_SPINLOCK_DEBUG
+       lock->call_site = 0;
+       lock->calling_core = 0;
+       lock->irq_okay = FALSE;
+#endif
+}
+
+static inline void spinlock_init_irqsave(spinlock_t *lock)
+{
+       __spinlock_init(lock);
+#ifdef CONFIG_SPINLOCK_DEBUG
+       lock->call_site = 0;
+       lock->calling_core = 0;
+       lock->irq_okay = TRUE;
+#endif
+}
+
 // If ints are enabled, disable them and note it in the top bit of the lock
 // There is an assumption about releasing locks in order here...
 static inline void spin_lock_irqsave(spinlock_t *SAFE lock)
@@ -206,7 +290,7 @@ static inline bool spin_lock_irq_enabled(spinlock_t *SAFE lock)
  * concurrent write. */
 static inline void __seq_start_write(seq_ctr_t *seq_ctr)
 {
-#ifdef _CONFIG_SEQLOCK_DEBUG_
+#ifdef CONFIG_SEQLOCK_DEBUG
        assert(*seq_ctr % 2 == 0);
 #endif
        (*seq_ctr)++;
@@ -217,7 +301,7 @@ static inline void __seq_start_write(seq_ctr_t *seq_ctr)
 
 static inline void __seq_end_write(seq_ctr_t *seq_ctr)
 {
-#ifdef _CONFIG_SEQLOCK_DEBUG_
+#ifdef CONFIG_SEQLOCK_DEBUG
        assert(*seq_ctr % 2 == 1);
 #endif
        /* Need to prevent the compiler (and some arches) from reordering older
@@ -243,7 +327,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)