WvStreams
wvmagiccircle.cc
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  *
00005  * A circular queue that can be accessed across fork().
00006  */
00007 #include "wvmagiccircle.h"
00008 #include <assert.h>
00009 
00010 
00011 WvMagicCircle::WvMagicCircle(size_t _size)
00012     : shm(_size + 1 + 2*sizeof(int)), 
00013        head(((int*)shm.buf)[0]), tail(((int*)shm.buf)[1])
00014 {
00015     assert((int)_size > 0);
00016     
00017     head = tail = 0;
00018     size = _size + 1; // a circular queue uses one extra byte
00019     circle = shm.cbuf + 2*sizeof(int);
00020     
00021     if (shm.geterr())
00022         seterr(shm);
00023 }
00024 
00025 
00026 WvMagicCircle::~WvMagicCircle()
00027 {
00028     // nothing special
00029 }
00030 
00031 
00032 size_t WvMagicCircle::used()
00033 {
00034     int x = tail - head;
00035     if (x < 0)
00036         x += size;
00037     assert(x >= 0);
00038     assert(x < size);
00039     
00040     return x;
00041 }
00042 
00043 
00044 size_t WvMagicCircle::put(const void *data, size_t len)
00045 {
00046     size_t max = left();
00047     size_t chunk1;
00048     
00049     if (len > max)
00050         len = max;
00051     
00052     chunk1 = size - tail;
00053     if (len < chunk1)
00054         chunk1 = len;
00055 
00056 #if 0
00057     WvLog log("put", WvLog::Info);
00058     log("put: head %s, tail %s, size %s, len %s, chunk1 %s\n",
00059         head, tail, size, len, chunk1);
00060 #endif
00061     
00062     memcpy(circle + tail, data, chunk1);
00063     if (chunk1 < len)
00064         memcpy(circle, (char *)data + chunk1, len - chunk1);
00065     
00066     tail = (tail + len) % size;
00067     
00068     return len;
00069 }
00070 
00071 
00072 size_t WvMagicCircle::get(void *data, size_t len)
00073 {
00074     size_t max = used();
00075     size_t chunk1;
00076     
00077     if (len > max)
00078         len = max;
00079     
00080     chunk1 = size - head;
00081     if (chunk1 > len)
00082         chunk1 = len;
00083     
00084     memcpy(data, circle + head, chunk1);
00085     if (chunk1 < len)
00086         memcpy((char *)data + chunk1, circle, len - chunk1);
00087     
00088     head = (head + len) % size;
00089     
00090     return len;
00091 }
00092 
00093 
00094 size_t WvMagicCircle::skip(size_t len)
00095 {
00096     size_t max = used();
00097     
00098     if (len > max)
00099         len = max;
00100     
00101     head = (head + len) % size;
00102     
00103     return len;
00104 }