426 lines
11 KiB
C
426 lines
11 KiB
C
/*
|
|
* SpanDSP - a series of DSP components for telephony
|
|
*
|
|
* queue.c - simple in-process message queuing
|
|
*
|
|
* Written by Steve Underwood <steveu@coppice.org>
|
|
*
|
|
* Copyright (C) 2004 Steve Underwood
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 2.1,
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* 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 Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
* $Id: queue.c,v 1.31 2009/04/11 18:11:19 steveu Exp $
|
|
*/
|
|
|
|
/*! \file */
|
|
|
|
#if defined(HAVE_CONFIG_H)
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
#include <inttypes.h>
|
|
#include <sys/types.h>
|
|
|
|
#define SPANDSP_FULLY_DEFINE_QUEUE_STATE_T
|
|
#include "spandsp/telephony.h"
|
|
#include "spandsp/queue.h"
|
|
|
|
#include "spandsp/private/queue.h"
|
|
|
|
SPAN_DECLARE(int) queue_empty(queue_state_t *s)
|
|
{
|
|
return (s->iptr == s->optr);
|
|
}
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
SPAN_DECLARE(int) queue_free_space(queue_state_t *s)
|
|
{
|
|
int len;
|
|
|
|
if ((len = s->optr - s->iptr - 1) < 0)
|
|
len += s->len;
|
|
/*endif*/
|
|
return len;
|
|
}
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
SPAN_DECLARE(int) queue_contents(queue_state_t *s)
|
|
{
|
|
int len;
|
|
|
|
if ((len = s->iptr - s->optr) < 0)
|
|
len += s->len;
|
|
/*endif*/
|
|
return len;
|
|
}
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
SPAN_DECLARE(void) queue_flush(queue_state_t *s)
|
|
{
|
|
s->optr = s->iptr;
|
|
}
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
SPAN_DECLARE(int) queue_view(queue_state_t *s, uint8_t *buf, int len)
|
|
{
|
|
int real_len;
|
|
int to_end;
|
|
int iptr;
|
|
int optr;
|
|
|
|
/* Snapshot the values (although only iptr should be changeable during this processing) */
|
|
iptr = s->iptr;
|
|
optr = s->optr;
|
|
if ((real_len = iptr - optr) < 0)
|
|
real_len += s->len;
|
|
/*endif*/
|
|
if (real_len < len)
|
|
{
|
|
if (s->flags & QUEUE_READ_ATOMIC)
|
|
return -1;
|
|
/*endif*/
|
|
}
|
|
else
|
|
{
|
|
real_len = len;
|
|
}
|
|
/*endif*/
|
|
if (real_len == 0)
|
|
return 0;
|
|
/*endif*/
|
|
to_end = s->len - optr;
|
|
if (iptr < optr && to_end < real_len)
|
|
{
|
|
/* A two step process */
|
|
if (buf)
|
|
{
|
|
memcpy(buf, s->data + optr, to_end);
|
|
memcpy(buf + to_end, s->data, real_len - to_end);
|
|
}
|
|
/*endif*/
|
|
}
|
|
else
|
|
{
|
|
/* A one step process */
|
|
if (buf)
|
|
memcpy(buf, s->data + optr, real_len);
|
|
/*endif*/
|
|
}
|
|
/*endif*/
|
|
return real_len;
|
|
}
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
SPAN_DECLARE(int) queue_read(queue_state_t *s, uint8_t *buf, int len)
|
|
{
|
|
int real_len;
|
|
int to_end;
|
|
int new_optr;
|
|
int iptr;
|
|
int optr;
|
|
|
|
/* Snapshot the values (although only iptr should be changeable during this processing) */
|
|
iptr = s->iptr;
|
|
optr = s->optr;
|
|
if ((real_len = iptr - optr) < 0)
|
|
real_len += s->len;
|
|
/*endif*/
|
|
if (real_len < len)
|
|
{
|
|
if (s->flags & QUEUE_READ_ATOMIC)
|
|
return -1;
|
|
/*endif*/
|
|
}
|
|
else
|
|
{
|
|
real_len = len;
|
|
}
|
|
/*endif*/
|
|
if (real_len == 0)
|
|
return 0;
|
|
/*endif*/
|
|
to_end = s->len - optr;
|
|
if (iptr < optr && to_end < real_len)
|
|
{
|
|
/* A two step process */
|
|
if (buf)
|
|
{
|
|
memcpy(buf, s->data + optr, to_end);
|
|
memcpy(buf + to_end, s->data, real_len - to_end);
|
|
}
|
|
/*endif*/
|
|
new_optr = real_len - to_end;
|
|
}
|
|
else
|
|
{
|
|
/* A one step process */
|
|
if (buf)
|
|
memcpy(buf, s->data + optr, real_len);
|
|
/*endif*/
|
|
new_optr = optr + real_len;
|
|
if (new_optr >= s->len)
|
|
new_optr = 0;
|
|
/*endif*/
|
|
}
|
|
/*endif*/
|
|
/* Only change the pointer now we have really finished */
|
|
s->optr = new_optr;
|
|
return real_len;
|
|
}
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
SPAN_DECLARE(int) queue_read_byte(queue_state_t *s)
|
|
{
|
|
int real_len;
|
|
int to_end;
|
|
int iptr;
|
|
int optr;
|
|
int byte;
|
|
|
|
/* Snapshot the values (although only iptr should be changeable during this processing) */
|
|
iptr = s->iptr;
|
|
optr = s->optr;
|
|
if ((real_len = iptr - optr) < 0)
|
|
real_len += s->len;
|
|
/*endif*/
|
|
if (real_len < 1)
|
|
return -1;
|
|
/*endif*/
|
|
to_end = s->len - optr;
|
|
byte = s->data[optr];
|
|
if (++optr >= s->len)
|
|
optr = 0;
|
|
/*endif*/
|
|
/* Only change the pointer now we have really finished */
|
|
s->optr = optr;
|
|
return byte;
|
|
}
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
SPAN_DECLARE(int) queue_write(queue_state_t *s, const uint8_t *buf, int len)
|
|
{
|
|
int real_len;
|
|
int to_end;
|
|
int new_iptr;
|
|
int iptr;
|
|
int optr;
|
|
|
|
/* Snapshot the values (although only optr should be changeable during this processing) */
|
|
iptr = s->iptr;
|
|
optr = s->optr;
|
|
|
|
if ((real_len = optr - iptr - 1) < 0)
|
|
real_len += s->len;
|
|
/*endif*/
|
|
if (real_len < len)
|
|
{
|
|
if (s->flags & QUEUE_WRITE_ATOMIC)
|
|
return -1;
|
|
/*endif*/
|
|
}
|
|
else
|
|
{
|
|
real_len = len;
|
|
}
|
|
/*endif*/
|
|
if (real_len == 0)
|
|
return 0;
|
|
/*endif*/
|
|
to_end = s->len - iptr;
|
|
if (iptr < optr || to_end >= real_len)
|
|
{
|
|
/* A one step process */
|
|
memcpy(s->data + iptr, buf, real_len);
|
|
new_iptr = iptr + real_len;
|
|
if (new_iptr >= s->len)
|
|
new_iptr = 0;
|
|
/*endif*/
|
|
}
|
|
else
|
|
{
|
|
/* A two step process */
|
|
memcpy(s->data + iptr, buf, to_end);
|
|
memcpy(s->data, buf + to_end, real_len - to_end);
|
|
new_iptr = real_len - to_end;
|
|
}
|
|
/*endif*/
|
|
/* Only change the pointer now we have really finished */
|
|
s->iptr = new_iptr;
|
|
return real_len;
|
|
}
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
SPAN_DECLARE(int) queue_write_byte(queue_state_t *s, uint8_t byte)
|
|
{
|
|
int real_len;
|
|
int iptr;
|
|
int optr;
|
|
|
|
/* Snapshot the values (although only optr should be changeable during this processing) */
|
|
iptr = s->iptr;
|
|
optr = s->optr;
|
|
|
|
if ((real_len = optr - iptr - 1) < 0)
|
|
real_len += s->len;
|
|
/*endif*/
|
|
if (real_len < 1)
|
|
{
|
|
if (s->flags & QUEUE_WRITE_ATOMIC)
|
|
return -1;
|
|
/*endif*/
|
|
return 0;
|
|
}
|
|
/*endif*/
|
|
s->data[iptr] = byte;
|
|
if (++iptr >= s->len)
|
|
iptr = 0;
|
|
/*endif*/
|
|
/* Only change the pointer now we have really finished */
|
|
s->iptr = iptr;
|
|
return 1;
|
|
}
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
SPAN_DECLARE(int) queue_state_test_msg(queue_state_t *s)
|
|
{
|
|
uint16_t lenx;
|
|
|
|
if (queue_view(s, (uint8_t *) &lenx, sizeof(uint16_t)) != sizeof(uint16_t))
|
|
return -1;
|
|
/*endif*/
|
|
return lenx;
|
|
}
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
SPAN_DECLARE(int) queue_read_msg(queue_state_t *s, uint8_t *buf, int len)
|
|
{
|
|
uint16_t lenx;
|
|
|
|
/* If we assume the write message was atomic, this read message should be
|
|
safe when conducted in multiple chunks */
|
|
if (queue_read(s, (uint8_t *) &lenx, sizeof(uint16_t)) != sizeof(uint16_t))
|
|
return -1;
|
|
/*endif*/
|
|
/* If we got this far, the actual message chunk should be guaranteed to be
|
|
available */
|
|
if (lenx == 0)
|
|
return 0;
|
|
/*endif*/
|
|
if ((int) lenx > len)
|
|
{
|
|
len = queue_read(s, buf, len);
|
|
/* Discard the rest of the message */
|
|
queue_read(s, NULL, lenx - len);
|
|
return len;
|
|
}
|
|
/*endif*/
|
|
return queue_read(s, buf, lenx);
|
|
}
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
SPAN_DECLARE(int) queue_write_msg(queue_state_t *s, const uint8_t *buf, int len)
|
|
{
|
|
int real_len;
|
|
int to_end;
|
|
int new_iptr;
|
|
int iptr;
|
|
int optr;
|
|
uint16_t lenx;
|
|
|
|
/* Snapshot the values (although only optr should be changeable during this processing) */
|
|
iptr = s->iptr;
|
|
optr = s->optr;
|
|
|
|
if ((real_len = optr - iptr - 1) < 0)
|
|
real_len += s->len;
|
|
/*endif*/
|
|
if (real_len < len + (int) sizeof(uint16_t))
|
|
return -1;
|
|
/*endif*/
|
|
real_len = len + (int) sizeof(uint16_t);
|
|
|
|
to_end = s->len - iptr;
|
|
lenx = (uint16_t) len;
|
|
if (iptr < optr || to_end >= real_len)
|
|
{
|
|
/* A one step process */
|
|
memcpy(s->data + iptr, &lenx, sizeof(uint16_t));
|
|
memcpy(s->data + iptr + sizeof(uint16_t), buf, len);
|
|
new_iptr = iptr + real_len;
|
|
if (new_iptr >= s->len)
|
|
new_iptr = 0;
|
|
/*endif*/
|
|
}
|
|
else
|
|
{
|
|
/* A two step process */
|
|
if (to_end >= sizeof(uint16_t))
|
|
{
|
|
/* The actual message wraps around the end of the buffer */
|
|
memcpy(s->data + iptr, &lenx, sizeof(uint16_t));
|
|
memcpy(s->data + iptr + sizeof(uint16_t), buf, to_end - sizeof(uint16_t));
|
|
memcpy(s->data, buf + to_end - sizeof(uint16_t), real_len - to_end);
|
|
}
|
|
else
|
|
{
|
|
/* The message length wraps around the end of the buffer */
|
|
memcpy(s->data + iptr, (uint8_t *) &lenx, to_end);
|
|
memcpy(s->data, ((uint8_t *) &lenx) + to_end, sizeof(uint16_t) - to_end);
|
|
memcpy(s->data + sizeof(uint16_t) - to_end, buf, len);
|
|
}
|
|
new_iptr = real_len - to_end;
|
|
}
|
|
/*endif*/
|
|
/* Only change the pointer now we have really finished */
|
|
s->iptr = new_iptr;
|
|
return len;
|
|
}
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
SPAN_DECLARE(queue_state_t *) queue_init(queue_state_t *s, int len, int flags)
|
|
{
|
|
if (s == NULL)
|
|
{
|
|
if ((s = (queue_state_t *) malloc(sizeof(*s) + len + 1)) == NULL)
|
|
return NULL;
|
|
}
|
|
s->iptr =
|
|
s->optr = 0;
|
|
s->flags = flags;
|
|
s->len = len + 1;
|
|
return s;
|
|
}
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
SPAN_DECLARE(int) queue_release(queue_state_t *s)
|
|
{
|
|
return 0;
|
|
}
|
|
/*- End of function --------------------------------------------------------*/
|
|
|
|
SPAN_DECLARE(int) queue_free(queue_state_t *s)
|
|
{
|
|
free(s);
|
|
return 0;
|
|
}
|
|
/*- End of function --------------------------------------------------------*/
|
|
/*- End of file ------------------------------------------------------------*/
|