blob: fe023d8f3a7cc75e5d3274e26f7f9a73748b557f [file] [log] [blame]
/* $Id$ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pj/fifobuf.h>
#include <pj/log.h>
#include <pj/assert.h>
#include <pj/os.h>
#define THIS_FILE "fifobuf"
#define SZ sizeof(unsigned)
PJ_DEF(void) pj_fifobuf_init (pj_fifobuf_t *fifobuf, void *buffer, unsigned size)
{
PJ_CHECK_STACK();
PJ_LOG(6, (THIS_FILE,
"fifobuf_init fifobuf=%p buffer=%p, size=%d",
fifobuf, buffer, size));
fifobuf->first = (char*)buffer;
fifobuf->last = fifobuf->first + size;
fifobuf->ubegin = fifobuf->uend = fifobuf->first;
fifobuf->full = 0;
}
PJ_DEF(unsigned) pj_fifobuf_max_size (pj_fifobuf_t *fifobuf)
{
unsigned s1, s2;
PJ_CHECK_STACK();
if (fifobuf->uend >= fifobuf->ubegin) {
s1 = fifobuf->last - fifobuf->uend;
s2 = fifobuf->ubegin - fifobuf->first;
} else {
s1 = s2 = fifobuf->ubegin - fifobuf->uend;
}
return s1<s2 ? s2 : s1;
}
PJ_DEF(void*) pj_fifobuf_alloc (pj_fifobuf_t *fifobuf, unsigned size)
{
unsigned available;
char *start;
PJ_CHECK_STACK();
if (fifobuf->full) {
PJ_LOG(6, (THIS_FILE,
"fifobuf_alloc fifobuf=%p, size=%d: full!",
fifobuf, size));
return NULL;
}
/* try to allocate from the end part of the fifo */
if (fifobuf->uend >= fifobuf->ubegin) {
available = fifobuf->last - fifobuf->uend;
if (available >= size+SZ) {
char *ptr = fifobuf->uend;
fifobuf->uend += (size+SZ);
if (fifobuf->uend == fifobuf->last)
fifobuf->uend = fifobuf->first;
if (fifobuf->uend == fifobuf->ubegin)
fifobuf->full = 1;
*(unsigned*)ptr = size+SZ;
ptr += SZ;
PJ_LOG(6, (THIS_FILE,
"fifobuf_alloc fifobuf=%p, size=%d: returning %p, p1=%p, p2=%p",
fifobuf, size, ptr, fifobuf->ubegin, fifobuf->uend));
return ptr;
}
}
/* try to allocate from the start part of the fifo */
start = (fifobuf->uend <= fifobuf->ubegin) ? fifobuf->uend : fifobuf->first;
available = fifobuf->ubegin - start;
if (available >= size+SZ) {
char *ptr = start;
fifobuf->uend = start + size + SZ;
if (fifobuf->uend == fifobuf->ubegin)
fifobuf->full = 1;
*(unsigned*)ptr = size+SZ;
ptr += SZ;
PJ_LOG(6, (THIS_FILE,
"fifobuf_alloc fifobuf=%p, size=%d: returning %p, p1=%p, p2=%p",
fifobuf, size, ptr, fifobuf->ubegin, fifobuf->uend));
return ptr;
}
PJ_LOG(6, (THIS_FILE,
"fifobuf_alloc fifobuf=%p, size=%d: no space left! p1=%p, p2=%p",
fifobuf, size, fifobuf->ubegin, fifobuf->uend));
return NULL;
}
PJ_DEF(pj_status_t) pj_fifobuf_unalloc (pj_fifobuf_t *fifobuf, void *buf)
{
char *ptr = (char*)buf;
char *endptr;
unsigned sz;
PJ_CHECK_STACK();
ptr -= SZ;
sz = *(unsigned*)ptr;
endptr = fifobuf->uend;
if (endptr == fifobuf->first)
endptr = fifobuf->last;
if (ptr+sz != endptr) {
pj_assert(!"Invalid pointer to undo alloc");
return -1;
}
fifobuf->uend = ptr;
fifobuf->full = 0;
PJ_LOG(6, (THIS_FILE,
"fifobuf_unalloc fifobuf=%p, ptr=%p, size=%d, p1=%p, p2=%p",
fifobuf, buf, sz, fifobuf->ubegin, fifobuf->uend));
return 0;
}
PJ_DEF(pj_status_t) pj_fifobuf_free (pj_fifobuf_t *fifobuf, void *buf)
{
char *ptr = (char*)buf;
char *end;
unsigned sz;
PJ_CHECK_STACK();
ptr -= SZ;
if (ptr < fifobuf->first || ptr >= fifobuf->last) {
pj_assert(!"Invalid pointer to free");
return -1;
}
if (ptr != fifobuf->ubegin && ptr != fifobuf->first) {
pj_assert(!"Invalid free() sequence!");
return -1;
}
end = (fifobuf->uend > fifobuf->ubegin) ? fifobuf->uend : fifobuf->last;
sz = *(unsigned*)ptr;
if (ptr+sz > end) {
pj_assert(!"Invalid size!");
return -1;
}
fifobuf->ubegin = ptr + sz;
/* Rollover */
if (fifobuf->ubegin == fifobuf->last)
fifobuf->ubegin = fifobuf->first;
/* Reset if fifobuf is empty */
if (fifobuf->ubegin == fifobuf->uend)
fifobuf->ubegin = fifobuf->uend = fifobuf->first;
fifobuf->full = 0;
PJ_LOG(6, (THIS_FILE,
"fifobuf_free fifobuf=%p, ptr=%p, size=%d, p1=%p, p2=%p",
fifobuf, buf, sz, fifobuf->ubegin, fifobuf->uend));
return 0;
}