recvbuff.c revision 290001
1#ifdef HAVE_CONFIG_H 2# include <config.h> 3#endif 4 5#include <stdio.h> 6 7#include "ntp_assert.h" 8#include "ntp_syslog.h" 9#include "ntp_stdlib.h" 10#include "ntp_lists.h" 11#include "recvbuff.h" 12#include "iosignal.h" 13 14 15/* 16 * Memory allocation 17 */ 18static u_long volatile full_recvbufs; /* recvbufs on full_recv_fifo */ 19static u_long volatile free_recvbufs; /* recvbufs on free_recv_list */ 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 DECL_FIFO_ANCHOR(recvbuf_t) full_recv_fifo; 26static recvbuf_t * free_recv_list; 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() do {} while (FALSE) 40# define UNLOCK() do {} while (FALSE) 41#endif 42 43#ifdef DEBUG 44static void uninit_recvbuff(void); 45#endif 46 47 48u_long 49free_recvbuffs (void) 50{ 51 return free_recvbufs; 52} 53 54u_long 55full_recvbuffs (void) 56{ 57 return full_recvbufs; 58} 59 60u_long 61total_recvbuffs (void) 62{ 63 return total_recvbufs; 64} 65 66u_long 67lowater_additions(void) 68{ 69 return lowater_adds; 70} 71 72static inline void 73initialise_buffer(recvbuf_t *buff) 74{ 75 ZERO(*buff); 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#ifndef DEBUG 88 bufp = emalloc_zero(abuf * sizeof(*bufp)); 89#endif 90 91 for (i = 0; i < abuf; i++) { 92#ifdef DEBUG 93 /* 94 * Allocate each buffer individually so they can be 95 * free()d during ntpd shutdown on DEBUG builds to 96 * keep them out of heap leak reports. 97 */ 98 bufp = emalloc_zero(sizeof(*bufp)); 99#endif 100 LINK_SLIST(free_recv_list, bufp, link); 101 bufp++; 102 free_recvbufs++; 103 total_recvbufs++; 104 } 105 lowater_adds++; 106} 107 108void 109init_recvbuff(int nbufs) 110{ 111 112 /* 113 * Init buffer free list and stat counters 114 */ 115 free_recvbufs = total_recvbufs = 0; 116 full_recvbufs = lowater_adds = 0; 117 118 create_buffers(nbufs); 119 120#if defined(SYS_WINNT) 121 InitializeCriticalSection(&RecvLock); 122#endif 123 124#ifdef DEBUG 125 atexit(&uninit_recvbuff); 126#endif 127} 128 129 130#ifdef DEBUG 131static void 132uninit_recvbuff(void) 133{ 134 recvbuf_t *rbunlinked; 135 136 for (;;) { 137 UNLINK_FIFO(rbunlinked, full_recv_fifo, link); 138 if (rbunlinked == NULL) 139 break; 140 free(rbunlinked); 141 } 142 143 for (;;) { 144 UNLINK_HEAD_SLIST(rbunlinked, free_recv_list, link); 145 if (rbunlinked == NULL) 146 break; 147 free(rbunlinked); 148 } 149} 150#endif /* DEBUG */ 151 152 153/* 154 * freerecvbuf - make a single recvbuf available for reuse 155 */ 156void 157freerecvbuf(recvbuf_t *rb) 158{ 159 if (rb == NULL) { 160 msyslog(LOG_ERR, "freerecvbuff received NULL buffer"); 161 return; 162 } 163 164 LOCK(); 165 rb->used--; 166 if (rb->used != 0) 167 msyslog(LOG_ERR, "******** freerecvbuff non-zero usage: %d *******", rb->used); 168 LINK_SLIST(free_recv_list, rb, link); 169 free_recvbufs++; 170 UNLOCK(); 171} 172 173 174void 175add_full_recv_buffer(recvbuf_t *rb) 176{ 177 if (rb == NULL) { 178 msyslog(LOG_ERR, "add_full_recv_buffer received NULL buffer"); 179 return; 180 } 181 LOCK(); 182 LINK_FIFO(full_recv_fifo, rb, link); 183 full_recvbufs++; 184 UNLOCK(); 185} 186 187 188recvbuf_t * 189get_free_recv_buffer(void) 190{ 191 recvbuf_t *buffer; 192 193 LOCK(); 194 UNLINK_HEAD_SLIST(buffer, free_recv_list, link); 195 if (buffer != NULL) { 196 free_recvbufs--; 197 initialise_buffer(buffer); 198 buffer->used++; 199 } else { 200 buffer_shortfall++; 201 } 202 UNLOCK(); 203 204 return buffer; 205} 206 207 208#ifdef HAVE_IO_COMPLETION_PORT 209recvbuf_t * 210get_free_recv_buffer_alloc(void) 211{ 212 recvbuf_t *buffer; 213 214 buffer = get_free_recv_buffer(); 215 if (NULL == buffer) { 216 create_buffers(RECV_INC); 217 buffer = get_free_recv_buffer(); 218 } 219 ENSURE(buffer != NULL); 220 return (buffer); 221} 222#endif 223 224 225recvbuf_t * 226get_full_recv_buffer(void) 227{ 228 recvbuf_t * rbuf; 229 230 LOCK(); 231 232#ifdef HAVE_SIGNALED_IO 233 /* 234 * make sure there are free buffers when we 235 * wander off to do lengthy packet processing with 236 * any buffer we grab from the full list. 237 * 238 * fixes malloc() interrupted by SIGIO risk 239 * (Bug 889) 240 */ 241 if (NULL == free_recv_list || buffer_shortfall > 0) { 242 /* 243 * try to get us some more buffers 244 */ 245 create_buffers(RECV_INC); 246 } 247#endif 248 249 /* 250 * try to grab a full buffer 251 */ 252 UNLINK_FIFO(rbuf, full_recv_fifo, link); 253 if (rbuf != NULL) 254 full_recvbufs--; 255 UNLOCK(); 256 257 return rbuf; 258} 259 260 261/* 262 * purge_recv_buffers_for_fd() - purges any previously-received input 263 * from a given file descriptor. 264 */ 265void 266purge_recv_buffers_for_fd( 267 SOCKET fd 268 ) 269{ 270 recvbuf_t *rbufp; 271 recvbuf_t *next; 272 recvbuf_t *punlinked; 273 274 LOCK(); 275 276 for (rbufp = HEAD_FIFO(full_recv_fifo); 277 rbufp != NULL; 278 rbufp = next) { 279 next = rbufp->link; 280 if (rbufp->fd == fd) { 281 UNLINK_MID_FIFO(punlinked, full_recv_fifo, 282 rbufp, link, recvbuf_t); 283 INSIST(punlinked == rbufp); 284 full_recvbufs--; 285 freerecvbuf(rbufp); 286 } 287 } 288 289 UNLOCK(); 290} 291 292 293/* 294 * Checks to see if there are buffers to process 295 */ 296isc_boolean_t has_full_recv_buffer(void) 297{ 298 if (HEAD_FIFO(full_recv_fifo) != NULL) 299 return (ISC_TRUE); 300 else 301 return (ISC_FALSE); 302} 303 304 305#ifdef NTP_DEBUG_LISTS_H 306void 307check_gen_fifo_consistency(void *fifo) 308{ 309 gen_fifo *pf; 310 gen_node *pthis; 311 gen_node **pptail; 312 313 pf = fifo; 314 REQUIRE((NULL == pf->phead && NULL == pf->pptail) || 315 (NULL != pf->phead && NULL != pf->pptail)); 316 317 pptail = &pf->phead; 318 for (pthis = pf->phead; 319 pthis != NULL; 320 pthis = pthis->link) 321 if (NULL != pthis->link) 322 pptail = &pthis->link; 323 324 REQUIRE(NULL == pf->pptail || pptail == pf->pptail); 325} 326#endif /* NTP_DEBUG_LISTS_H */ 327