|
|
1.1 root 1: /* ringbuf.c */
2:
3: /* Synchronet ring buffer routines */
4:
1.1.1.2 ! root 5: /* $Id: ringbuf.c,v 1.29 2011/04/21 20:52:27 deuce Exp $ */
1.1 root 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_MUTEX
151: pthread_mutex_unlock(&rb->mutex);
152: #endif
153:
154: return(retval);
155: }
156:
157: DWORD RINGBUFCALL RingBufFree( RingBuf* rb )
158: {
159: DWORD retval;
160:
161: retval = (rb->size - RingBufFull( rb ));
162:
163: return(retval);
164: }
165:
166: DWORD RINGBUFCALL RingBufWrite( RingBuf* rb, BYTE* src, DWORD cnt )
167: {
168: DWORD max, first, remain;
169:
1.1.1.2 ! root 170: if(cnt==0)
! 171: return(cnt);
! 172:
1.1 root 173: if(rb->pStart==NULL)
174: return(0);
175:
176: #ifdef RINGBUF_MUTEX
177: pthread_mutex_lock(&rb->mutex);
178: #endif
179:
180: /* allowed to write at pEnd */
1.1.1.2 ! root 181: max = rb->pEnd - rb->pHead + 1;
1.1 root 182:
183: /*
184: * we assume the caller has checked that there is enough room. For this reason
185: * we do not have to worry about head wrapping past the tail
186: */
187:
188: if( max >= cnt ) {
189: first = cnt;
190: remain = 0;
191: } else {
192: first = max;
193: remain = cnt - first;
194: }
195:
196: rb_memcpy( rb->pHead, src, first );
197: rb->pHead += first;
198: src += first;
199:
200: if(remain) {
201:
202: rb->pHead = rb->pStart;
203: rb_memcpy(rb->pHead, src, remain);
204: rb->pHead += remain;
205: }
206:
207: if(rb->pHead > rb->pEnd)
208: rb->pHead = rb->pStart;
209:
210: #ifdef RINGBUF_SEM
211: sem_post(&rb->sem);
212: if(rb->highwater_mark!=0 && RINGBUF_FILL_LEVEL(rb)>=rb->highwater_mark)
213: sem_post(&rb->highwater_sem);
214: #endif
215: #ifdef RINGBUF_EVENT
216: if(rb->empty_event!=NULL)
217: ResetEvent(rb->empty_event);
218: #endif
219:
220: #ifdef RINGBUF_MUTEX
221: pthread_mutex_unlock(&rb->mutex);
222: #endif
223:
224: return(cnt);
225: }
226:
227: /* Pass NULL dst to just foward pointer (after Peek) */
228: DWORD RINGBUFCALL RingBufRead( RingBuf* rb, BYTE* dst, DWORD cnt )
229: {
230: DWORD max, first, remain, len;
231:
232: #ifdef RINGBUF_MUTEX
233: pthread_mutex_lock(&rb->mutex);
234: #endif
235:
236: len = RINGBUF_FILL_LEVEL(rb);
237:
238: if( len < cnt )
239: cnt = len;
240:
241: /* allowed to read at pEnd */
1.1.1.2 ! root 242: max = rb->pEnd - rb->pTail + 1;
1.1 root 243:
244: if( max >= cnt ) {
245: first = cnt;
246: remain = 0;
247: } else {
248: first = max;
249: remain = cnt - first;
250: }
251:
252: if(first && dst!=NULL) {
253: rb_memcpy( dst, rb->pTail, first );
254: dst += first;
255: }
256: rb->pTail += first;
257:
258: if( remain ){
259:
260: rb->pTail = rb->pStart;
261: if(dst!=NULL)
262: rb_memcpy( dst, rb->pTail, remain );
263: rb->pTail += remain;
264: }
265:
266: if(rb->pTail > rb->pEnd)
267: rb->pTail = rb->pStart;
268:
269: #ifdef RINGBUF_SEM /* clear/signal semaphores, if appropriate */
270: if(RINGBUF_FILL_LEVEL(rb) == 0) /* empty */
271: sem_reset(&rb->sem);
272: if(RINGBUF_FILL_LEVEL(rb) < rb->highwater_mark)
273: sem_reset(&rb->highwater_sem);
274: #endif
275:
276: #ifdef RINGBUF_EVENT
277: if(rb->empty_event!=NULL && RINGBUF_FILL_LEVEL(rb)==0)
278: SetEvent(rb->empty_event);
279: #endif
280:
281: #ifdef RINGBUF_MUTEX
282: pthread_mutex_unlock(&rb->mutex);
283: #endif
284:
285: return(cnt);
286: }
287:
288: DWORD RINGBUFCALL RingBufPeek( RingBuf* rb, BYTE* dst, DWORD cnt)
289: {
290: DWORD max, first, remain, len;
291:
292: len = RingBufFull( rb );
293: if( len == 0 )
294: return(0);
295:
296: #ifdef RINGBUF_MUTEX
297: pthread_mutex_lock(&rb->mutex);
298: #endif
299:
300: if( len < cnt )
301: cnt = len;
302:
303: /* allowed to read at pEnd */
1.1.1.2 ! root 304: max = rb->pEnd - rb->pTail + 1;
1.1 root 305:
306: if( max >= cnt ) {
307: first = cnt;
308: remain = 0;
309: } else {
310: first = max;
311: remain = cnt - first;
312: }
313:
314: rb_memcpy( dst, rb->pTail, first );
315: dst += first;
316:
317: if(remain) {
318: rb_memcpy( dst, rb->pStart, remain );
319: }
320:
321: #ifdef RINGBUF_MUTEX
322: pthread_mutex_unlock(&rb->mutex);
323: #endif
324:
325: return(cnt);
326: }
327:
328: /* Reset head and tail pointers */
329: void RINGBUFCALL RingBufReInit(RingBuf* rb)
330: {
331: #ifdef RINGBUF_MUTEX
332: pthread_mutex_lock(&rb->mutex);
333: #endif
334: rb->pHead = rb->pTail = rb->pStart;
335: #ifdef RINGBUF_SEM
336: sem_reset(&rb->sem);
337: sem_reset(&rb->highwater_sem);
338: #endif
339: #ifdef RINGBUF_MUTEX
340: pthread_mutex_unlock(&rb->mutex);
341: #endif
342: }
343:
344: /* End of RINGBUF.C */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.