Add READ_ONCE and WRITE_ONCE (XCC)
[akaros.git] / kern / include / ros / ring_buffer.h
index 6c01406..76288da 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  * ring.h
- * 
+ *
  * Shared producer-consumer ring macros.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * Tim Deegan and Andrew Warfield November 2004.
  */
 
-#ifndef ROS_INC_RING_BUFFER_H
-#define ROS_INC_RING_BUFFER_H
-
+#pragma once
 #include <string.h>
-#include <arch/atomic.h>
+#include <ros/arch/membar.h>
 
 #define xen_mb()  mb()
 #define xen_rmb() rmb()
 #define xen_wmb() wmb()
 
+/* Helpers for generic power-of-2 ring buffers */
+#define __ring_nr_empty(sz, prod, cons) ((sz) - ((prod) - (cons)))
+#define __ring_empty(prod, cons) ((prod) == (cons))
+#define __ring_nr_full(prod, cons) ((prod) - (cons))
+#define __ring_full(sz, prod, cons) (__ring_nr_empty((sz), (prod), (cons)) == 0)
+
 typedef unsigned int RING_IDX;
 
 /* Round a 32-bit unsigned constant down to the nearest power of two. */
@@ -43,68 +47,38 @@ typedef unsigned int RING_IDX;
 #define __RD16(_x) (((_x) & 0x0000ff00UL) ? __RD8((_x)>>8)<<8    : __RD8(_x))
 #define __RD32(_x) (((_x) & 0xffff0000UL) ? __RD16((_x)>>16)<<16 : __RD16(_x))
 
-/* Statically assert that two values are in fact equal.
- * It works by enducing a compil error from a duplicate case in a switch 
- * statement if the assertion is false.
- */
-#define __ASSERT_EQUAL(x, y) \
-       switch ((x) == (y)) case 0: case ((x) == (y)):
-
 /*
  * Calculate size of a shared ring, given the total available space for the
  * ring and indexes (_sz), and the name tag of the request/response structure.
- * A ring contains as many entries as will fit, rounded down to the nearest 
+ * A ring contains as many entries as will fit, rounded down to the nearest
  * power of two (so we can mask with (size-1) to loop around).
- * This tells us how many elements the ring _s can contain, given _sz space.
- */
-#define __RING_SIZE(_s, _sz) \
-    __RING_SIZE_BYTES(_s, _sz) / sizeof((_s)->ring[0])
-
-/*
- * This is the same as above, except in terms of bytes instead of elements
  */
