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 24typedef 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 33typedef 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 68Buf_BufferQueue 69Buf_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 99void 100Buf_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 144int 145Buf_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 216int 217Buf_QueueWrite (queue, inbuf, size) 218Buf_BufferQueue queue; 219CONST char* inbuf; 220int 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 290void 291Buf_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 349int 350Buf_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