1 /*
2 * Copyright (c) 2023 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
3 * Licensed under the Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 * http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9 * PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 */
12
13 #include <chcore/ring_buffer.h>
14 #include <sys/mman.h>
15 #include <string.h>
16 #include <chcore/defs.h>
17
18 /*
19 * next_slot returns the virtual address of the next slot to the given offset.
20 * This function should not be used by user directly, so we will not check the
21 * correctness of the offset here.
22 */
next_slot(struct ring_buffer * ring_buf,off_t off)23 static inline off_t next_slot(struct ring_buffer *ring_buf, off_t off)
24 {
25 return ((off == ring_buf->buffer_size - ring_buf->msg_size) ?
26 (sizeof(struct ring_buffer)) :
27 (off + ring_buf->msg_size));
28 }
29
get_one_msg(struct ring_buffer * ring_buf,void * msg)30 int get_one_msg(struct ring_buffer *ring_buf, void *msg)
31 {
32 off_t p_off = ring_buf->producer_offset;
33 off_t c_off = ring_buf->consumer_offset;
34
35 /* recycle_msg_buffer is empty */
36 if (p_off == c_off)
37 return MSG_OP_FAILURE;
38 vaddr_t buf = (vaddr_t)ring_buf + c_off;
39 memcpy(msg, (void *)buf, ring_buf->msg_size);
40 ring_buf->consumer_offset = next_slot(ring_buf, c_off);
41 return MSG_OP_SUCCESS;
42 }
43
44 /*
45 * Whether ring buffer is full
46 * Always keep a slot empty
47 * Max capicity = buffer_size - msg_size
48 * p_off = c_off : buffer empty
49 * c_off = next_slot(p_off) : buffer full
50 */
if_buffer_full(struct ring_buffer * ring_buf)51 int if_buffer_full(struct ring_buffer *ring_buf)
52 {
53 off_t p_off = ring_buf->producer_offset;
54 off_t c_off = ring_buf->consumer_offset;
55
56 /* recycle_msg_buffer is full */
57 if (c_off == next_slot(ring_buf, p_off))
58 return RING_BUFFER_FULL;
59
60 return RING_BUFFER_NOT_FULL;
61 }
62
set_one_msg(struct ring_buffer * ring_buf,void * msg)63 int set_one_msg(struct ring_buffer *ring_buf, void *msg)
64 {
65 if (if_buffer_full(ring_buf)) {
66 return MSG_OP_FAILURE;
67 }
68
69 off_t p_off = ring_buf->producer_offset;
70 vaddr_t buf = (vaddr_t)ring_buf + p_off;
71
72 memcpy((void *)buf, msg, ring_buf->msg_size);
73 ring_buf->producer_offset = next_slot(ring_buf, p_off);
74 return MSG_OP_SUCCESS;
75 }
76
new_ringbuffer(int msg_num,size_t msg_size)77 struct ring_buffer *new_ringbuffer(int msg_num, size_t msg_size)
78 {
79 size_t buffer_size = msg_num * msg_size + sizeof(struct ring_buffer);
80 int page_num = ROUND_UP(buffer_size, 0x1000);
81 struct ring_buffer *ring_buf =
82 (struct ring_buffer *)mmap(NULL,
83 page_num * 0x1000,
84 PROT_READ | PROT_WRITE,
85 MAP_ANONYMOUS | MAP_PRIVATE,
86 -1,
87 0);
88 // struct ring_buffer *ring_buf = (struct ring_buffer
89 // *)malloc(buffer_size);
90 if (ring_buf == 0)
91 return NULL;
92 memset(ring_buf, 0, buffer_size);
93 ring_buf->msg_size = msg_size;
94 ring_buf->buffer_size = buffer_size;
95 ring_buf->producer_offset = (off_t)sizeof(struct ring_buffer);
96 ring_buf->consumer_offset = (off_t)sizeof(struct ring_buffer);
97 return ring_buf;
98 }
99
free_ringbuffer(struct ring_buffer * ring_buf)100 void free_ringbuffer(struct ring_buffer *ring_buf)
101 {
102 int page_num = ROUND_UP(ring_buf->buffer_size, 0x1000);
103 munmap(ring_buf, page_num * 0x1000);
104 }