ITOSA looks like NSAppleScript, almost. It works quite well now, except
[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  */
21
22 /*
23  * $Id$
24  *
25  */
26 #include <stdlib.h>
27 #include "queue.h"
28
29 queue*
30 qinit(queue *q,size_t defaultsize)
31 {
32         pthread_rwlock_init(&q->pmutex, NULL);
33         if (!defaultsize) defaultsize = 16;
34         q->data = (void **) calloc(defaultsize, sizeof(void *));
35         q->begin = q->end = 0;
36         q->allocated = defaultsize;
37         q->filled = 0;
38         return q;
39 }
40
41 void
42 qdel(queue * q)
43 {
44         pthread_rwlock_destroy(&q->pmutex);
45         free(q->data);
46 }
47
48 void           *
49 qpop(queue * q)
50 {
51 if (q->filled == 0) return (void*)0xABCDEF00;
52         int err = pthread_rwlock_wrlock(&q->pmutex);
53         void           *v = q->data[q->begin++];
54         q->filled--;
55         if (q->filled == 0) {q->begin = q->end = 0;}
56         if (q->begin >= q->allocated) q->begin = 0;
57         if(err == 0)
58         {
59                 err = pthread_rwlock_unlock(&q->pmutex);
60         }
61         return v;
62 }
63
64 void
65 qpush(queue * q, void *p)
66 {
67         int err = pthread_rwlock_wrlock(&q->pmutex);
68     if (q->allocated == q->filled) q->allocated = growarray(&q->data,q->allocated);
69         q->data[q->end++] = p;
70         q->filled++;
71         if (q->end >= q->allocated) q->end = 0;
72         if(err == 0)
73         {
74                 err = pthread_rwlock_unlock(&q->pmutex);
75         }
76 }
77
78 void
79 qperform(queue *q, qperformer p, void *pctx)
80 {
81     if (q->end == q->begin) return; //no handling wrapped around status
82                                     //in fact no handling anything but we'll handle nonwrapped first
83     int err = pthread_rwlock_rdlock(&q->pmutex);
84     if (q->end > q->begin) {
85         int i = q->begin, c = q->end - q->begin;
86         do 
87         {
88             p(pctx,q->data[i++]);
89         } while (c--);
90     } else {
91         int i = q->begin, c = q->filled;
92         while (c--) {
93             p(pctx,q->data[i++]);
94         }
95         i = 0;
96         c = q->end;
97         do {
98             p(pctx,q->data[i++]);
99         } while (c--);
100     }
101     q->filled = q->begin = q->end = 0;
102     if (err = 0) pthread_rwlock_unlock(&q->pmutex);
103 }
104
105 /* XXX this should not be in here, but whatever */
106 /*
107  * XXX there should also be a reverse shrinkarray for when the fill size hits
108  * a low-water-mark point. FreeBSD at least will free up memory if you
109  * realloc something smaller.
110  */
111 size_t
112 growarray(void ***datap, size_t oldsize)
113 {
114         size_t          newsize = oldsize + 8, diff = 8;
115     void **data = *datap;
116         *datap = reallocf(data, sizeof(void *[newsize]));
117         while (diff--) {data[oldsize+diff] = (void*)0xDDDADEDC;}
118         return newsize;
119 }