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