1 /*
2 * bufQueue.c --
3 *
4 * Implementation of a queue out of buffers.
5 *
6 * Copyright (c) 2000 by Andreas Kupries <a.kupries@westend.com>
7 *
8 * See the file "license.terms" for information on usage and redistribution
9 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10 *
11 * RCS: @(#) $Id: bufQueue.c,v 1.2 2002/04/25 06:29:48 andreas_kupries Exp $
12 */
13
14 #include "buf.h"
15
16 /*
17 * Internal structures used to hold the buffers in the queue.
18 */
19
20 /*
21 * Structure of a node in the queue.
22 */
23
24 typedef struct QNode_ {
25 Buf_Buffer buf; /* The buffer managed by the node */
26 struct QNode_* nextPtr; /* Reference to the next node/buffer */
27 } QNode;
28
29 /*
30 * Structure of the whole queue.
31 */
32
33 typedef struct Queue_ {
34 QNode* firstNode; /* Head of the queue */
35 QNode* lastNode; /* Last node/buffer in the queue */
36 int size; /* Number of bytes stored in the queue */
37 #if GT81
38 Tcl_Mutex lock; /* mutex to serialize access to the
39 * queue when more than one thread
40 * is trying to access it. */
41 #endif
42 } Queue;
43
44 /*
45 * Declaration of size to use for new buffers when
46 * extending the queue
47 */
48
49 #define BUF_SIZE (1024)
50
51
52 /*
53 *------------------------------------------------------*
54 *
55 * Buf_NewQueue --
56 *
57 * Creates a new, empty queue.
58 *
59 * Sideeffects:
60 * Allocates and initializes memory.
61 *
62 * Result:
63 * A queue token.
64 *
65 *------------------------------------------------------*
66 */
67
68 Buf_BufferQueue
Buf_NewQueue()69 Buf_NewQueue ()
70 {
71 Queue* q = (Queue*) Tcl_Alloc (sizeof (Queue));
72
73 q->firstNode = (QNode*) NULL;
74 q->lastNode = (QNode*) NULL;
75 q->size = 0;
76 #if GT81
77 q->lock = (Tcl_Mutex) NULL;
78 #endif
79 return (Buf_BufferQueue) q;
80 }
81
82 /*
83 *------------------------------------------------------*
84 *
85 * Buf_FreeQueue --
86 *
87 * Deletes the specified queue.
88 *
89 * Sideeffects:
90 * Deallocates the memory which was
91 * allocated in Buf_NewQueue.
92 *
93 * Result:
94 * None.
95 *
96 *------------------------------------------------------*
97 */
98
99 void
Buf_FreeQueue(queue)100 Buf_FreeQueue (queue)
101 Buf_BufferQueue queue;
102 {
103 Queue* q = (Queue*) queue;
104 QNode* n = q->firstNode;
105 QNode* tmp;
106
107 #if GT81
108 Tcl_MutexLock (&q->lock);
109 #endif
110
111 while (n != (QNode*) NULL) {
112 Buf_DecrRefcount (n->buf);
113 tmp = n->nextPtr;
114 Tcl_Free ((char*) n);
115 n = tmp;
116 }
117
118 #if GT81
119 Tcl_MutexUnlock (&q->lock);
120 Tcl_MutexFinalize (&q->lock);
121 #endif
122 Tcl_Free((char*) q);
123 return;
124 }
125
126 /*
127 *------------------------------------------------------*
128 *
129 * Buf_QueueRead --
130 *
131 * Reads information from the queue. The read data
132 * is deleted from the queue.
133 *
134 * Sideeffects:
135 * May deallocate memory. Moves the access
136 * pointer in the queue buffers.
137 *
138 * Result:
139 * Returns the number of bytes actually read.
140 *
141 *------------------------------------------------------*
142 */
143
144 int
Buf_QueueRead(queue,outbuf,size)145 Buf_QueueRead (queue, outbuf, size)
146 Buf_BufferQueue queue;
147 char* outbuf;
148 int size;
149 {
150 Queue* q = (Queue*) queue;
151 QNode* n;
152 int got, read;
153
154 #if GT81
155 Tcl_MutexLock (&q->lock);
156 #endif
157
158 n = q->firstNode;
159
160 if ((size <= 0) || (n == (QNode*) NULL)) {
161 #if GT81
162 Tcl_MutexUnlock (&q->lock);
163 #endif
164 return 0;
165 }
166
167 read = 0;
168 while ((size > 0) && (n != (QNode*) NULL)) {
169 got = Buf_Read (n->buf, outbuf, size);
170
171 if (got > 0) {
172 read += got;
173 outbuf += got;
174 size -= got;
175 }
176
177 if (size > 0) {
178 Buf_DecrRefcount (n->buf);
179 q->firstNode = n->nextPtr;
180 Tcl_Free ((char*) n);
181 n = q->firstNode;
182 }
183 }
184
185 if (n == (QNode*) NULL) {
186 q->lastNode = (QNode*) NULL;
187 }
188
189 q->size -= read;
190
191 #if GT81
192 Tcl_MutexUnlock (&q->lock);
193 #endif
194
195 return read;
196 }
197
198 /*
199 *------------------------------------------------------*
200 *
201 * Buf_QueueWrite --
202 *
203 * Writes information to the queue. The written data
204 * is appended at the end of the queue.
205 *
206 * Sideeffects:
207 * May allocate memory. Moves the access
208 * pointer in the queue buffers.
209 *
210 * Result:
211 * Returns the number of bytes actually written.
212 *
213 *------------------------------------------------------*
214 */
215
216 int
Buf_QueueWrite(queue,inbuf,size)217 Buf_QueueWrite (queue, inbuf, size)
218 Buf_BufferQueue queue;
219 CONST char* inbuf;
220 int size;
221 {
222 Queue* q = (Queue*) queue;
223 QNode* n;
224 int done, written;
225
226 if ((size <= 0)) {
227 return 0;
228 }
229
230 #if GT81
231 Tcl_MutexLock (&q->lock);
232 #endif
233
234 n = q->firstNode;
235 written = 0;
236
237 while (size > 0) {
238 if (n == (QNode*) NULL) {
239 n = (QNode*) Tcl_Alloc (sizeof (QNode));
240 n->nextPtr = (QNode*) NULL;
241 n->buf = Buf_CreateFixedBuffer (BUF_SIZE);
242
243 if (q->lastNode == (QNode*) NULL) {
244 q->firstNode = n;
245 } else {
246 q->lastNode->nextPtr = n;
247 }
248
249 q->lastNode = n;
250 }
251
252 done = Buf_Write (n->buf, inbuf, size);
253
254 if (done > 0) {
255 written += done;
256 inbuf += done;
257 size -= done;
258 }
259 if (size > 0) {
260 n = (QNode*) NULL;
261 }
262 }
263
264 q->size += written;
265
266 #if GT81
267 Tcl_MutexUnlock (&q->lock);
268 #endif
269
270 return written;
271 }
272
273 /*
274 *------------------------------------------------------*
275 *
276 * BufQueue_Append --
277 *
278 * Appends a range containing the information
279 * not yet read from the specified buffer to the queue.
280 *
281 * Sideeffects:
282 * Creates a range buffer, allocates memory.
283 *
284 * Result:
285 * None.
286 *
287 *------------------------------------------------------*
288 */
289
290 void
Buf_QueueAppend(queue,buf)291 Buf_QueueAppend (queue, buf)
292 Buf_BufferQueue queue;
293 Buf_Buffer buf;
294 {
295 /* Not the buffer is appended, but a range containing
296 * the rest of the data to read from it.
297 *
298 * Allows external usage of the buffer without affecting
299 * the queue. Writing (s.a.) is no problem, as ranges
300 * always return that nothing was written and thus force
301 * the system to append a new fixed-size buffer behind them.
302 */
303
304 Queue* q = (Queue*) queue;
305 QNode* n;
306
307 #if GT81
308 Tcl_MutexLock (&q->lock);
309 #endif
310
311 buf = Buf_CreateRange (buf, Buf_Size (buf));
312
313 n = (QNode*) Tcl_Alloc (sizeof (QNode));
314 n->nextPtr = (QNode*) NULL;
315 n->buf = buf;
316
317 if (q->lastNode == (QNode*) NULL) {
318 q->firstNode = n;
319 } else {
320 q->lastNode->nextPtr = n;
321 }
322
323 q->lastNode = n;
324
325 q->size += Buf_Size (buf);
326
327 #if GT81
328 Tcl_MutexUnlock (&q->lock);
329 #endif
330 return;
331 }
332
333 /*
334 *------------------------------------------------------*
335 *
336 * BufQueue_Size --
337 *
338 * Returns the current number of bytes stored in the queue.
339 *
340 * Sideeffects:
341 * None.
342 *
343 * Result:
344 * None.
345 *
346 *------------------------------------------------------*
347 */
348
349 int
Buf_QueueSize(queue)350 Buf_QueueSize (queue)
351 Buf_BufferQueue queue;
352 {
353 Queue* q = (Queue*) queue;
354 int size;
355
356 #if GT81
357 Tcl_MutexLock (&q->lock);
358 #endif
359
360 size = q->size;
361
362 #if GT81
363 Tcl_MutexUnlock (&q->lock);
364 #endif
365 return size;
366 }
367