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