-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Libsharedringbuffer #15
base: master
Are you sure you want to change the base?
Conversation
c8a42ed
to
d0c0327
Compare
libsharedringbuffer/include/shared_ringbuffer/shared_ringbuffer.h
Outdated
Show resolved
Hide resolved
|
||
*addr = ring->buffers[ring->read_idx % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT].encoded_addr; | ||
*len = ring->buffers[ring->read_idx % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT].len; | ||
*cookie = &ring->buffers[ring->read_idx % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*cookie = &ring->buffers[ring->read_idx % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT]; | |
*cookie = &ring->buffers[ring->read_idx % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT].cookie; |
static int driver_dequeue(ring_buffer_t *ring, uintptr_t *addr, unsigned int *len, void **cookie) | ||
{ | ||
if (!((ring->write_idx - ring->read_idx) % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT)) { | ||
ZF_LOGW("write idx = %d, read idx = %d", ring->write_idx, ring->read_idx); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be a debug log printed afterwards (to have the context when reading the logs) or just merge into the next log.
libsharedringbuffer/CMakeLists.txt
Outdated
# Copyright 2022, Trustworthy Systems, UNSW | ||
# | ||
# Copyright 2022, UNSW (ABN 57 195 873 179) | ||
# SPDX-License-Identifier: BSD-3-Clause |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I gave you the wrong one on the chat, it should be BSD-2-Clause for these
libsharedringbuffer/README.md
Outdated
@@ -1,5 +1,6 @@ | |||
<!-- | |||
Copyright ? | |||
Copyright 2022, UNSW (ABN 57 195 873 179) | |||
SPDX-License-Identifier: BSD-3-Clause |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
READMEs and docs are CC-BY-SA-4.0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay thanks, I fixed this up
Hi @lucypa, the content looks fine from my side, but I will leave a deeper review of that to systems people. There is something slightly strange in the commit sequence of the PR, it seems to contain commits that are already on the master branch. Might just need a rebase. Most of the commits in this PR should be squashed into fewer larger commits (X update, style, etc). The commits should be single logical units and ideally go from a working/compilable code state to working/compilable code state, so that git bisect can be used to find issues later. See also the git conventions and git style guide. The link check is failing, but is fine to ignore for this PR (the failure is unrelated) |
/* Buffer descriptor */ | ||
typedef struct buff_desc { | ||
uintptr_t encoded_addr; /* encoded dma addresses */ | ||
unsigned int len; /* associated memory lengths */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use size_t
here, so it scales with the architecture. Unless there is a strong reason to fix the structure size across architectures.
|
||
/* Circular buffer containing descriptors */ | ||
typedef struct ring_buffer { | ||
uint32_t write_idx; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be size_t
also and not fix is to 32-bit (even is 32-bit might be practically sufficient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought that size_t would be reserved for lengths/sizes of things. This is just an index into the array
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For portable code, my rule of thumb usually is, that it's either unsigned int
(as C's native integer) or size_t
(to support the maximum range, which might be more than unsigned int
covers) then. If specific fix-size types are used, this should have a good reason or some explanation that we want to ensure something - but this would also become compile time asserts then.
When it comes to structures, a reason might be that the structure's memory layout is important because it get's serialized/deserialized and thus has to work across different architectures.
#include <shared_ringbuffer/gen_config.h> | ||
|
||
/* Function pointer to be used to 'notify' components on either end of the shared memory */ | ||
typedef void (*notify_fn)(void); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this get a context parameter for convenience reasons?
return -1; | ||
} | ||
|
||
ring->buffers[ring->write_idx % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT].encoded_addr = buffer; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could the code redundancy a bit (even if the compiler might optimize this anyway)
buff_desc_t *buff_desc = &(ring->buffers[ring->write_idx % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT]);
buff_desc->encoded_addr = buffer
buff_desc->len = len;
buff_desc->cookie = cookie;
return -1; | ||
} | ||
|
||
*addr = ring->buffers[ring->read_idx % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT].encoded_addr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
buff_desc_t *buff_desc = &(ring->buffers[ring->read_idx % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT]);
*addr = buff_desc->encoded_addr;
...
|
||
/* Buffer descriptor */ | ||
typedef struct buff_desc { | ||
uintptr_t encoded_addr; /* encoded dma addresses */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, this is agnostic of what this memory is. IN the end, this could also be a void*
in the end.
*/ | ||
static inline int ring_empty(ring_buffer_t *ring) | ||
{ | ||
return !((ring->write_idx - ring->read_idx) % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we have the modulo operation here? Isn't this simply:
return (ring->write_idx == ring->read_idx);
* | ||
* @return true indicates the buffer is empty, false otherwise. | ||
*/ | ||
static inline int ring_empty(ring_buffer_t *ring) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't the a bool type also that we could use here?
*/ | ||
static inline int ring_full(ring_buffer_t *ring) | ||
{ | ||
return !((ring->write_idx - ring->read_idx + 1) % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sam here, why the modulo operation, this will even work for overflows:
return CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT == (ring->write_idx - ring->read_idx);
Thanks for factoring this out. I wonder, How much does this differ from the |
1825567
to
f852ae2
Compare
Hi @axel-h |
libvswitch/src/vswitch.c
Outdated
@@ -18,6 +18,10 @@ struct ether_addr bcast_macaddr = { .ether_addr_octet = { | |||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF | |||
} | |||
}; | |||
struct ether_addr ipv6_multicast_macaddr = { .ether_addr_octet = { | |||
0x33, 0x33, 0x0, 0x0, 0x0, 0x0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a comment about the value of the address, e.g which range is allowed here, which spec defines this...
{ | ||
ring->used_ring = used; | ||
ring->avail_ring = avail; | ||
ring->notify = notify; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we consider passing NULL
for any of these an error actually? We could put an assert here for development convenience, so this is caught and avoids potentially having to debug strange errors later.
libusbdrivers/src/services.h
Outdated
#else | ||
asm volatile ("" ::: "memory"); | ||
asm volatile("" :: | ||
: "memory"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the style check demanding this line break?
CMakeLists.txt
Outdated
@@ -17,3 +17,4 @@ add_subdirectory(libvswitch) | |||
add_subdirectory(libfdtgen) | |||
add_subdirectory(libtx2bpmp) | |||
add_subdirectory(libplatsupportports) | |||
add_subdirectory(libsharedringbuffer) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add a newline at the end of files.
static inline bool ring_full(ring_buffer_t *ring) | ||
{ | ||
//return !((ring->write_idx - ring->read_idx + 1) % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT); | ||
return CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT == (ring->write_idx - ring->read_idx); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We cold also add a cheap sanity check here that the indices are not running wild or got corrupted:
return CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT == (ring->write_idx - ring->read_idx); | |
size_t cnt = ring->write_idx - ring->read_idx; | |
assert(cnt <= CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT) | |
return (CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT == cnt); |
*len = buff_desc->len; | ||
*cookie = buff_desc->cookie; | ||
|
||
/* Ensure data is written back to memory */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpicking: I think all we ensure here is, that no writes are reorderd beyond this point, so they are visible. But it's not guaranteed the data really ends up in memory, as this is no cache flush.
buff_desc->encoded_addr = buffer; | ||
buff_desc->len = len; | ||
buff_desc->cookie = cookie; | ||
ring->write_idx++; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it intentional that this increment isn't after the release barrier? Otherwise I think it could potentially complete before the writes to the buff_desc do and cause a reader to read too early.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, sorry i think this was an accident. Thanks for pointing it out!
THREAD_MEMORY_RELEASE(); | ||
ring->read_idx++; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if it'd end up making a noticeable performance difference, but there's an option for these two lines to be combined into __atomic_store_n(&ring->read_idx, ring->read_idx+1, __ATOMIC_RELEASE);
which allows the compiler to generate slightly different instructions on architectures like aarch64 where there is a store-release instruction (stlr
) which means an additional dmb ish
isn't required as shown in the small assembly examples below which are generated from aarch64-linux-gnu-gcc:
4005a8: d5033bbf dmb ish
4005ac: 90000462 adrp x2, 48c000 <object.0+0x28>
.. <cut 2 unrelated instructions>
4005b8: b9400841 ldr w1, [x2, #8]
4005bc: 11000421 add w1, w1, #0x1
4005c0: b9000841 str w1, [x2, #8]
4005b0: b9400801 ldr w1, [x0, #8]
4005b4: 11000421 add w1, w1, #0x1
4005b8: 889ffc41 stlr w1, [x2]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not really have a requirement for __atomic_store_n()
? There is no race for incrementing the value, there is only one writer. Also, does this guarantee that all other writes are finish before also, or do we still need a barrier to play safe to enforce this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's still a plain store, but with release semantics. So it's not allowed to be re-ordered with any memory operations that come before it in program-order.
*/ | ||
static int driver_dequeue(ring_buffer_t *ring, uintptr_t *addr, size_t *len, void **pointer) | ||
{ | ||
if (!((ring->write_idx - ring->read_idx) % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could simply use our helper function:
if (!((ring->write_idx - ring->read_idx) % CONFIG_LIB_SHARED_RINGBUFFER_DESC_COUNT)) { | |
if (ring_empty(ring) { |
#include <sel4utils/sel4_zf_logif.h> | ||
#include <utils/util.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These two includes need to have their order swapped in order to avoid the following compiler warning:
#include <sel4utils/sel4_zf_logif.h> | |
#include <utils/util.h> | |
#include <utils/util.h> | |
#include <sel4utils/sel4_zf_logif.h> |
[267/468] Building C object projects_libs/li...d_ringbuffer.dir/src/shared_ringbuffer.c.obj
In file included from /tmp/tmp.MkaXVLiTOr/projects/projects_libs/libsharedringbuffer/include/shared_ringbuffer/shared_ringbuffer.h:12,
from /tmp/tmp.MkaXVLiTOr/projects/projects_libs/libsharedringbuffer/src/shared_ringbuffer.c:7:
/tmp/tmp.MkaXVLiTOr/projects/util_libs/libutils/include/utils/util.h:40:2: warning: #warning "Attempted to set ZF_LOG_LEVEL but _ZF_LOG_LEVEL has already been defined." "Check that <utils/zf_log.h> hasn't been imported before this file, or define ZF_LOG_LEVEL explicitly before including <utils/zf_log.h>." [-Wcpp]
40 | #warning "Attempted to set ZF_LOG_LEVEL but _ZF_LOG_LEVEL has already been defined." \
| ^~~~~~~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
f8ab455
to
962c8a8
Compare
962c8a8
to
04e8c42
Compare
Signed-off-by: Lucy <[email protected]>
Signed-off-by: Lucy <[email protected]>
Signed-off-by: Lucy <[email protected]>
Signed-off-by: Lucy <[email protected]>
Signed-off-by: Lucy <[email protected]>
04e8c42
to
09528e8
Compare
This is a new library as part of the sDDF. It provides an efficient data transport layer between driver and client, and was implemented to improve network I/O performance. It will later be used as part of ongoing VMM projects as well.
Test with: seL4/global-components#33