00001
00002
00003
00004
00005 #include <sys/types.h>
00006 #include <sys/mman.h>
00007 #include <stdlib.h>
00008 #include <string.h>
00009 #include <unistd.h>
00010 #include <u/toolbox/rb.h>
00011 #include <u/toolbox/misc.h>
00012 #include <u/toolbox/carpal.h>
00013
00014 #if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
00015 #define u_vm_page_sz sysconf(_SC_PAGE_SIZE)
00016 #elif defined (HAVE_SYSCONF) && defined(_SC_PAGESIZE)
00017 #define u_vm_page_sz sysconf(_SC_PAGESIZE)
00018 #elif defined(HAVE_GETPAGESIZE)
00019 #define u_vm_page_sz getpagesize()
00020 #else
00021 #error "don't know how to get page size. reconfigure with --no_ringbuffer."
00022 #endif
00023
00024 struct u_rb_s
00025 {
00026 char *base;
00027 size_t sz;
00028 size_t wr_off;
00029 size_t rd_off;
00030 int opts;
00031 };
00032
00033 static char *write_addr (u_rb_t *rb);
00034 static void write_incr (u_rb_t *rb, size_t cnt);
00035 static char *read_addr (u_rb_t *rb);
00036 static void read_incr (u_rb_t *rb, size_t cnt);
00037 static size_t round_sz (size_t sz);
00038
00112 int u_rb_create (size_t hint_sz, int opts, u_rb_t **prb)
00113 {
00114 int fd = -1;
00115 u_rb_t *rb = NULL;
00116 char path[] = "/tmp/rb-XXXXXX";
00117
00118 dbg_err_sif ((rb = u_zalloc(sizeof(u_rb_t))) == NULL);
00119 dbg_err_sif ((fd = mkstemp(path)) == -1);
00120 dbg_err_sif (u_remove(path));
00121
00122
00123
00124 rb->sz = round_sz(hint_sz);
00125 rb->wr_off = 0;
00126 rb->rd_off = 0;
00127 rb->opts = opts;
00128
00129 dbg_err_sif (ftruncate(fd, rb->sz) == -1);
00130
00131
00132
00133
00134
00135
00136 rb->base = mmap(NULL, rb->sz << 1, PROT_NONE,
00137 MAP_ANON | MAP_PRIVATE, -1, 0);
00138 dbg_err_sif (rb->base == MAP_FAILED);
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149 dbg_err_sif (mmap(rb->base, rb->sz, PROT_READ | PROT_WRITE,
00150 MAP_FIXED | MAP_SHARED, fd, 0) != rb->base);
00151
00152
00153
00154 dbg_err_sif (mmap(rb->base + rb->sz, rb->sz, PROT_READ | PROT_WRITE,
00155 MAP_FIXED | MAP_SHARED, fd, 0) != rb->base + rb->sz);
00156
00157
00158 dbg_err_sif (close(fd) == -1);
00159
00160 *prb = rb;
00161
00162 return 0;
00163 err:
00164 u_rb_free(rb);
00165 U_CLOSE(fd);
00166 return -1;
00167 }
00168
00178 void u_rb_free (u_rb_t *rb)
00179 {
00180 nop_return_if (rb == NULL, );
00181
00182
00183
00184
00185 dbg_return_sif (rb->base && (munmap(rb->base, rb->sz << 1) == -1), );
00186 u_free(rb);
00187
00188 return;
00189 }
00190
00201 size_t u_rb_size (u_rb_t *rb)
00202 {
00203 return rb->sz;
00204 }
00205
00221 ssize_t u_rb_write (u_rb_t *rb, const void *b, size_t b_sz)
00222 {
00223 size_t to_be_written;
00224
00225 dbg_return_if (rb == NULL, -1);
00226 dbg_return_if (b == NULL, -1);
00227 dbg_return_if (b_sz > u_rb_size(rb), -1);
00228
00229 nop_goto_if (!(to_be_written = U_MIN(u_rb_avail(rb), b_sz)), end);
00230
00231 memcpy(write_addr(rb), b, to_be_written);
00232 write_incr(rb, to_be_written);
00233
00234
00235 end:
00236 return to_be_written;
00237 }
00238
00256 ssize_t u_rb_read (u_rb_t *rb, void *b, size_t b_sz)
00257 {
00258 size_t to_be_read;
00259
00260 dbg_return_if (b == NULL, -1);
00261 dbg_return_if (rb == NULL, -1);
00262 dbg_return_if (b_sz > u_rb_size(rb), -1);
00263
00264
00265 nop_goto_if (!(to_be_read = U_MIN(u_rb_ready(rb), b_sz)), end);
00266
00267 memcpy(b, read_addr(rb), to_be_read);
00268 read_incr(rb, to_be_read);
00269
00270
00271 end:
00272 return to_be_read;
00273 }
00274
00295 void *u_rb_fast_read (u_rb_t *rb, size_t *pb_sz)
00296 {
00297 void *data = NULL;
00298
00299 dbg_return_if (rb == NULL, NULL);
00300 dbg_return_if (!(rb->opts & U_RB_OPT_USE_CONTIGUOUS_MEM), NULL);
00301 dbg_return_if (pb_sz == NULL, NULL);
00302 dbg_return_if (*pb_sz > u_rb_size(rb), NULL);
00303
00304
00305 nop_goto_if (!(*pb_sz = U_MIN(u_rb_ready(rb), *pb_sz)), end);
00306
00307 data = read_addr(rb);
00308 read_incr(rb, *pb_sz);
00309
00310
00311 end:
00312 return data;
00313 }
00314
00325 int u_rb_clear (u_rb_t *rb)
00326 {
00327 dbg_return_if (rb == NULL, -1);
00328 rb->wr_off = rb->rd_off = 0;
00329 return 0;
00330 }
00331
00342 size_t u_rb_ready (u_rb_t *rb)
00343 {
00344 return rb->wr_off - rb->rd_off;
00345 }
00346
00358 size_t u_rb_avail (u_rb_t *rb)
00359 {
00360 return rb->sz - u_rb_ready(rb);
00361 }
00362
00367
00368 static size_t round_sz (size_t sz)
00369 {
00370 size_t pg_sz = (size_t) u_vm_page_sz;
00371
00372 return !sz ? pg_sz : (((sz - 1) / pg_sz) + 1) * pg_sz;
00373 }
00374
00375
00376 static char *write_addr (u_rb_t *rb)
00377 {
00378 return rb->base + rb->wr_off;
00379 }
00380
00381
00382 static void write_incr (u_rb_t *rb, size_t cnt)
00383 {
00384 rb->wr_off += cnt;
00385 }
00386
00387
00388 static char *read_addr (u_rb_t *rb)
00389 {
00390 return rb->base + rb->rd_off;
00391 }
00392
00393
00394 static void read_incr (u_rb_t *rb, size_t cnt)
00395 {
00396
00397
00398
00399 rb->rd_off += cnt;
00400
00401
00402
00403
00404 if (rb->rd_off >= rb->sz)
00405 {
00406 rb->rd_off -= rb->sz;
00407 rb->wr_off -= rb->sz;
00408 }
00409
00410 return;
00411 }