|
|
1.1 root 1: /* ringbuf.c */
2:
3: /* Synchronet ring buffer routines */
4:
5: /* $Id: ringbuf.c,v 1.27 2005/10/21 21:52:45 deuce Exp $ */
6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
11: * Copyright 2005 Rob Swindell - http://www.synchro.net/copyright.html *
12: * *
13: * This program is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU General Public License for more details: gpl.txt or *
18: * http://www.fsf.org/copyleft/gpl.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: /* Pre-define RINGBUF_USE_STD_RTL to use standard C runtime library symbols
39: * for malloc, free, and memcpy
40: */
41:
42: #ifdef VTOOLSD
43: #include <vtoolsd.h>
44: #include LOCKED_CODE_SEGMENT
45: #include LOCKED_DATA_SEGMENT
46: #endif
47:
48: #include "ringbuf.h"
49: #include "genwrap.h" /* SLEEP() */
50:
51: #ifdef RINGBUF_USE_STD_RTL
52:
53: #ifndef VTOOLSD
54:
55: /* FreeBSD uses <stdlib.h> instead of <malloc.h> */
56: #ifdef __unix__
57: #include <stdlib.h>
58: #else
59: #include <malloc.h> /* malloc prototype */
60: #endif
61: #include <string.h> /* memcpy prototype */
62: #endif /* !VTOOLSD */
63:
64: #define os_malloc malloc
65: #define rb_malloc malloc
66: #define os_free free
67: #define rb_free free
68: #define os_memcpy memcpy
69: #define rb_memcpy memcpy
70:
71: #else
72:
73: void (*rb_free)(void *);
74: void *(*rb_memcpy)(void *, const void *, size_t);
75:
76: #endif
77: /****************************************************************************/
78: /* Returns 0 on success, non-zero on failure */
79: /****************************************************************************/
80: int RINGBUFCALL RingBufInit( RingBuf* rb, DWORD size
81: #ifndef RINGBUF_USE_STD_RTL
82: ,void *(os_malloc)(size_t)
83: ,void (os_free)(void *)
84: ,void *(os_memcpy)(void *, const void *, size_t)
85: #endif
86: )
87: {
88: memset(rb,0,sizeof(RingBuf));
89: if((rb->pStart=(BYTE *)os_malloc(size+1))==NULL)
90: return(-1);
91: #ifndef RINGBUF_USE_STD_RTL
92: rb_free=os_free;
93: rb_memcpy=os_memcpy;
94: #endif
95: rb->pHead=rb->pTail=rb->pStart;
96: rb->pEnd=rb->pStart+size;
97: rb->size=size;
98: #ifdef RINGBUF_SEM
99: sem_init(&rb->sem,0,0);
100: sem_init(&rb->highwater_sem,0,0);
101: #endif
102: #ifdef RINGBUF_EVENT
103: rb->empty_event=CreateEvent(NULL,TRUE,TRUE,NULL);
104: #endif
105: #ifdef RINGBUF_MUTEX
106: pthread_mutex_init(&rb->mutex,NULL);
107: #endif
108: return(0);
109: }
110:
111: void RINGBUFCALL RingBufDispose( RingBuf* rb)
112: {
113: if(rb->pStart!=NULL)
114: os_free(rb->pStart);
115: #ifdef RINGBUF_SEM
116: sem_post(&rb->sem); /* just incase someone's waiting */
117: while(sem_destroy(&rb->sem)==-1 && errno==EBUSY) {
118: SLEEP(1);
119: sem_post(&rb->sem);
120: }
121: while(sem_destroy(&rb->highwater_sem)==-1 && errno==EBUSY) {
122: SLEEP(1);
123: sem_post(&rb->highwater_sem);
124: }
125: #endif
126: #ifdef RINGBUF_EVENT
127: if(rb->empty_event!=NULL)
128: CloseEvent(rb->empty_event);
129: #endif
130: #ifdef RINGBUF_MUTEX
131: while(pthread_mutex_destroy(&rb->mutex)==EBUSY)
132: SLEEP(1);
133: #endif
134: memset(rb,0,sizeof(RingBuf));
135: }
136:
137: #define RINGBUF_FILL_LEVEL(rb) (rb->pHead >= rb->pTail ? (rb->pHead - rb->pTail) \
138: : (rb->size - (rb->pTail - (rb->pHead + 1))))
139:
140: DWORD RINGBUFCALL RingBufFull( RingBuf* rb )
141: {
142: DWORD retval;
143:
144: #ifdef RINGBUF_MUTEX
145: pthread_mutex_lock(&rb->mutex);
146: #endif
147:
148: retval = RINGBUF_FILL_LEVEL(rb);
149:
150: #ifdef RINGBUF_EVENT
151: if(rb->empty_event!=NULL) {
152: if(retval==0)
153: SetEvent(rb->empty_event);
154: else
155: ResetEvent(rb->empty_event);
156: }
157: #endif
158:
159: #ifdef RINGBUF_MUTEX
160: pthread_mutex_unlock(&rb->mutex);
161: #endif
162:
163: return(retval);
164: }
165:
166: DWORD RINGBUFCALL RingBufFree( RingBuf* rb )
167: {
168: DWORD retval;
169:
170: retval = (rb->size - RingBufFull( rb ));
171:
172: return(retval);
173: }
174:
175: DWORD RINGBUFCALL RingBufWrite( RingBuf* rb, BYTE* src, DWORD cnt )
176: {
177: DWORD max, first, remain;
178:
179: if(rb->pStart==NULL)
180: return(0);
181:
182: #ifdef RINGBUF_MUTEX
183: pthread_mutex_lock(&rb->mutex);
184: #endif
185:
186: /* allowed to write at pEnd */
187: max = (((DWORD) rb->pEnd) - ((DWORD) rb->pHead)) + 1;
188:
189: /*
190: * we assume the caller has checked that there is enough room. For this reason
191: * we do not have to worry about head wrapping past the tail
192: */
193:
194: if( max >= cnt ) {
195: first = cnt;
196: remain = 0;
197: } else {
198: first = max;
199: remain = cnt - first;
200: }
201:
202: rb_memcpy( rb->pHead, src, first );
203: rb->pHead += first;
204: src += first;
205:
206: if(remain) {
207:
208: rb->pHead = rb->pStart;
209: rb_memcpy(rb->pHead, src, remain);
210: rb->pHead += remain;
211: }
212:
213: if(rb->pHead > rb->pEnd)
214: rb->pHead = rb->pStart;
215:
216: #ifdef RINGBUF_SEM
217: sem_post(&rb->sem);
218: if(rb->highwater_mark!=0 && RINGBUF_FILL_LEVEL(rb)>=rb->highwater_mark)
219: sem_post(&rb->highwater_sem);
220: #endif
221: #ifdef RINGBUF_EVENT
222: if(rb->empty_event!=NULL)
223: ResetEvent(rb->empty_event);
224: #endif
225:
226: #ifdef RINGBUF_MUTEX
227: pthread_mutex_unlock(&rb->mutex);
228: #endif
229:
230: return(cnt);
231: }
232:
233: /* Pass NULL dst to just foward pointer (after Peek) */
234: DWORD RINGBUFCALL RingBufRead( RingBuf* rb, BYTE* dst, DWORD cnt )
235: {
236: DWORD max, first, remain, len;
237:
238: #ifdef RINGBUF_MUTEX
239: pthread_mutex_lock(&rb->mutex);
240: #endif
241:
242: len = RINGBUF_FILL_LEVEL(rb);
243:
244: if( len < cnt )
245: cnt = len;
246:
247: /* allowed to read at pEnd */
248: max = (((DWORD) rb->pEnd) - ((DWORD) rb->pTail)) + 1;
249:
250: if( max >= cnt ) {
251: first = cnt;
252: remain = 0;
253: } else {
254: first = max;
255: remain = cnt - first;
256: }
257:
258: if(first && dst!=NULL) {
259: rb_memcpy( dst, rb->pTail, first );
260: dst += first;
261: }
262: rb->pTail += first;
263:
264: if( remain ){
265:
266: rb->pTail = rb->pStart;
267: if(dst!=NULL)
268: rb_memcpy( dst, rb->pTail, remain );
269: rb->pTail += remain;
270: }
271:
272: if(rb->pTail > rb->pEnd)
273: rb->pTail = rb->pStart;
274:
275: #ifdef RINGBUF_SEM /* clear/signal semaphores, if appropriate */
276: if(RINGBUF_FILL_LEVEL(rb) == 0) /* empty */
277: sem_reset(&rb->sem);
278: if(RINGBUF_FILL_LEVEL(rb) < rb->highwater_mark)
279: sem_reset(&rb->highwater_sem);
280: #endif
281:
282: #ifdef RINGBUF_EVENT
283: if(rb->empty_event!=NULL && RINGBUF_FILL_LEVEL(rb)==0)
284: SetEvent(rb->empty_event);
285: #endif
286:
287: #ifdef RINGBUF_MUTEX
288: pthread_mutex_unlock(&rb->mutex);
289: #endif
290:
291: return(cnt);
292: }
293:
294: DWORD RINGBUFCALL RingBufPeek( RingBuf* rb, BYTE* dst, DWORD cnt)
295: {
296: DWORD max, first, remain, len;
297:
298: len = RingBufFull( rb );
299: if( len == 0 )
300: return(0);
301:
302: #ifdef RINGBUF_MUTEX
303: pthread_mutex_lock(&rb->mutex);
304: #endif
305:
306: if( len < cnt )
307: cnt = len;
308:
309: /* allowed to read at pEnd */
310: max = (((DWORD) rb->pEnd) - ((DWORD) rb->pTail)) + 1;
311:
312: if( max >= cnt ) {
313: first = cnt;
314: remain = 0;
315: } else {
316: first = max;
317: remain = cnt - first;
318: }
319:
320: rb_memcpy( dst, rb->pTail, first );
321: dst += first;
322:
323: if(remain) {
324: rb_memcpy( dst, rb->pStart, remain );
325: }
326:
327: #ifdef RINGBUF_MUTEX
328: pthread_mutex_unlock(&rb->mutex);
329: #endif
330:
331: return(cnt);
332: }
333:
334: /* Reset head and tail pointers */
335: void RINGBUFCALL RingBufReInit(RingBuf* rb)
336: {
337: #ifdef RINGBUF_MUTEX
338: pthread_mutex_lock(&rb->mutex);
339: #endif
340: rb->pHead = rb->pTail = rb->pStart;
341: #ifdef RINGBUF_SEM
342: sem_reset(&rb->sem);
343: sem_reset(&rb->highwater_sem);
344: #endif
345: #ifdef RINGBUF_MUTEX
346: pthread_mutex_unlock(&rb->mutex);
347: #endif
348: }
349:
350: /* End of RINGBUF.C */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.