今天我们来看一下,linux kernel driver中经常使用的环形缓冲区以及对它的操作,参考文件:u_serial.c,如下图所示:
buf_buf
+
|
v
+----------x-----------+
| |
| |
| buf_get +---->|
| |
| |
| |
| |
| |<------+ buf_put
| |
| |
+----------------------+
(它是圆的,它是圆的)
它的“名”如下:
84 /* circular buffer */
85 struct gs_buf {
86 unsigned buf_size;
87 char *buf_buf;
88 char *buf_get;
89 char *buf_put;
90 };
91
其中,buf_size为缓冲区大小,buf_buf指向开辟缓冲区的起始地址,buf_get指向缓冲区中可读的起
始地址,buf_put为可写的缓冲区起始地址。
同时,该文件还封装了对Circle buf的几个方法,如下:
//实例化,开辟空间,赋初值
155 static int gs_buf_alloc(struct gs_buf *gb, unsigned size)
156 {
157 gb->buf_buf = kmalloc(size, GFP_KERNEL);
158 if (gb->buf_buf == NULL)
159 return -ENOMEM;
160
161 gb->buf_size = size;
162 gb->buf_put = gb->buf_buf;
163 gb->buf_get = gb->buf_buf;
164
165 return 0;
166 }
//释放空间
173 static void gs_buf_free(struct gs_buf *gb)
174 {
175 kfree(gb->buf_buf);
176 gb->buf_buf = NULL;
177 }
//清空可读的内容
184 static void gs_buf_clear(struct gs_buf *gb)
185 {
186 gb->buf_get = gb->buf_put;
187 /* equivalent to a get of all data available */
188 }
//circle buf status : how many data do we have
196 static unsigned gs_buf_data_avail(struct gs_buf *gb)
197 {
198 return (gb->buf_size + gb->buf_put - gb->buf_get) % gb->buf_size;
199 }
//circle buf status : how many space left to write
207 static unsigned gs_buf_space_avail(struct gs_buf *gb)
208 {
209 return (gb->buf_size + gb->buf_get - gb->buf_put - 1) % gb->buf_size;
210 }
//write buf
220 static unsigned
221 gs_buf_put(struct gs_buf *gb, const char *buf, unsigned count)
222 {
223 unsigned len;
224
225 len = gs_buf_space_avail(gb);
226 if (count > len)
227 count = len;
228
229 if (count == 0)
230 return 0;
231
232 len = gb->buf_buf + gb->buf_size - gb->buf_put;
233 if (count > len) {
234 memcpy(gb->buf_put, buf, len);
235 memcpy(gb->buf_buf, buf+len, count - len);
236 gb->buf_put = gb->buf_buf + count - len;
237 } else {
238 memcpy(gb->buf_put, buf, count);
239 if (count < len)
240 gb->buf_put += count;
241 else /* count == len */
242 gb->buf_put = gb->buf_buf;
243 }
244
245 return count;
246 }
//read from buf
256 static unsigned
257 gs_buf_get(struct gs_buf *gb, char *buf, unsigned count)
258 {
259 unsigned len;
260
261 len = gs_buf_data_avail(gb);
262 if (count > len)
263 count = len;
264
265 if (count == 0)
266 return 0;
267
268 len = gb->buf_buf + gb->buf_size - gb->buf_get;
269 if (count > len) {
270 memcpy(buf, gb->buf_get, len);
271 memcpy(buf+len, gb->buf_buf, count - len);
272 gb->buf_get = gb->buf_buf + count - len;
273 } else {
274 memcpy(buf, gb->buf_get, count);
275 if (count < len)
276 gb->buf_get += count;
277 else /* count == len */
278 gb->buf_get = gb->buf_buf;
279 }
280
281 return count;
282 }