1 /*
2 * Copyright (c) 2009-2013 Travis Geiselbrecht
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23 #pragma once
24
25 #include <compiler.h>
26 #include <sys/types.h>
27 #include <kernel/event.h>
28 #include <kernel/spinlock.h>
29 #include <iovec.h>
30
31 __BEGIN_CDECLS
32
33 typedef struct cbuf {
34 uint head;
35 uint tail;
36 uint len_pow2;
37 char *buf;
38 event_t event;
39 spin_lock_t lock;
40 } cbuf_t;
41
42 /**
43 * cbuf_initialize
44 *
45 * Initialize a cbuf structure, mallocing the underlying data buffer in the
46 * process. Make sure that the buffer has enough space for at least len bytes.
47 *
48 * @param[in] cbuf A pointer to the cbuf structure to allocate.
49 * @param[in] len The minimum number of bytes for the underlying data buffer.
50 * Must be a power of two.
51 */
52 void cbuf_initialize(cbuf_t *cbuf, size_t len);
53
54 /**
55 * cbuf_initalize_etc
56 *
57 * Initialize a cbuf structure using the supplied buffer for internal storage.
58 *
59 * @param[in] cbuf A pointer to the cbuf structure to allocate.
60 * @param[in] len The size of the supplied buffer, in bytes. Must be a power
61 * of two.
62 * @param[in] buf A pointer to the memory to be used for internal storage.
63 */
64 void cbuf_initialize_etc(cbuf_t *cbuf, size_t len, void *buf);
65
66 /**
67 * cbuf_read
68 *
69 * Read up to buflen bytes in to the supplied buffer.
70 *
71 * @param[in] cbuf The cbuf instance to read from.
72 * @param[in] buf A pointer to a buffer to read data into. If NULL, cbuf_read
73 * will skip up to the next buflen bytes from the cbuf.
74 * @param[in] buflen The maximum number of bytes to read from the cbuf.
75 * @param[in] block When true, will cause the caller to block until there is at
76 * least one byte available to read from the cbuf.
77 *
78 * @return The actual number of bytes which were read (or skipped).
79 */
80 size_t cbuf_read(cbuf_t *cbuf, void *buf, size_t buflen, bool block);
81
82 /**
83 * cbuf_peek
84 *
85 * Peek at the data available for read in the cbuf right now. Does not actually
86 * consume the data, it just fills out a pair of iovec structures describing the
87 * (up to) two contiguous regions currently available for read.
88 *
89 * @param[in] cbuf The cbuf instance to write to.
90 * @param[out] A pointer to two iovec structures to hold the contiguous regions
91 * for read. NOTE: regions must point to a chunk of memory which is at least
92 * sizeof(iovec_t) * 2 bytes long.
93 *
94 * @return The number of bytes which were written (or skipped).
95 */
96 size_t cbuf_peek(cbuf_t *cbuf, iovec_t *regions);
97
98 /**
99 * cbuf_write
100 *
101 * Write up to len bytes from the the supplied buffer into the cbuf.
102 *
103 * @param[in] cbuf The cbuf instance to write to.
104 * @param[in] buf A pointer to a buffer to read data from. If NULL, cbuf_write
105 * will skip up to the next len bytes in the cbuf, filling with zeros instead of
106 * supplied data.
107 * @param[in] len The maximum number of bytes to write to the cbuf.
108 * @param[in] canreschedule Rescheduling policy passed through to the internal
109 * event when signaling the event to indicate that there is now data in the
110 * buffer to be read.
111 *
112 * @return The number of bytes which were written (or skipped).
113 */
114 size_t cbuf_write(cbuf_t *cbuf, const void *buf, size_t len, bool canreschedule);
115
116 /**
117 * cbuf_space_avail
118 *
119 * @param[in] cbuf The cbuf instance to query
120 *
121 * @return The number of free space available in the cbuf (IOW - the maximum
122 * number of bytes which can currently be written)
123 */
124 size_t cbuf_space_avail(cbuf_t *cbuf);
125
126 /**
127 * cbuf_space_used
128 *
129 * @param[in] cbuf The cbuf instance to query
130 *
131 * @return The number of used bytes in the cbuf (IOW - the maximum number of
132 * bytes which can currently be read).
133 */
134 size_t cbuf_space_used(cbuf_t *cbuf);
135
136 /**
137 * cbuf_size
138 *
139 * @param[in] cbuf The cbuf instance to query
140 *
141 * @return The size of the cbuf's underlying data buffer.
142 */
cbuf_size(cbuf_t * cbuf)143 static inline size_t cbuf_size(cbuf_t *cbuf)
144 {
145 return (1UL << cbuf->len_pow2);
146 }
147
148 /**
149 * cbuf_reset
150 *
151 * Reset the cbuf instance, discarding any data which may be in the buffer at
152 * the moment.
153 *
154 * @param[in] cbuf The cbuf instance to reset.
155 */
cbuf_reset(cbuf_t * cbuf)156 static inline void cbuf_reset(cbuf_t *cbuf)
157 {
158 cbuf_read(cbuf, NULL, cbuf_size(cbuf), false);
159 }
160
161 /* special cases for dealing with a single char of data */
162 size_t cbuf_read_char(cbuf_t *cbuf, char *c, bool block);
163 size_t cbuf_write_char(cbuf_t *cbuf, char c, bool canreschedule);
164
165 __END_CDECLS
166
167