├── LICENSE ├── Makefile ├── README.md ├── main.c ├── mread.c ├── mread.h ├── ringbuffer.c ├── ringbuffer.h └── testringbuffer.c /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2012-2015 codingnow.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, 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 included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc -g -o mread -Wall mread.c ringbuffer.c main.c 3 | 4 | test: 5 | gcc -g -o testrb -Wall ringbuffer.c testringbuffer.c 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A lightweight epoll wrap for read multi-sockets 2 | 3 | ## api 4 | 5 | ```C 6 | // create a pool , listen on port , set max connection and , buffer size (0 for default 1M bytes) 7 | struct mread_pool * mread_create(int port , int max , int buffer); 8 | 9 | // release the pool 10 | void mread_close(struct mread_pool *m); 11 | 12 | // poll the poll, timeout (in milliseconds) can be -1 for indefinitely. 13 | // return id (which socket can read) , -1 for block 14 | int mread_poll(struct mread_pool *m , int timeout); 15 | 16 | // pull data from the id return by poll. 17 | // return size of buffer or NULL 18 | void * mread_pull(struct mread_pool *m , int size); 19 | 20 | // When you don't need use the data return by pull, you must call yield 21 | // Otherwise, you will get them again after next poll 22 | void mread_yield(struct mread_pool *m); 23 | 24 | // When the id is closed, it returns 1 25 | int mread_closed(struct mread_pool *m); 26 | 27 | // Close id 28 | void mread_close_client(struct mread_pool *m, int id); 29 | 30 | // Get the socket fd bind with id , you can use it for sending. 31 | int mread_socket(struct mread_pool *m , int id); 32 | 33 | ``` 34 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include "mread.h" 2 | 3 | #include 4 | #include 5 | 6 | static void 7 | test(struct mread_pool *m) { 8 | int id = mread_poll(m,0); 9 | if (id >= 0) { 10 | for (;;) { 11 | char * buffer = mread_pull(m, 4); 12 | if (buffer == NULL) { 13 | if (mread_closed(m)) { 14 | printf("%d: CLOSED\n",id); 15 | } 16 | break; 17 | } else { 18 | printf("%d : %d %d %d %d\n",id, buffer[0],buffer[1],buffer[2],buffer[3]); 19 | mread_yield(m); 20 | } 21 | } 22 | } 23 | } 24 | 25 | int 26 | main() { 27 | struct mread_pool * m = mread_create(2525 , 10, 0); 28 | if (m == NULL) { 29 | perror("error:"); 30 | return 1; 31 | } 32 | for (;;) { 33 | test(m); 34 | sleep(1); 35 | } 36 | mread_close(m); 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /mread.c: -------------------------------------------------------------------------------- 1 | #include "mread.h" 2 | #include "ringbuffer.h" 3 | 4 | /* Test for polling API */ 5 | #ifdef __linux__ 6 | #define HAVE_EPOLL 1 7 | #endif 8 | 9 | #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__) 10 | #define HAVE_KQUEUE 1 11 | #endif 12 | 13 | #if !defined(HAVE_EPOLL) && !defined(HAVE_KQUEUE) 14 | #error "system does not support epoll or kqueue API" 15 | #endif 16 | /* ! Test for polling API */ 17 | 18 | #ifdef HAVE_EPOLL 19 | #include 20 | #elif HAVE_KQUEUE 21 | #include 22 | #endif 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #define BACKLOG 32 37 | #define READQUEUE 32 38 | #define READBLOCKSIZE 2048 39 | #define RINGBUFFER_DEFAULT 1024 * 1024 40 | 41 | #define SOCKET_INVALID 0 42 | #define SOCKET_CLOSED 1 43 | #define SOCKET_SUSPEND 2 44 | #define SOCKET_READ 3 45 | #define SOCKET_POLLIN 4 46 | 47 | #define SOCKET_ALIVE SOCKET_SUSPEND 48 | 49 | #define LISTENSOCKET (void *)((intptr_t)~0) 50 | 51 | struct socket { 52 | int fd; 53 | struct ringbuffer_block * node; 54 | struct ringbuffer_block * temp; 55 | int status; 56 | }; 57 | 58 | struct mread_pool { 59 | int listen_fd; 60 | #ifdef HAVE_EPOLL 61 | int epoll_fd; 62 | #elif HAVE_KQUEUE 63 | int kqueue_fd; 64 | #endif 65 | int max_connection; 66 | int closed; 67 | int active; 68 | int skip; 69 | struct socket * sockets; 70 | struct socket * free_socket; 71 | int queue_len; 72 | int queue_head; 73 | #ifdef HAVE_EPOLL 74 | struct epoll_event ev[READQUEUE]; 75 | #elif HAVE_KQUEUE 76 | struct kevent ev[READQUEUE]; 77 | #endif 78 | struct ringbuffer * rb; 79 | }; 80 | 81 | static struct socket * 82 | _create_sockets(int max) { 83 | int i; 84 | struct socket * s = malloc(max * sizeof(struct socket)); 85 | for (i=0;ilisten_fd = listen_fd; 185 | #ifdef HAVE_EPOLL 186 | self->epoll_fd = epoll_fd; 187 | #elif HAVE_KQUEUE 188 | self->kqueue_fd = kqueue_fd; 189 | #endif 190 | self->max_connection = max; 191 | self->closed = 0; 192 | self->active = -1; 193 | self->skip = 0; 194 | self->sockets = _create_sockets(max); 195 | self->free_socket = &self->sockets[0]; 196 | self->queue_len = 0; 197 | self->queue_head = 0; 198 | if (buffer_size == 0) { 199 | self->rb = _create_rb(RINGBUFFER_DEFAULT); 200 | } else { 201 | self->rb = _create_rb(buffer_size); 202 | } 203 | 204 | return self; 205 | } 206 | 207 | void 208 | mread_close(struct mread_pool *self) { 209 | if (self == NULL) 210 | return; 211 | int i; 212 | struct socket * s = self->sockets; 213 | for (i=0;imax_connection;i++) { 214 | if (s[i].status >= SOCKET_ALIVE) { 215 | close(s[i].fd); 216 | } 217 | } 218 | free(s); 219 | if (self->listen_fd >= 0) { 220 | close(self->listen_fd); 221 | } 222 | #ifdef HAVE_EPOLL 223 | close(self->epoll_fd); 224 | #elif HAVE_KQUEUE 225 | close(self->kqueue_fd); 226 | #endif 227 | _release_rb(self->rb); 228 | free(self); 229 | } 230 | 231 | static int 232 | _read_queue(struct mread_pool * self, int timeout) { 233 | self->queue_head = 0; 234 | #ifdef HAVE_EPOLL 235 | int n = epoll_wait(self->epoll_fd , self->ev, READQUEUE, timeout); 236 | #elif HAVE_KQUEUE 237 | struct timespec timeoutspec; 238 | timeoutspec.tv_sec = timeout / 1000; 239 | timeoutspec.tv_nsec = (timeout % 1000) * 1000000; 240 | int n = kevent(self->kqueue_fd, NULL, 0, self->ev, READQUEUE, &timeoutspec); 241 | #endif 242 | if (n == -1) { 243 | self->queue_len = 0; 244 | return -1; 245 | } 246 | self->queue_len = n; 247 | return n; 248 | } 249 | 250 | inline static struct socket * 251 | _read_one(struct mread_pool * self) { 252 | if (self->queue_head >= self->queue_len) { 253 | return NULL; 254 | } 255 | #ifdef HAVE_EPOLL 256 | return self->ev[self->queue_head ++].data.ptr; 257 | #elif HAVE_KQUEUE 258 | return self->ev[self->queue_head ++].udata; 259 | #endif 260 | } 261 | 262 | static struct socket * 263 | _alloc_socket(struct mread_pool * self) { 264 | if (self->free_socket == NULL) { 265 | return NULL; 266 | } 267 | struct socket * s = self->free_socket; 268 | int next_free = s->fd; 269 | if (next_free < 0 ) { 270 | self->free_socket = NULL; 271 | } else { 272 | self->free_socket = &self->sockets[next_free]; 273 | } 274 | return s; 275 | } 276 | 277 | static void 278 | _add_client(struct mread_pool * self, int fd) { 279 | struct socket * s = _alloc_socket(self); 280 | if (s == NULL) { 281 | close(fd); 282 | return; 283 | } 284 | #ifdef HAVE_EPOLL 285 | struct epoll_event ev; 286 | ev.events = EPOLLIN; 287 | ev.data.ptr = s; 288 | if (epoll_ctl(self->epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) { 289 | close(fd); 290 | return; 291 | } 292 | #elif HAVE_KQUEUE 293 | struct kevent ke; 294 | EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, s); 295 | if (kevent(self->kqueue_fd, &ke, 1, NULL, 0, NULL) == -1) { 296 | close(fd); 297 | return; 298 | } 299 | #endif 300 | 301 | s->fd = fd; 302 | s->node = NULL; 303 | s->status = SOCKET_SUSPEND; 304 | } 305 | 306 | static int 307 | _report_closed(struct mread_pool * self) { 308 | int i; 309 | for (i=0;imax_connection;i++) { 310 | if (self->sockets[i].status == SOCKET_CLOSED) { 311 | self->active = i; 312 | return i; 313 | } 314 | } 315 | assert(0); 316 | return -1; 317 | } 318 | 319 | int 320 | mread_poll(struct mread_pool * self , int timeout) { 321 | self->skip = 0; 322 | if (self->active >= 0) { 323 | struct socket * s = &self->sockets[self->active]; 324 | if (s->status == SOCKET_READ) { 325 | return self->active; 326 | } 327 | } 328 | if (self->closed > 0 ) { 329 | return _report_closed(self); 330 | } 331 | if (self->queue_head >= self->queue_len) { 332 | if (_read_queue(self, timeout) == -1) { 333 | self->active = -1; 334 | return -1; 335 | } 336 | } 337 | for (;;) { 338 | struct socket * s = _read_one(self); 339 | if (s == NULL) { 340 | self->active = -1; 341 | return -1; 342 | } 343 | if (s == LISTENSOCKET) { 344 | struct sockaddr_in remote_addr; 345 | socklen_t len = sizeof(struct sockaddr_in); 346 | int client_fd = accept(self->listen_fd , (struct sockaddr *)&remote_addr , &len); 347 | if (client_fd >= 0) { 348 | printf("MREAD connect %s:%u (fd=%d)\n",inet_ntoa(remote_addr.sin_addr),ntohs(remote_addr.sin_port), client_fd); 349 | _add_client(self, client_fd); 350 | } 351 | } else { 352 | int index = s - self->sockets; 353 | assert(index >=0 && index < self->max_connection); 354 | self->active = index; 355 | s->status = SOCKET_POLLIN; 356 | return index; 357 | } 358 | } 359 | } 360 | 361 | int 362 | mread_socket(struct mread_pool * self, int index) { 363 | return self->sockets[index].fd; 364 | } 365 | 366 | static void 367 | _link_node(struct ringbuffer * rb, int id, struct socket * s , struct ringbuffer_block * blk) { 368 | if (s->node) { 369 | ringbuffer_link(rb, s->node , blk); 370 | } else { 371 | blk->id = id; 372 | s->node = blk; 373 | } 374 | } 375 | 376 | void 377 | mread_close_client(struct mread_pool * self, int id) { 378 | struct socket * s = &self->sockets[id]; 379 | s->status = SOCKET_CLOSED; 380 | s->node = NULL; 381 | s->temp = NULL; 382 | close(s->fd); 383 | printf("MREAD close %d (fd=%d)\n",id,s->fd); 384 | 385 | #ifdef HAVE_EPOLL 386 | epoll_ctl(self->epoll_fd, EPOLL_CTL_DEL, s->fd , NULL); 387 | #elif HAVE_KQUEUE 388 | struct kevent ke; 389 | EV_SET(&ke, s->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); 390 | kevent(self->kqueue_fd, &ke, 1, NULL, 0, NULL); 391 | #endif 392 | 393 | ++self->closed; 394 | } 395 | 396 | static void 397 | _close_active(struct mread_pool * self) { 398 | int id = self->active; 399 | struct socket * s = &self->sockets[id]; 400 | ringbuffer_free(self->rb, s->temp); 401 | ringbuffer_free(self->rb, s->node); 402 | mread_close_client(self, id); 403 | } 404 | 405 | static char * 406 | _ringbuffer_read(struct mread_pool * self, int *size) { 407 | struct socket * s = &self->sockets[self->active]; 408 | if (s->node == NULL) { 409 | *size = 0; 410 | return NULL; 411 | } 412 | int sz = *size; 413 | void * ret; 414 | *size = ringbuffer_data(self->rb, s->node, sz , self->skip, &ret); 415 | return ret; 416 | } 417 | 418 | void * 419 | mread_pull(struct mread_pool * self , int size) { 420 | if (self->active == -1) { 421 | return NULL; 422 | } 423 | struct socket *s = &self->sockets[self->active]; 424 | int rd_size = size; 425 | char * buffer = _ringbuffer_read(self, &rd_size); 426 | if (buffer) { 427 | self->skip += size; 428 | return buffer; 429 | } 430 | switch (s->status) { 431 | case SOCKET_READ: 432 | s->status = SOCKET_SUSPEND; 433 | case SOCKET_CLOSED: 434 | case SOCKET_SUSPEND: 435 | return NULL; 436 | default: 437 | assert(s->status == SOCKET_POLLIN); 438 | break; 439 | } 440 | 441 | int sz = size - rd_size; 442 | int rd = READBLOCKSIZE; 443 | if (rd < sz) { 444 | rd = sz; 445 | } 446 | 447 | int id = self->active; 448 | struct ringbuffer * rb = self->rb; 449 | 450 | struct ringbuffer_block * blk = ringbuffer_alloc(rb , rd); 451 | while (blk == NULL) { 452 | int collect_id = ringbuffer_collect(rb); 453 | mread_close_client(self , collect_id); 454 | if (id == collect_id) { 455 | return NULL; 456 | } 457 | blk = ringbuffer_alloc(rb , rd); 458 | } 459 | 460 | buffer = (char *)(blk + 1); 461 | 462 | for (;;) { 463 | int bytes = recv(s->fd, buffer, rd, MSG_DONTWAIT); 464 | if (bytes > 0) { 465 | ringbuffer_shrink(rb, blk , bytes); 466 | if (bytes < sz) { 467 | _link_node(rb, self->active, s , blk); 468 | s->status = SOCKET_SUSPEND; 469 | return NULL; 470 | } 471 | s->status = SOCKET_READ; 472 | break; 473 | } 474 | if (bytes == 0) { 475 | ringbuffer_shrink(rb, blk, 0); 476 | _close_active(self); 477 | return NULL; 478 | } 479 | if (bytes == -1) { 480 | switch(errno) { 481 | case EWOULDBLOCK: 482 | ringbuffer_shrink(rb, blk, 0); 483 | s->status = SOCKET_SUSPEND; 484 | return NULL; 485 | case EINTR: 486 | continue; 487 | default: 488 | ringbuffer_shrink(rb, blk, 0); 489 | _close_active(self); 490 | return NULL; 491 | } 492 | } 493 | } 494 | _link_node(rb, self->active , s , blk); 495 | void * ret; 496 | int real_rd = ringbuffer_data(rb, s->node , size , self->skip, &ret); 497 | if (ret) { 498 | self->skip += size; 499 | return ret; 500 | } 501 | assert(real_rd == size); 502 | struct ringbuffer_block * temp = ringbuffer_alloc(rb, size); 503 | while (temp == NULL) { 504 | int collect_id = ringbuffer_collect(rb); 505 | mread_close_client(self , collect_id); 506 | if (id == collect_id) { 507 | return NULL; 508 | } 509 | temp = ringbuffer_alloc(rb , size); 510 | } 511 | temp->id = id; 512 | if (s->temp) { 513 | ringbuffer_link(rb, temp, s->temp); 514 | } 515 | s->temp = temp; 516 | ret = ringbuffer_copy(rb, s->node, self->skip, temp); 517 | assert(ret); 518 | self->skip += size; 519 | 520 | return ret; 521 | } 522 | 523 | void 524 | mread_yield(struct mread_pool * self) { 525 | if (self->active == -1) { 526 | return; 527 | } 528 | struct socket *s = &self->sockets[self->active]; 529 | ringbuffer_free(self->rb , s->temp); 530 | s->temp = NULL; 531 | if (s->status == SOCKET_CLOSED && s->node == NULL) { 532 | --self->closed; 533 | s->status = SOCKET_INVALID; 534 | s->fd = self->free_socket - self->sockets; 535 | self->free_socket = s; 536 | self->skip = 0; 537 | self->active = -1; 538 | } else { 539 | if (s->node) { 540 | s->node = ringbuffer_yield(self->rb, s->node, self->skip); 541 | } 542 | self->skip = 0; 543 | if (s->node == NULL) { 544 | self->active = -1; 545 | } 546 | } 547 | } 548 | 549 | int 550 | mread_closed(struct mread_pool * self) { 551 | if (self->active == -1) { 552 | return 0; 553 | } 554 | struct socket * s = &self->sockets[self->active]; 555 | if (s->status == SOCKET_CLOSED && s->node == NULL) { 556 | mread_yield(self); 557 | return 1; 558 | } 559 | return 0; 560 | } 561 | -------------------------------------------------------------------------------- /mread.h: -------------------------------------------------------------------------------- 1 | #ifndef MREAD_H 2 | #define MREAD_H 3 | 4 | struct mread_pool; 5 | 6 | struct mread_pool * mread_create(int port , int max , int buffer); 7 | void mread_close(struct mread_pool *m); 8 | 9 | int mread_poll(struct mread_pool *m , int timeout); 10 | void * mread_pull(struct mread_pool *m , int size); 11 | void mread_yield(struct mread_pool *m); 12 | int mread_closed(struct mread_pool *m); 13 | void mread_close_client(struct mread_pool *m, int id); 14 | int mread_socket(struct mread_pool *m , int index); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /ringbuffer.c: -------------------------------------------------------------------------------- 1 | #include "ringbuffer.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define ALIGN(s) (((s) + 3 ) & ~3) 9 | 10 | struct ringbuffer { 11 | int size; 12 | int head; 13 | }; 14 | 15 | static inline int 16 | block_offset(struct ringbuffer * rb, struct ringbuffer_block * blk) { 17 | char * start = (char *)(rb + 1); 18 | return (char *)blk - start; 19 | } 20 | 21 | static inline struct ringbuffer_block * 22 | block_ptr(struct ringbuffer * rb, int offset) { 23 | char * start = (char *)(rb + 1); 24 | return (struct ringbuffer_block *)(start + offset); 25 | } 26 | 27 | static inline struct ringbuffer_block * 28 | block_next(struct ringbuffer * rb, struct ringbuffer_block * blk) { 29 | int align_length = ALIGN(blk->length); 30 | int head = block_offset(rb, blk); 31 | if (align_length + head == rb->size) { 32 | return NULL; 33 | } 34 | assert(align_length + head < rb->size); 35 | return block_ptr(rb, head + align_length); 36 | } 37 | 38 | struct ringbuffer * 39 | ringbuffer_new(int size) { 40 | struct ringbuffer * rb = malloc(sizeof(*rb) + size); 41 | rb->size = size; 42 | rb->head = 0; 43 | struct ringbuffer_block * blk = block_ptr(rb, 0); 44 | blk->length = size; 45 | blk->id = -1; 46 | return rb; 47 | } 48 | 49 | void 50 | ringbuffer_delete(struct ringbuffer * rb) { 51 | free(rb); 52 | } 53 | 54 | void 55 | ringbuffer_link(struct ringbuffer *rb , struct ringbuffer_block * head, struct ringbuffer_block * next) { 56 | while (head->next >=0) { 57 | head = block_ptr(rb, head->next); 58 | } 59 | next->id = head->id; 60 | head->next = block_offset(rb, next); 61 | } 62 | 63 | static struct ringbuffer_block * 64 | _alloc(struct ringbuffer * rb, int total_size , int size) { 65 | struct ringbuffer_block * blk = block_ptr(rb, rb->head); 66 | int align_length = ALIGN(sizeof(struct ringbuffer_block) + size); 67 | blk->length = sizeof(struct ringbuffer_block) + size; 68 | blk->offset = 0; 69 | blk->next = -1; 70 | blk->id = -1; 71 | struct ringbuffer_block * next = block_next(rb, blk); 72 | if (next) { 73 | rb->head = block_offset(rb, next); 74 | if (align_length < total_size) { 75 | next->length = total_size - align_length; 76 | if (next->length >= sizeof(struct ringbuffer_block)) { 77 | next->id = -1; 78 | } 79 | } 80 | } else { 81 | rb->head = 0; 82 | } 83 | return blk; 84 | } 85 | 86 | struct ringbuffer_block * 87 | ringbuffer_alloc(struct ringbuffer * rb, int size) { 88 | int align_length = ALIGN(sizeof(struct ringbuffer_block) + size); 89 | int i; 90 | for (i=0;i<2;i++) { 91 | int free_size = 0; 92 | struct ringbuffer_block * blk = block_ptr(rb, rb->head); 93 | do { 94 | if (blk->length >= sizeof(struct ringbuffer_block) && blk->id >= 0) 95 | return NULL; 96 | free_size += ALIGN(blk->length); 97 | if (free_size >= align_length) { 98 | return _alloc(rb, free_size , size); 99 | } 100 | blk = block_next(rb, blk); 101 | } while(blk); 102 | rb->head = 0; 103 | } 104 | return NULL; 105 | } 106 | 107 | static int 108 | _last_id(struct ringbuffer * rb) { 109 | int i; 110 | for (i=0;i<2;i++) { 111 | struct ringbuffer_block * blk = block_ptr(rb, rb->head); 112 | do { 113 | if (blk->length >= sizeof(struct ringbuffer_block) && blk->id >= 0) 114 | return blk->id; 115 | blk = block_next(rb, blk); 116 | } while(blk); 117 | rb->head = 0; 118 | } 119 | return -1; 120 | } 121 | 122 | int 123 | ringbuffer_collect(struct ringbuffer * rb) { 124 | int id = _last_id(rb); 125 | struct ringbuffer_block *blk = block_ptr(rb, 0); 126 | do { 127 | if (blk->length >= sizeof(struct ringbuffer_block) && blk->id == id) { 128 | blk->id = -1; 129 | } 130 | blk = block_next(rb, blk); 131 | } while(blk); 132 | return id; 133 | } 134 | 135 | void 136 | ringbuffer_shrink(struct ringbuffer * rb, struct ringbuffer_block * blk, int size) { 137 | if (size == 0) { 138 | rb->head = block_offset(rb, blk); 139 | return; 140 | } 141 | int align_length = ALIGN(sizeof(struct ringbuffer_block) + size); 142 | int old_length = ALIGN(blk->length); 143 | assert(align_length <= old_length); 144 | blk->length = size + sizeof(struct ringbuffer_block); 145 | if (align_length == old_length) { 146 | return; 147 | } 148 | blk = block_next(rb, blk); 149 | blk->length = old_length - align_length; 150 | if (blk->length >= sizeof(struct ringbuffer_block)) { 151 | blk->id = -1; 152 | } 153 | rb->head = block_offset(rb, blk); 154 | } 155 | 156 | static int 157 | _block_id(struct ringbuffer_block * blk) { 158 | assert(blk->length >= sizeof(struct ringbuffer_block)); 159 | int id = blk->id; 160 | assert(id>=0); 161 | return id; 162 | } 163 | 164 | void 165 | ringbuffer_free(struct ringbuffer * rb, struct ringbuffer_block * blk) { 166 | if (blk == NULL) 167 | return; 168 | int id = _block_id(blk); 169 | blk->id = -1; 170 | while (blk->next >= 0) { 171 | blk = block_ptr(rb, blk->next); 172 | assert(_block_id(blk) == id); 173 | blk->id = -1; 174 | } 175 | } 176 | 177 | int 178 | ringbuffer_data(struct ringbuffer * rb, struct ringbuffer_block * blk, int size, int skip, void **ptr) { 179 | int length = blk->length - sizeof(struct ringbuffer_block) - blk->offset; 180 | for (;;) { 181 | if (length > skip) { 182 | if (length - skip >= size) { 183 | char * start = (char *)(blk + 1); 184 | *ptr = (start + blk->offset + skip); 185 | return size; 186 | } 187 | *ptr = NULL; 188 | int ret = length - skip; 189 | while (blk->next >= 0) { 190 | blk = block_ptr(rb, blk->next); 191 | ret += blk->length - sizeof(struct ringbuffer_block); 192 | if (ret >= size) 193 | return size; 194 | } 195 | return ret; 196 | } 197 | if (blk->next < 0) { 198 | assert(length == skip); 199 | *ptr = NULL; 200 | return 0; 201 | } 202 | blk = block_ptr(rb, blk->next); 203 | assert(blk->offset == 0); 204 | skip -= length; 205 | length = blk->length - sizeof(struct ringbuffer_block); 206 | } 207 | } 208 | 209 | void * 210 | ringbuffer_copy(struct ringbuffer * rb, struct ringbuffer_block * from, int skip, struct ringbuffer_block * to) { 211 | int size = to->length - sizeof(struct ringbuffer_block); 212 | int length = from->length - sizeof(struct ringbuffer_block) - from->offset; 213 | char * ptr = (char *)(to+1); 214 | for (;;) { 215 | if (length > skip) { 216 | char * src = (char *)(from + 1); 217 | src += from->offset + skip; 218 | length -= skip; 219 | while (length < size) { 220 | memcpy(ptr, src, length); 221 | assert(from->next >= 0); 222 | from = block_ptr(rb , from->next); 223 | assert(from->offset == 0); 224 | ptr += length; 225 | size -= length; 226 | length = from->length - sizeof(struct ringbuffer_block); 227 | src = (char *)(from + 1); 228 | } 229 | memcpy(ptr, src , size); 230 | to->id = from->id; 231 | return (char *)(to + 1); 232 | } 233 | assert(from->next >= 0); 234 | from = block_ptr(rb, from->next); 235 | assert(from->offset == 0); 236 | skip -= length; 237 | length = from->length - sizeof(struct ringbuffer_block); 238 | } 239 | } 240 | 241 | struct ringbuffer_block * 242 | ringbuffer_yield(struct ringbuffer * rb, struct ringbuffer_block *blk, int skip) { 243 | int length = blk->length - sizeof(struct ringbuffer_block) - blk->offset; 244 | for (;;) { 245 | if (length > skip) { 246 | blk->offset += skip; 247 | return blk; 248 | } 249 | blk->id = -1; 250 | if (blk->next < 0) { 251 | return NULL; 252 | } 253 | blk = block_ptr(rb, blk->next); 254 | assert(blk->offset == 0); 255 | skip -= length; 256 | length = blk->length - sizeof(struct ringbuffer_block); 257 | } 258 | } 259 | 260 | void 261 | ringbuffer_dump(struct ringbuffer * rb) { 262 | struct ringbuffer_block *blk = block_ptr(rb,0); 263 | int i=0; 264 | printf("total size= %d\n",rb->size); 265 | while (blk) { 266 | ++i; 267 | if (i>10) 268 | break; 269 | if (blk->length >= sizeof(*blk)) { 270 | printf("[%u : %d]", (unsigned)(blk->length - sizeof(*blk)), block_offset(rb,blk)); 271 | printf(" id=%d",blk->id); 272 | if (blk->id >=0) { 273 | printf(" offset=%d next=%d",blk->offset, blk->next); 274 | } 275 | } else { 276 | printf("<%u : %d>", blk->length, block_offset(rb,blk)); 277 | } 278 | printf("\n"); 279 | blk = block_next(rb, blk); 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /ringbuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef MREAD_RINGBUFFER_H 2 | #define MREAD_RINGBUFFER_H 3 | 4 | struct ringbuffer; 5 | 6 | struct ringbuffer_block { 7 | int length; 8 | int offset; 9 | int id; 10 | int next; 11 | }; 12 | 13 | struct ringbuffer * ringbuffer_new(int size); 14 | void ringbuffer_delete(struct ringbuffer * rb); 15 | void ringbuffer_link(struct ringbuffer *rb , struct ringbuffer_block * prev, struct ringbuffer_block * next); 16 | struct ringbuffer_block * ringbuffer_alloc(struct ringbuffer * rb, int size); 17 | int ringbuffer_collect(struct ringbuffer * rb); 18 | void ringbuffer_shrink(struct ringbuffer * rb, struct ringbuffer_block * blk, int size); 19 | void ringbuffer_free(struct ringbuffer * rb, struct ringbuffer_block * blk); 20 | int ringbuffer_data(struct ringbuffer * rb, struct ringbuffer_block * blk, int size, int skip, void **ptr); 21 | void * ringbuffer_copy(struct ringbuffer * rb, struct ringbuffer_block * from, int skip, struct ringbuffer_block * to); 22 | struct ringbuffer_block * ringbuffer_yield(struct ringbuffer * rb, struct ringbuffer_block *blk, int skip); 23 | 24 | void ringbuffer_dump(struct ringbuffer * rb); 25 | 26 | #endif 27 | 28 | -------------------------------------------------------------------------------- /testringbuffer.c: -------------------------------------------------------------------------------- 1 | #include "ringbuffer.h" 2 | #include 3 | 4 | static void 5 | init(struct ringbuffer_block * blk, int n) { 6 | char * ptr = (char *)(blk+1); 7 | int i; 8 | for (i=0;iid = 0; 34 | ringbuffer_free(rb,blk); 35 | blk = ringbuffer_alloc(rb,48); 36 | blk->id = 1; 37 | ringbuffer_free(rb,blk); 38 | 39 | blk = ringbuffer_alloc(rb,80); 40 | blk->id = 0; 41 | ringbuffer_free(rb,blk); 42 | 43 | 44 | blk = ringbuffer_alloc(rb,50); 45 | blk->id = 1; 46 | struct ringbuffer_block * next = ringbuffer_alloc(rb, 40); 47 | next->id = 1; 48 | ringbuffer_link(rb, blk, next); 49 | ringbuffer_dump(rb); 50 | blk = ringbuffer_alloc(rb,4); 51 | printf("%p\n",blk); 52 | int id = ringbuffer_collect(rb); 53 | printf("collect %d\n",id); 54 | 55 | blk = ringbuffer_alloc(rb,4); 56 | blk->id = 2; 57 | init(blk,4); 58 | 59 | next = ringbuffer_alloc(rb,5); 60 | init(next,5); 61 | ringbuffer_link(rb, blk, next); 62 | 63 | next = ringbuffer_alloc(rb,6); 64 | init(next,6); 65 | ringbuffer_link(rb, blk , next); 66 | 67 | 68 | dump(rb, blk , 3); 69 | dump(rb, blk , 6); 70 | dump(rb, blk , 16); 71 | 72 | blk = ringbuffer_yield(rb, blk, 5); 73 | 74 | next = ringbuffer_alloc(rb, 7); 75 | ringbuffer_copy(rb, blk, 1, next); 76 | dump(rb, next, 7); 77 | 78 | blk = ringbuffer_yield(rb, blk , 5); 79 | 80 | ringbuffer_dump(rb); 81 | } 82 | 83 | int 84 | main() { 85 | struct ringbuffer * rb = ringbuffer_new(128); 86 | test(rb); 87 | ringbuffer_delete(rb); 88 | return 0; 89 | } 90 | --------------------------------------------------------------------------------