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 21static void uninit_recvbuff(void); 22#endif 23 24/* 25 * Memory allocation 26 */ 27static u_long volatile full_recvbufs; /* number of recvbufs on fulllist */ 28static u_long volatile free_recvbufs; /* number of recvbufs on freelist */ 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 */ 33 34static ISC_LIST(recvbuf_t) full_recv_list; /* Currently used recv buffers */ 35static 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 */ 44static CRITICAL_SECTION RecvLock; 45# define LOCK() EnterCriticalSection(&RecvLock) 46# define UNLOCK() LeaveCriticalSection(&RecvLock) 47#else 48# define LOCK() 49# define UNLOCK() 50#endif 51 52u_long 53free_recvbuffs (void) 54{ 55 return free_recvbufs; 56} 57 58u_long 59full_recvbuffs (void) 60{ 61 return full_recvbufs; 62} 63 64u_long 65total_recvbuffs (void) 66{ 67 return total_recvbufs; 68} 69 70u_long 71lowater_additions(void) 72{ 73 return lowater_adds; 74} 75 76static inline void 77initialise_buffer(recvbuf_t *buff) 78{ 79 memset(buff, 0, sizeof(*buff)); 80} 81 82static void 83create_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 113void 114init_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 137static void 138uninit_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 */ 159void 160freerecvbuf(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 177void 178add_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 191recvbuf_t * 192get_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 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 NTP_ENSURE(buffer != NULL); 220 return (buffer); 221} 222#endif 223 224recvbuf_t * 225get_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 */ 266isc_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