recvbuff.c revision 182007
1#ifdef HAVE_CONFIG_H 2# include <config.h> 3#endif 4 5#include <stdio.h> 6#include "ntp_machine.h" 7#include "ntp_fp.h" 8#include "ntp_syslog.h" 9#include "ntp_stdlib.h" 10#include "ntp_io.h" 11#include "recvbuff.h" 12#include "iosignal.h" 13 14#include <isc/list.h> 15/* 16 * Memory allocation 17 */ 18static u_long volatile full_recvbufs; /* number of recvbufs on fulllist */ 19static u_long volatile free_recvbufs; /* number of recvbufs on freelist */ 20static u_long volatile total_recvbufs; /* total recvbufs currently in use */ 21static u_long volatile lowater_adds; /* number of times we have added memory */ 22static u_long volatile buffer_shortfall;/* number of missed free receive buffers 23 between replenishments */ 24 25static ISC_LIST(recvbuf_t) full_recv_list; /* Currently used recv buffers */ 26static ISC_LIST(recvbuf_t) free_recv_list; /* Currently unused buffers */ 27 28#if defined(SYS_WINNT) 29 30/* 31 * For Windows we need to set up a lock to manipulate the 32 * recv buffers to prevent corruption. We keep it lock for as 33 * short a time as possible 34 */ 35static CRITICAL_SECTION RecvLock; 36# define LOCK() EnterCriticalSection(&RecvLock) 37# define UNLOCK() LeaveCriticalSection(&RecvLock) 38#else 39# define LOCK() 40# define UNLOCK() 41#endif 42 43u_long 44free_recvbuffs (void) 45{ 46 return free_recvbufs; 47} 48 49u_long 50full_recvbuffs (void) 51{ 52 return full_recvbufs; 53} 54 55u_long 56total_recvbuffs (void) 57{ 58 return total_recvbufs; 59} 60 61u_long 62lowater_additions(void) 63{ 64 return lowater_adds; 65} 66 67static void 68initialise_buffer(recvbuf_t *buff) 69{ 70 memset((char *) buff, 0, sizeof(recvbuf_t)); 71 72#if defined SYS_WINNT 73 buff->wsabuff.len = RX_BUFF_SIZE; 74 buff->wsabuff.buf = (char *) buff->recv_buffer; 75#endif 76} 77 78static void 79create_buffers(int nbufs) 80{ 81 register recvbuf_t *bufp; 82 int i, abuf; 83 84 abuf = nbufs + buffer_shortfall; 85 buffer_shortfall = 0; 86 87 bufp = (recvbuf_t *) emalloc(abuf*sizeof(recvbuf_t)); 88 89 for (i = 0; i < abuf; i++) 90 { 91 memset((char *) bufp, 0, sizeof(recvbuf_t)); 92 ISC_LIST_APPEND(free_recv_list, bufp, link); 93 bufp++; 94 free_recvbufs++; 95 total_recvbufs++; 96 } 97 lowater_adds++; 98} 99 100void 101init_recvbuff(int nbufs) 102{ 103 104 /* 105 * Init buffer free list and stat counters 106 */ 107 ISC_LIST_INIT(full_recv_list); 108 ISC_LIST_INIT(free_recv_list); 109 free_recvbufs = total_recvbufs = 0; 110 full_recvbufs = lowater_adds = 0; 111 112 create_buffers(nbufs); 113 114#if defined(SYS_WINNT) 115 InitializeCriticalSection(&RecvLock); 116#endif 117 118} 119 120/* 121 * freerecvbuf - make a single recvbuf available for reuse 122 */ 123void 124freerecvbuf(recvbuf_t *rb) 125{ 126 if (rb == NULL) { 127 msyslog(LOG_ERR, "freerecvbuff received NULL buffer"); 128 return; 129 } 130 131 LOCK(); 132 (rb->used)--; 133 if (rb->used != 0) 134 msyslog(LOG_ERR, "******** freerecvbuff non-zero usage: %d *******", rb->used); 135 ISC_LIST_APPEND(free_recv_list, rb, link); 136#if defined SYS_WINNT 137 rb->wsabuff.len = RX_BUFF_SIZE; 138 rb->wsabuff.buf = (char *) rb->recv_buffer; 139#endif 140 free_recvbufs++; 141 UNLOCK(); 142} 143 144 145void 146add_full_recv_buffer(recvbuf_t *rb) 147{ 148 if (rb == NULL) { 149 msyslog(LOG_ERR, "add_full_recv_buffer received NULL buffer"); 150 return; 151 } 152 LOCK(); 153 ISC_LIST_APPEND(full_recv_list, rb, link); 154 full_recvbufs++; 155 UNLOCK(); 156} 157 158recvbuf_t * 159get_free_recv_buffer(void) 160{ 161 recvbuf_t * buffer = NULL; 162 LOCK(); 163 buffer = ISC_LIST_HEAD(free_recv_list); 164 if (buffer != NULL) 165 { 166 ISC_LIST_DEQUEUE(free_recv_list, buffer, link); 167 free_recvbufs--; 168 initialise_buffer(buffer); 169 (buffer->used)++; 170 } 171 else 172 { 173 buffer_shortfall++; 174 } 175 UNLOCK(); 176 return (buffer); 177} 178 179#ifdef HAVE_IO_COMPLETION_PORT 180recvbuf_t * 181get_free_recv_buffer_alloc(void) 182{ 183 recvbuf_t * buffer = get_free_recv_buffer(); 184 if (buffer == NULL) 185 { 186 create_buffers(RECV_INC); 187 buffer = get_free_recv_buffer(); 188 } 189 return (buffer); 190} 191#endif 192 193recvbuf_t * 194get_full_recv_buffer(void) 195{ 196 recvbuf_t *rbuf; 197 LOCK(); 198 199#ifdef HAVE_SIGNALED_IO 200 /* 201 * make sure there are free buffers when we 202 * wander off to do lengthy paket processing with 203 * any buffer we grab from the full list. 204 * 205 * fixes malloc() interrupted by SIGIO risk 206 * (Bug 889) 207 */ 208 rbuf = ISC_LIST_HEAD(free_recv_list); 209 if (rbuf == NULL || buffer_shortfall > 0) { 210 /* 211 * try to get us some more buffers 212 */ 213 create_buffers(RECV_INC); 214 } 215#endif 216 217 /* 218 * try to grab a full buffer 219 */ 220 rbuf = ISC_LIST_HEAD(full_recv_list); 221 if (rbuf != NULL) 222 { 223 ISC_LIST_DEQUEUE(full_recv_list, rbuf, link); 224 --full_recvbufs; 225 } 226 else 227 { 228 /* 229 * Make sure we reset the full count to 0 230 */ 231 full_recvbufs = 0; 232 } 233 UNLOCK(); 234 return (rbuf); 235} 236 237/* 238 * Checks to see if there are buffers to process 239 */ 240isc_boolean_t has_full_recv_buffer(void) 241{ 242 if (ISC_LIST_HEAD(full_recv_list) != NULL) 243 return (ISC_TRUE); 244 else 245 return (ISC_FALSE); 246} 247