|
|
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.