Vcore states for preemption recovery (XCC)
[akaros.git] / kern / include / ros / ucq.h
1 /* Copyright (c) 2011 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Unbounded concurrent queues.  Linked buffers/arrays of elements, in page
6  * size chunks.  The pages/buffers are linked together by an info struct at the
7  * beginning of the page.  Producers and consumers sync on the idxes when
8  * operating in a page, and page swaps are synced via the proc* for the kernel
9  * and via the ucq's u_lock for the user. 
10  *
11  * There's a bunch of details and issues discussed in the Documentation.
12  *
13  * This header contains the stuff that the kernel and userspace need to agree
14  * on.  Each side of the implementation will have their own .c and .h files.
15  * The kernel's implementation is in kern/src/ucq.c, and the user's is in
16  * user/parlib/ucq.c. */
17
18 #ifndef ROS_INC_UCQ_H
19 #define ROS_INC_UCQ_H
20
21 #include <ros/common.h>
22 #include <ros/atomic.h>
23 #include <ros/arch/mmu.h>
24 /* #include <ros/event.h> included below */
25
26 /* The main UCQ structure, contains indexes and start points (for the indexes),
27  * etc. */
28 struct ucq {
29         atomic_t                                        prod_idx;               /* both pg and slot nr */
30         bool                                            prod_overflow;  /* flag to prevent wraparound */
31         atomic_t                                        spare_pg;               /* mmaped, unused page */
32         atomic_t                                        nr_extra_pgs;   /* nr pages mmaped */
33         atomic_t                                        cons_idx;               /* cons pg and slot nr */
34         bool                                            ucq_ready;              /* ucq is ready to be used */
35         /* Userspace lock for modifying the UCQ */
36         void                                            *u_lock[3];             /* sizeof an mcs_pdr_lock */
37 };
38
39 /* Struct at the beginning of every page/buffer, tracking consumers and
40  * pointing to the next one, so that the consumer can follow. */
41 struct ucq_page_header {
42         uintptr_t                                       cons_next_pg;   /* next page to consume */
43         atomic_t                                        nr_cons;                /* like an inverted refcnt */
44 };
45
46 /* Including here since event.h needs to know about struct ucq */
47 #include <ros/event.h>
48
49 struct msg_container {
50         struct event_msg                        ev_msg;
51         bool                                            ready;                  /* kernel has written */
52 };
53
54 struct ucq_page {
55         struct ucq_page_header          header;
56         struct msg_container            msgs[];
57 };
58
59 #define UCQ_WARN_THRESH                 1000                    /* nr pages befor warning */
60
61 #define NR_MSG_PER_PAGE ((PGSIZE - ROUNDUP(sizeof(struct ucq_page_header),     \
62                                            __alignof__(struct msg_container))) \
63                          / sizeof(struct msg_container))
64
65 /* A slot encodes both the page addr and the count within the page */
66 static bool slot_is_good(uintptr_t slot)
67 {
68         uintptr_t counter = PGOFF(slot);
69         uintptr_t pg_addr = PTE_ADDR(slot);
70         return ((counter < NR_MSG_PER_PAGE) && pg_addr) ? TRUE : FALSE;
71 }
72
73 /* Helper: converts a slot/index into a msg container.  The ucq_page is the
74  * PPN/PTE_ADDR of 'slot', and the specific slot *number* is the PGOFF.  Assumes
75  * the slot is good.  If it isn't, you're going to get random memory.
76  *
77  * Note that this doesn't actually read the memory, just computes an address. */
78 static inline struct msg_container *slot2msg(uintptr_t slot)
79 {
80         return &((struct ucq_page*)PTE_ADDR(slot))->msgs[PGOFF(slot)];
81 }
82
83 #endif /* ROS_INC_UCQ_H */