-#define __RING_SIZE_BYTES(_s, _sz) \
-    (__RD32((_sz) - (long)(_s)->ring + (long)(_s)))
-
+#define __CONST_RING_SIZE(_s, _sz) \
+    (__RD32(((_sz) - offsetof(struct _s##_sring, ring)) / \
+           sizeof(((struct _s##_sring *)0)->ring[0])))
 /*
- * These two are the same as above except that they rely on type information
- * to determine the sizes statically, rather than the runtime instantiation
- * of the ring buffer variable
+ * The same for passing in an actual pointer instead of a name tag.
  */
-#define __RING_SIZE_STATIC(__name, _sz) \
-    (__RING_SIZE_BYTES_STATIC(_sz) / sizeof(union __name##_sring_entry))
-
-#define __RING_SIZE_BYTES_STATIC(_sz) \
-    (__RD32((_sz) - __RING_HEADER_SIZE()))
+#define __RING_SIZE(_s, _sz) \
+    (__RD32(((_sz) - (long)(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0])))
 
 /*
  * Macros to make the correct C datatypes for a new kind of ring.
- * 
+ *
  * To make a new ring datatype, you need to have two message structures,
  * let's say request_t, and response_t already defined.
  *
  * In a header where you want the ring datatype declared, you then do:
  *
  *     DEFINE_RING_TYPES(mytag, request_t, response_t);
- * or
- *     DEFINE_RING_TYPES_WITH_SIZE(mytag, request_t, response_t, size);
  *
- * Both macros expand out to give you a set of types, as you can see below.
+ * These expand out to give you a set of types, as you can see below.
  * The most important of these are:
- * 
+ *
  *     mytag_sring_t      - The shared ring.
  *     mytag_front_ring_t - The 'front' half of the ring.
  *     mytag_back_ring_t  - The 'back' half of the ring.
  *
- * The first of these macros will only declare a single element array to 
- * represent the ring buffer in the shared ring struct that is ultimately
- * created.  
- *
- * The second macro actually statically declares space of size (size) inside
- * the shared ring struct. This size is rounded down to the nearest power of 2
- * and space is subtracted off to account for holding any necessary ring 
- * buffer headers.
- *
  * To initialize a ring in your code you need to know the location and size
  * of the shared memory area (PAGE_SIZE, for instance). To initialise
  * the front half:
@@ -118,37 +92,31 @@ typedef unsigned int RING_IDX;
  *
  *     mytag_back_ring_t back_ring;
  *     BACK_RING_INIT(&back_ring, (mytag_sring_t *)shared_page, PAGE_SIZE);
- *
- * If you use the second of the two macros when first defining your ring 
- * structures, then the size you use when initializing your front and back 
- * rings *should* match the size you passed into this macro (e.g. PAGE_SIZE
- * in this example).
  */
 
-#define __RING_HEADER()                                                 \
-    RING_IDX req_prod, req_event;                                       \
-    RING_IDX rsp_prod, rsp_event;                                       \
-    uint8_t  pad[48];
-    
-#define __RING_HEADER_SIZE() \
-    (sizeof(struct {__RING_HEADER()} ))
-
 #define DEFINE_RING_TYPES(__name, __req_t, __rsp_t)                     \
-       DEFINE_RING_TYPES_WITH_SIZE(__name, __req_t, __rsp_t,               \
-                                   __RING_HEADER_SIZE() + 1)
-
-#define DEFINE_RING_TYPES_WITH_SIZE(__name, __req_t, __rsp_t, __size)   \
                                                                         \
 /* Shared ring entry */                                                 \
 union __name##_sring_entry {                                            \
     __req_t req;                                                        \
     __rsp_t rsp;                                                        \
-} TRUSTED;                                                              \
+};                                                                      \
                                                                         \
 /* Shared ring page */                                                  \
 struct __name##_sring {                                                 \
-       __RING_HEADER()                                                     \
-    union __name##_sring_entry ring[__RING_SIZE_STATIC(__name, __size)];\
+    RING_IDX req_prod, req_event;                                       \
+    RING_IDX rsp_prod, rsp_event;                                       \
+    union {                                                             \
+        struct {                                                        \
+            uint8_t smartpoll_active;                                   \
+        } netif;                                                        \
+        struct {                                                        \
+            uint8_t msg;                                                \
+        } tapif_user;                                                   \
+        uint8_t pvt_pad[4];                                             \
+    } priv;                                                             \
+    uint8_t __pad[44];                                                  \
+    union __name##_sring_entry ring[1]; /* variable-length */           \
 };                                                                      \
                                                                         \
 /* "Front" end's private variables */                                   \
@@ -170,33 +138,19 @@ struct __name##_back_ring {                                             \
 /* Syntactic sugar */                                                   \
 typedef struct __name##_sring __name##_sring_t;                         \
 typedef struct __name##_front_ring __name##_front_ring_t;               \
-typedef struct __name##_back_ring __name##_back_ring_t;                 \
-                                                                        \
-/* This is a dummy function just used to statically assert that         \
- * there are no weird padding issues associated with our sring structs  \
- */                                                                     \
-static void __name##_assert_sring_size() __attribute__((used));         \
-static void __name##_assert_sring_size() {                              \
-       __ASSERT_EQUAL( sizeof(__name##_sring_t),                           \
-                       ( __RING_HEADER_SIZE()  +                           \
-                         ( __RING_SIZE_STATIC(__name, __size) *            \
-                           sizeof(union __name##_sring_entry)              \
-                         )                                                 \
-                       )                                                   \
-                     );                                                    \
-}              
+typedef struct __name##_back_ring __name##_back_ring_t
 
 /*
  * Macros for manipulating rings.
- * 
- * FRONT_RING_whatever works on the "front end" of a ring: here 
+ *
+ * FRONT_RING_whatever works on the "front end" of a ring: here
  * requests are pushed on to the ring and responses taken off it.
- * 
- * BACK_RING_whatever works on the "back end" of a ring: here 
+ *
+ * BACK_RING_whatever works on the "back end" of a ring: here
  * requests are taken off the ring and responses put on.
- * 
- * N.B. these macros do NO INTERLOCKS OR FLOW CONTROL. 
- * This is OK in 1-for-1 request-response situations where the 
+ *
+ * N.B. these macros do NO INTERLOCKS OR FLOW CONTROL.
+ * This is OK in 1-for-1 request-response situations where the
  * requestor (front end) never has more than RING_SIZE()-1
  * outstanding requests.
  */
@@ -205,7 +159,8 @@ static void __name##_assert_sring_size() {                              \
 #define SHARED_RING_INIT(_s) do {                                       \
     (_s)->req_prod  = (_s)->rsp_prod  = 0;                              \
     (_s)->req_event = (_s)->rsp_event = 1;                              \
-    (void)memset((_s)->pad, 0, sizeof((_s)->pad));                      \
+    (void)memset((_s)->priv.pvt_pad, 0, sizeof((_s)->priv.pvt_pad));    \
+    (void)memset((_s)->__pad, 0, sizeof((_s)->__pad));                  \
 } while(0)
 
 #define FRONT_RING_INIT(_r, _s, __size) do {                            \
@@ -294,26 +249,26 @@ static void __name##_assert_sring_size() {                              \
 
 /*
  * Notification hold-off (req_event and rsp_event):
- * 
+ *
  * When queueing requests or responses on a shared ring, it may not always be
  * necessary to notify the remote end. For example, if requests are in flight
  * in a backend, the front may be able to queue further requests without
  * notifying the back (if the back checks for new requests when it queues
  * responses).
- * 
+ *
  * When enqueuing requests or responses:
- * 
+ *
  *  Use RING_PUSH_{REQUESTS,RESPONSES}_AND_CHECK_NOTIFY(). The second argument
  *  is a boolean return value. True indicates that the receiver requires an
  *  asynchronous notification.
- * 
+ *
  * After dequeuing requests or responses (before sleeping the connection):
- * 
+ *
  *  Use RING_FINAL_CHECK_FOR_REQUESTS() or RING_FINAL_CHECK_FOR_RESPONSES().
  *  The second argument is a boolean return value. True indicates that there
  *  are pending messages on the ring (i.e., the connection should not be put
  *  to sleep).
- * 
+ *
  *  These macros will set the req_event/rsp_event field to trigger a
  *  notification on the very next message that is enqueued. If you want to
  *  create batches of work (i.e., only receive a notification after several
@@ -358,8 +313,6 @@ static void __name##_assert_sring_size() {                              \
     (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r);                  \
 } while (0)
 
-#endif /* ROS_INC_RING_BUFFER_H */
-
 /*
  * Local variables:
  * mode: C
@@ -369,4 +322,3 @@ static void __name##_assert_sring_size() {                              \
  * indent-tabs-mode: nil
  * End:
  */
-