|  | /* Copyright (c) 2011 The Regents of the University of California | 
|  | * Barret Rhoden <brho@cs.berkeley.edu> | 
|  | * See LICENSE for details. | 
|  | * | 
|  | * Unbounded concurrent queues.  Linked buffers/arrays of elements, in page | 
|  | * size chunks.  The pages/buffers are linked together by an info struct at the | 
|  | * beginning of the page.  Producers and consumers sync on the idxes when | 
|  | * operating in a page, and page swaps are synced via the proc* for the kernel | 
|  | * and via the ucq's u_lock for the user. | 
|  | * | 
|  | * There's a bunch of details and issues discussed in the Documentation. | 
|  | * | 
|  | * This header contains the stuff that the kernel and userspace need to agree | 
|  | * on.  Each side of the implementation will have their own .c and .h files. | 
|  | * The kernel's implementation is in kern/src/ucq.c, and the user's is in | 
|  | * user/parlib/ucq.c. */ | 
|  |  | 
|  | #pragma once | 
|  |  | 
|  | #include <ros/bits/event.h> | 
|  | #include <ros/atomic.h> | 
|  | #include <ros/arch/mmu.h> | 
|  |  | 
|  | #ifdef ROS_KERNEL | 
|  | #include <arch/arch.h> | 
|  | #else | 
|  | #include <parlib/arch/arch.h> | 
|  | #endif | 
|  |  | 
|  | /* #include <ros/event.h> included below */ | 
|  |  | 
|  | /* The main UCQ structure, contains indexes and start points (for the indexes), | 
|  | * etc. */ | 
|  | struct ucq { | 
|  | atomic_t			prod_idx;     /* both pg and slot nr */ | 
|  | atomic_t			spare_pg;     /* mmaped, unused page */ | 
|  | atomic_t			nr_extra_pgs; /* nr pages mmaped */ | 
|  | atomic_t			cons_idx;     /* cons pg and slot nr */ | 
|  | bool				prod_overflow;/* prevent wraparound */ | 
|  | bool				ucq_ready; | 
|  | /* Userspace lock for modifying the UCQ */ | 
|  | uint32_t			u_lock[2]; | 
|  | }; | 
|  |  | 
|  | /* Struct at the beginning of every page/buffer, tracking consumers and | 
|  | * pointing to the next one, so that the consumer can follow. */ | 
|  | struct ucq_page_header { | 
|  | uintptr_t			cons_next_pg; /* next page to consume */ | 
|  | atomic_t 			nr_cons; /* like an inverted refcnt */ | 
|  | }; | 
|  |  | 
|  | struct msg_container { | 
|  | struct event_msg		ev_msg; | 
|  | bool				ready; | 
|  | }; | 
|  |  | 
|  | struct ucq_page { | 
|  | struct ucq_page_header		header; | 
|  | struct msg_container		msgs[]; | 
|  | }; | 
|  |  | 
|  | #define UCQ_WARN_THRESH		1000		/* nr pages befor warning */ | 
|  |  | 
|  | #define NR_MSG_PER_PAGE ((PGSIZE - ROUNDUP(sizeof(struct ucq_page_header),     \ | 
|  | __alignof__(struct msg_container))) \ | 
|  | / sizeof(struct msg_container)) | 
|  |  | 
|  | /* A slot encodes both the page addr and the count within the page */ | 
|  | static bool slot_is_good(uintptr_t slot) | 
|  | { | 
|  | uintptr_t counter = PGOFF(slot); | 
|  | uintptr_t pg_addr = PTE_ADDR(slot); | 
|  |  | 
|  | return ((counter < NR_MSG_PER_PAGE) && pg_addr) ? TRUE : FALSE; | 
|  | } | 
|  |  | 
|  | /* Helper: converts a slot/index into a msg container.  The ucq_page is the | 
|  | * PPN/PTE_ADDR of 'slot', and the specific slot *number* is the PGOFF.  Assumes | 
|  | * the slot is good.  If it isn't, you're going to get random memory. | 
|  | * | 
|  | * Note that this doesn't actually read the memory, just computes an address. */ | 
|  | static inline struct msg_container *slot2msg(uintptr_t slot) | 
|  | { | 
|  | return &((struct ucq_page*)PTE_ADDR(slot))->msgs[PGOFF(slot)]; | 
|  | } |