/* * Copyright (c) 2002-2005 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Nathan Binkert */ #include #include #include #include #include "base/atomicio.hh" #include "base/circlebuf.hh" #include "base/cprintf.hh" #include "base/intmath.hh" using namespace std; CircleBuf::CircleBuf(int l) : _rollover(false), _buflen(l), _size(0), _start(0), _stop(0) { _buf = new char[_buflen]; } CircleBuf::~CircleBuf() { if (_buf) delete [] _buf; } void CircleBuf::dump() { cprintf("start = %10d, stop = %10d, buflen = %10d\n", _start, _stop, _buflen); fflush(stdout); atomic_write(STDOUT_FILENO, _buf, _buflen); atomic_write(STDOUT_FILENO, "<\n", 2); } void CircleBuf::flush() { _start = 0; _stop = 0; _rollover = false; } void CircleBuf::read(char *b, int len) { _size -= len; if (_size < 0) _size = 0; if (_stop > _start) { len = min(len, _stop - _start); memcpy(b, _buf + _start, len); _start += len; } else { int endlen = _buflen - _start; if (endlen > len) { memcpy(b, _buf + _start, len); _start += len; } else { memcpy(b, _buf + _start, endlen); _start = min(len - endlen, _stop); memcpy(b + endlen, _buf, _start); } } } void CircleBuf::read(int fd, int len) { _size -= len; if (_size < 0) _size = 0; if (_stop > _start) { len = min(len, _stop - _start); atomic_write(fd, _buf + _start, len); _start += len; } else { int endlen = _buflen - _start; if (endlen > len) { atomic_write(fd, _buf + _start, len); _start += len; } else { atomic_write(fd, _buf + _start, endlen); _start = min(len - endlen, _stop); atomic_write(fd, _buf, _start); } } } void CircleBuf::read(int fd) { _size = 0; if (_stop > _start) { atomic_write(fd, _buf + _start, _stop - _start); } else { atomic_write(fd, _buf + _start, _buflen - _start); atomic_write(fd, _buf, _stop); } _start = _stop; } void CircleBuf::read(ostream &out) { _size = 0; if (_stop > _start) { out.write(_buf + _start, _stop - _start); } else { out.write(_buf + _start, _buflen - _start); out.write(_buf, _stop); } _start = _stop; } void CircleBuf::readall(int fd) { if (_rollover) atomic_write(fd, _buf + _stop, _buflen - _stop); atomic_write(fd, _buf, _stop); _start = _stop; } void CircleBuf::write(char b) { write(&b, 1); } void CircleBuf::write(const char *b) { write(b, strlen(b)); } void CircleBuf::write(const char *b, int len) { if (len <= 0) return; _size += len; if (_size > _buflen) _size = _buflen; int old_start = _start; int old_stop = _stop; if (len >= _buflen) { _start = 0; _stop = _buflen; _rollover = true; memcpy(_buf, b + (len - _buflen), _buflen); return; } if (_stop + len <= _buflen) { memcpy(_buf + _stop, b, len); _stop += len; } else { int end_len = _buflen - old_stop; _stop = len - end_len; memcpy(_buf + old_stop, b, end_len); memcpy(_buf, b + end_len, _stop); _rollover = true; } if ((old_start > old_stop && old_start < _stop) || (old_start < old_stop && _stop < old_stop)) _start = _stop + 1; }