Added generic macro for running a function exactly once (XCC)
[akaros.git] / kern / include / ros / bcq.h
index 45402b8..71214d9 100644 (file)
@@ -9,7 +9,17 @@
 #ifndef ROS_INC_BCQ_H
 #define ROS_INC_BCQ_H
 
+#include <ros/common.h>
+#include <ros/bcq_struct.h>
+#include <string.h>
+
+/* Pain in the ass includes.  Glibc has an atomic.h, and eventually userspace
+ * will have to deal with the clobbering. */
+#ifdef ROS_KERNEL
 #include <atomic.h>
+#else
+#include <arch/atomic.h>
+#endif /* ROS_KERNEL */
 
 /* Bounded Concurrent Queues, untrusted consumer
  *
@@ -17,7 +27,7 @@
  * blocks and does not need to trust the data structure (which is writable by
  * the consumer).
  *
- * A producer enqueues and item, based on the indexes of the producer and
+ * A producer enqueues an item, based on the indexes of the producer and
  * consumer.  Enqueue cannot block, but can fail if the queue is full or if it
  * fails to enqueue after a certain amount of tries.
  *
@@ -69,6 +79,7 @@
  * bcq_enqueue(&some_bcq, &some_my_type, my_size, num_fails_okay);
  * bcq_dequeue(&some_bcq, &some_my_type, my_size);
  *
+ * They both return 0 on success, or some error code on failure.
  *
  * TODO later:
  * How about an atomic_add_return for the prod?  Now that we use powers of two,
  * Using uint32_t for now, since that's the comp_and_swap we have.  We'll
  * probably get other sizes once we're sure we like the current one.  */
 
+#if 0 // Defined in the included header
+
 struct bcq_header {
        uint32_t prod_idx;              /* next to be produced in */
        uint32_t cons_pub_idx;  /* last completely consumed */
        uint32_t cons_pvt_idx;  /* last a consumer has dibs on */
 };
 
-#define DEFINE_BCQ_TYPES(__name, __elem_t, __num_elems)                        \
-                                                                               \
-/* Wrapper, per element, with the consumption bool */                          \
-struct __name##_bcq_wrap {                                                     \
-       __elem_t elem;                                                             \
-       bool rdy_for_cons;      /* elem is ready for consumption */                    \
-};                                                                             \
-                                                                               \
-/* The actual BC queue */                                                      \
-struct __name##_bcq {                                                          \
-       struct bcq_header hdr;                                                     \
-       struct __name##_bcq_wrap wraps[__num_elems];                               \
-};                                                                             
-                                                                               
+// This is there too:
+#define DEFINE_BCQ_TYPES(__name, __elem_t, __num_elems)
+
+#endif
+
 /* Functions */                                                                
 #define bcq_init(_bcq, _ele_type, _num_elems)                                  \
        memset((_bcq), 0, sizeof( _ele_type ) * (_num_elems))                                 
