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