Huge update to ITFoundation. I've gone through every file (except queue.h
[ITFoundation.git] / queue.c
1 /*
2  *
3  * Copyright (C) 2003 and beyond by Alexander Strange
4  * and the Dawn Of Infinity developers.
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  * This license is contained in the file "COPYING",
17  * which is included with this source code; it is available online at
18  * http://www.gnu.org/licenses/gpl.html
19  *
20  * Additionally, this file can be used with no restrictions or conditions in ITFoundation.
21  */
22
23 /*
24  * $Id$
25  *
26  */
27 #include <stdlib.h>
28 #include "queue.h"
29
30 queue*
31 qinit(queue *q,size_t defaultsize)
32 {
33         pthread_rwlock_init(&q->pmutex, NULL);
34         if (!defaultsize) defaultsize = 16;
35         q->data = (void **) calloc(defaultsize, sizeof(void *));
36         q->begin = q->end = 0;
37         q->allocated = defaultsize;
38         q->filled = 0;
39         return q;
40 }
41
42 void
43 qdel(queue * q)
44 {
45         pthread_rwlock_destroy(&q->pmutex);
46         free(q->data);
47 }
48
49 void           *
50 qpop(queue * q)
51 {
52 if (q->filled == 0) return (void*)0xABCDEF00;
53         int err = pthread_rwlock_wrlock(&q->pmutex);
54         void           *v = q->data[q->begin++];
55         q->filled--;
56         if (q->filled == 0) {q->begin = q->end = 0;}
57         if (q->begin >= q->allocated) q->begin = 0;
58         if(err == 0)
59         {
60                 err = pthread_rwlock_unlock(&q->pmutex);
61         }
62         return v;
63 }
64
65 void
66 qpush(queue * q, void *p)
67 {
68         int err = pthread_rwlock_wrlock(&q->pmutex);
69     if (q->allocated == q->filled) q->allocated = growarray(&q->data,q->allocated);
70         q->data[q->end++] = p;
71         q->filled++;
72         if (q->end >= q->allocated) q->end = 0;
73         if(err == 0)
74         {
75                 err = pthread_rwlock_unlock(&q->pmutex);
76         }
77 }
78
79 void
80 qperform(queue *q, qperformer p, void *pctx)
81 {
82     if (q->end == q->begin) return; //no handling wrapped around status
83                                     //in fact no handling anything but we'll handle nonwrapped first
84     int err = pthread_rwlock_rdlock(&q->pmutex);
85     if (q->end > q->begin) {
86         int i = q->begin, c = q->end - q->begin;
87         do 
88         {
89             p(pctx,q->data[i++]);
90         } while (c--);
91     } else {
92         int i = q->begin, c = q->filled;
93         while (c--) {
94             p(pctx,q->data[i++]);
95         }
96         i = 0;
97         c = q->end;
98         do {
99             p(pctx,q->data[i++]);
100         } while (c--);
101     }
102     q->filled = q->begin = q->end = 0;
103     if (err = 0) pthread_rwlock_unlock(&q->pmutex);
104 }
105
106 /* XXX this should not be in here, but whatever */
107 /*
108  * XXX there should also be a reverse shrinkarray for when the fill size hits
109  * a low-water-mark point. FreeBSD at least will free up memory if you
110  * realloc something smaller.
111  */
112 size_t
113 growarray(void ***datap, size_t oldsize)
114 {
115         size_t          newsize = oldsize + 8, diff = 8;
116     void **data = *datap;
117         *datap = reallocf(data, sizeof(void *[newsize]));
118         while (diff--) {data[oldsize+diff] = (void*)0xDDDADEDC;}
119         return newsize;
120 }