@@ -129,6 +133,7 @@ struct __name##_bcq {                                                          \
        uint32_t __prod, __new_prod, __cons_pub, __failctr = 0;                    \
        int __retval = 0;                                                          \
        do {                                                                       \
+               cmb();                                                                 \
                if (((_num_fail)) && (__failctr++ >= (_num_fail))) {                   \
                        __retval = -EFAIL;                                                 \
                        break;                                                             \
@@ -140,7 +145,7 @@ struct __name##_bcq {                                                          \
                        break;                                                             \
                }                                                                      \
                __new_prod = __prod + 1;                                               \
-       } while (!atomic_comp_swap(&(_bcq)->hdr.prod_idx, __prod, __new_prod));    \
+       } while (!atomic_cas_u32(&(_bcq)->hdr.prod_idx, __prod, __new_prod));      \
        if (!__retval) {                                                           \
                /* from here out, __prod is the local __prod that we won */            \
                (_bcq)->wraps[__prod & ((_num_elems)-1)].elem = *(_elem);              \
@@ -156,6 +161,7 @@ struct __name##_bcq {                                                          \
        uint32_t __prod, __cons_pvt, __new_cons_pvt, __cons_pub;                   \
        int __retval = 0;                                                          \
        do {                                                                       \
+               cmb();                                                                 \
                __prod = (_bcq)->hdr.prod_idx;                                         \
                __cons_pvt = (_bcq)->hdr.cons_pvt_idx;                                 \
                if (BCQ_NO_WORK(__prod, __cons_pvt)) {                                 \
@@ -163,7 +169,7 @@ struct __name##_bcq {                                                          \
                        break;                                                             \
                }                                                                      \
                __new_cons_pvt = (__cons_pvt + 1);                                     \
-       } while (!atomic_comp_swap(&(_bcq)->hdr.cons_pvt_idx, __cons_pvt,          \
+       } while (!atomic_cas_u32(&(_bcq)->hdr.cons_pvt_idx, __cons_pvt,            \
                                   __new_cons_pvt));                               \
        if (!__retval) {                                                           \
                /* from here out, __cons_pvt is the local __cons_pvt that we won */    \
@@ -180,66 +186,8 @@ struct __name##_bcq {                                                          \
        __retval;                                                                  \
 })
 
-#if 0
-/* Original C Code, for posterity / debugging */
-static inline int enqueue(struct __name_bcq *bcq, __elem_t *elem,
-                          int num_fail)
-{
-       uint32_t __prod, __new_prod, __cons_pub, __failctr = 0;
-       do {
-               if ((num_fail) && (__failctr++ >= num_fail)) {
-                       printk("FAILED\n");
-                       return -EFAIL;
-               }
-               __prod = bcq->hdr.prod_idx;
-               __cons_pub = bcq->hdr.cons_pub_idx;
-       printk("# free slots : %d\n", BCQ_FREE_SLOTS(__prod, __cons_pub, __num_elems));
-
-//             printk("__prod = %p, cons_pub = %p\n", __prod, __cons_pub-1);
-//             printk("__prod mod = %p, cons_pub mod = %p\n", __prod &(__num_elems-1), (__cons_pub-1) &(__num_elems-1));
-
-               if (BCQ_FULL(__prod, __cons_pub, __num_elems)) {
-                       printk("BUSY\n");
-                       return -EBUSY;
-               }
-               __new_prod = __prod + 1;
-       } while (!atomic_comp_swap(&bcq->hdr.prod_idx, __prod, __new_prod));
-       /* from here out, __prod is the local __prod that we won */
-
-       printk("enqueuing to location %d\n", __prod & (__num_elems-1));
-
-       bcq->wraps[__prod & (__num_elems-1)].elem = *elem;
-       bcq->wraps[__prod & (__num_elems-1)].rdy_for_cons = TRUE;
-       return 0;
-}
-
-/* Similar to enqueue, spin afterwards til cons_pub is our element, then */
-/* advance it. */
-static inline int dequeue(struct __name_bcq *bcq, __elem_t *elem)
-{
-       uint32_t __prod, __cons_pvt, __new_cons_pvt, __cons_pub;
-       do {
-               __prod = bcq->hdr.prod_idx;
-               __cons_pvt = bcq->hdr.cons_pvt_idx;
-               if (BCQ_NO_WORK(__prod, __cons_pvt))
-                       return -EBUSY;
-               __new_cons_pvt = (__cons_pvt + 1);
-       } while (!atomic_comp_swap(&bcq->hdr.cons_pvt_idx, __cons_pvt,
-                                  __new_cons_pvt));
-       /* from here out, __cons_pvt is the local __cons_pvt that we won */
-       printk("dequeueing from location %d\n", __cons_pvt & (__num_elems-1));
-
-       /* wait for the producer to finish copying it in */
-       while (!bcq->wraps[__cons_pvt & (__num_elems-1)].rdy_for_cons)
-               cpu_relax();
-       *elem = bcq->wraps[__cons_pvt & (__num_elems-1)].elem;
-       bcq->wraps[__cons_pvt & (__num_elems-1)].rdy_for_cons = FALSE;
-       /* wait til we're the cons_pub, then advance it by one */
-       while (bcq->hdr.cons_pub_idx != __cons_pvt)
-               cpu_relax();
-       bcq->hdr.cons_pub_idx = __cons_pvt + 1;
-       return 0;
-}
-#endif
+/* Checks of a bcq is empty (meaning no work), instead of trying to dequeue */
+#define bcq_empty(_bcq)                                                        \
+       BCQ_NO_WORK((_bcq)->hdr.prod_idx, (_bcq)->hdr.cons_pvt_idx)
 
-#endif /* !ROS_INC_BCQ_H */
+#endif /* ROS_INC_BCQ_H */