blob: 62f66cccf18b8e8e3fff6847e73de9813bbffdf8 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id: fifobuf.c 4537 2013-06-19 06:47:43Z riza $ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <pj/fifobuf.h>
21#include <pj/log.h>
22#include <pj/assert.h>
23#include <pj/os.h>
24
25#define THIS_FILE "fifobuf"
26
27#define SZ sizeof(unsigned)
28
29PJ_DEF(void) pj_fifobuf_init (pj_fifobuf_t *fifobuf, void *buffer, unsigned size)
30{
31 PJ_CHECK_STACK();
32
33 PJ_LOG(6, (THIS_FILE,
34 "fifobuf_init fifobuf=%p buffer=%p, size=%d",
35 fifobuf, buffer, size));
36
37 fifobuf->first = (char*)buffer;
38 fifobuf->last = fifobuf->first + size;
39 fifobuf->ubegin = fifobuf->uend = fifobuf->first;
40 fifobuf->full = 0;
41}
42
43PJ_DEF(unsigned) pj_fifobuf_max_size (pj_fifobuf_t *fifobuf)
44{
45 unsigned s1, s2;
46
47 PJ_CHECK_STACK();
48
49 if (fifobuf->uend >= fifobuf->ubegin) {
50 s1 = (unsigned)(fifobuf->last - fifobuf->uend);
51 s2 = (unsigned)(fifobuf->ubegin - fifobuf->first);
52 } else {
53 s1 = s2 = (unsigned)(fifobuf->ubegin - fifobuf->uend);
54 }
55
56 return s1<s2 ? s2 : s1;
57}
58
59PJ_DEF(void*) pj_fifobuf_alloc (pj_fifobuf_t *fifobuf, unsigned size)
60{
61 unsigned available;
62 char *start;
63
64 PJ_CHECK_STACK();
65
66 if (fifobuf->full) {
67 PJ_LOG(6, (THIS_FILE,
68 "fifobuf_alloc fifobuf=%p, size=%d: full!",
69 fifobuf, size));
70 return NULL;
71 }
72
73 /* try to allocate from the end part of the fifo */
74 if (fifobuf->uend >= fifobuf->ubegin) {
75 available = (unsigned)(fifobuf->last - fifobuf->uend);
76 if (available >= size+SZ) {
77 char *ptr = fifobuf->uend;
78 fifobuf->uend += (size+SZ);
79 if (fifobuf->uend == fifobuf->last)
80 fifobuf->uend = fifobuf->first;
81 if (fifobuf->uend == fifobuf->ubegin)
82 fifobuf->full = 1;
83 *(unsigned*)ptr = size+SZ;
84 ptr += SZ;
85
86 PJ_LOG(6, (THIS_FILE,
87 "fifobuf_alloc fifobuf=%p, size=%d: returning %p, p1=%p, p2=%p",
88 fifobuf, size, ptr, fifobuf->ubegin, fifobuf->uend));
89 return ptr;
90 }
91 }
92
93 /* try to allocate from the start part of the fifo */
94 start = (fifobuf->uend <= fifobuf->ubegin) ? fifobuf->uend : fifobuf->first;
95 available = (unsigned)(fifobuf->ubegin - start);
96 if (available >= size+SZ) {
97 char *ptr = start;
98 fifobuf->uend = start + size + SZ;
99 if (fifobuf->uend == fifobuf->ubegin)
100 fifobuf->full = 1;
101 *(unsigned*)ptr = size+SZ;
102 ptr += SZ;
103
104 PJ_LOG(6, (THIS_FILE,
105 "fifobuf_alloc fifobuf=%p, size=%d: returning %p, p1=%p, p2=%p",
106 fifobuf, size, ptr, fifobuf->ubegin, fifobuf->uend));
107 return ptr;
108 }
109
110 PJ_LOG(6, (THIS_FILE,
111 "fifobuf_alloc fifobuf=%p, size=%d: no space left! p1=%p, p2=%p",
112 fifobuf, size, fifobuf->ubegin, fifobuf->uend));
113 return NULL;
114}
115
116PJ_DEF(pj_status_t) pj_fifobuf_unalloc (pj_fifobuf_t *fifobuf, void *buf)
117{
118 char *ptr = (char*)buf;
119 char *endptr;
120 unsigned sz;
121
122 PJ_CHECK_STACK();
123
124 ptr -= SZ;
125 sz = *(unsigned*)ptr;
126
127 endptr = fifobuf->uend;
128 if (endptr == fifobuf->first)
129 endptr = fifobuf->last;
130
131 if (ptr+sz != endptr) {
132 pj_assert(!"Invalid pointer to undo alloc");
133 return -1;
134 }
135
136 fifobuf->uend = ptr;
137 fifobuf->full = 0;
138
139 PJ_LOG(6, (THIS_FILE,
140 "fifobuf_unalloc fifobuf=%p, ptr=%p, size=%d, p1=%p, p2=%p",
141 fifobuf, buf, sz, fifobuf->ubegin, fifobuf->uend));
142
143 return 0;
144}
145
146PJ_DEF(pj_status_t) pj_fifobuf_free (pj_fifobuf_t *fifobuf, void *buf)
147{
148 char *ptr = (char*)buf;
149 char *end;
150 unsigned sz;
151
152 PJ_CHECK_STACK();
153
154 ptr -= SZ;
155 if (ptr < fifobuf->first || ptr >= fifobuf->last) {
156 pj_assert(!"Invalid pointer to free");
157 return -1;
158 }
159
160 if (ptr != fifobuf->ubegin && ptr != fifobuf->first) {
161 pj_assert(!"Invalid free() sequence!");
162 return -1;
163 }
164
165 end = (fifobuf->uend > fifobuf->ubegin) ? fifobuf->uend : fifobuf->last;
166 sz = *(unsigned*)ptr;
167 if (ptr+sz > end) {
168 pj_assert(!"Invalid size!");
169 return -1;
170 }
171
172 fifobuf->ubegin = ptr + sz;
173
174 /* Rollover */
175 if (fifobuf->ubegin == fifobuf->last)
176 fifobuf->ubegin = fifobuf->first;
177
178 /* Reset if fifobuf is empty */
179 if (fifobuf->ubegin == fifobuf->uend)
180 fifobuf->ubegin = fifobuf->uend = fifobuf->first;
181
182 fifobuf->full = 0;
183
184 PJ_LOG(6, (THIS_FILE,
185 "fifobuf_free fifobuf=%p, ptr=%p, size=%d, p1=%p, p2=%p",
186 fifobuf, buf, sz, fifobuf->ubegin, fifobuf->uend));
187
188 return 0;
189}