Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / ntp / dist / libntp / recvbuff.c
blobbd4e1618c571489ae987fe988909caf53cd9744e
1 /* $NetBSD$ */
3 #ifdef HAVE_CONFIG_H
4 # include <config.h>
5 #endif
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"
20 #ifdef DEBUG
21 static void uninit_recvbuff(void);
22 #endif
25 * Memory allocation
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 */
34 static ISC_LIST(recvbuf_t) full_recv_list; /* Currently used recv buffers */
35 static recvbuf_t * free_recv_list; /* Currently unused buffers */
37 #if defined(SYS_WINNT)
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
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
52 u_long
53 free_recvbuffs (void)
55 return free_recvbufs;
58 u_long
59 full_recvbuffs (void)
61 return full_recvbufs;
64 u_long
65 total_recvbuffs (void)
67 return total_recvbufs;
70 u_long
71 lowater_additions(void)
73 return lowater_adds;
76 static inline void
77 initialise_buffer(recvbuf_t *buff)
79 memset(buff, 0, sizeof(*buff));
82 static void
83 create_buffers(int nbufs)
85 register recvbuf_t *bufp;
86 int i, abuf;
88 abuf = nbufs + buffer_shortfall;
89 buffer_shortfall = 0;
91 #ifndef DEBUG
92 bufp = emalloc(abuf * sizeof(*bufp));
93 #endif
95 for (i = 0; i < abuf; i++) {
96 #ifdef DEBUG
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.
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++;
110 lowater_adds++;
113 void
114 init_recvbuff(int nbufs)
118 * Init buffer free list and stat counters
120 ISC_LIST_INIT(full_recv_list);
121 free_recvbufs = total_recvbufs = 0;
122 full_recvbufs = lowater_adds = 0;
124 create_buffers(nbufs);
126 #if defined(SYS_WINNT)
127 InitializeCriticalSection(&RecvLock);
128 #endif
130 #ifdef DEBUG
131 atexit(&uninit_recvbuff);
132 #endif
136 #ifdef DEBUG
137 static void
138 uninit_recvbuff(void)
140 recvbuf_t *rbunlinked;
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);
147 do {
148 UNLINK_HEAD_SLIST(rbunlinked, free_recv_list, link.next);
149 if (rbunlinked != NULL)
150 free(rbunlinked);
151 } while (rbunlinked != NULL);
153 #endif /* DEBUG */
157 * freerecvbuf - make a single recvbuf available for reuse
159 void
160 freerecvbuf(recvbuf_t *rb)
162 if (rb == NULL) {
163 msyslog(LOG_ERR, "freerecvbuff received NULL buffer");
164 return;
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();
177 void
178 add_full_recv_buffer(recvbuf_t *rb)
180 if (rb == NULL) {
181 msyslog(LOG_ERR, "add_full_recv_buffer received NULL buffer");
182 return;
184 LOCK();
185 ISC_LINK_INIT(rb, link);
186 ISC_LIST_APPEND(full_recv_list, rb, link);
187 full_recvbufs++;
188 UNLOCK();
191 recvbuf_t *
192 get_free_recv_buffer(void)
194 recvbuf_t *buffer;
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);
208 #ifdef HAVE_IO_COMPLETION_PORT
209 recvbuf_t *
210 get_free_recv_buffer_alloc(void)
212 recvbuf_t *buffer;
214 buffer = get_free_recv_buffer();
215 if (NULL == buffer) {
216 create_buffers(RECV_INC);
217 buffer = get_free_recv_buffer();
219 NTP_ENSURE(buffer != NULL);
220 return (buffer);
222 #endif
224 recvbuf_t *
225 get_full_recv_buffer(void)
227 recvbuf_t *rbuf;
228 LOCK();
230 #ifdef HAVE_SIGNALED_IO
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.
236 * fixes malloc() interrupted by SIGIO risk
237 * (Bug 889)
239 if (NULL == free_recv_list || buffer_shortfall > 0) {
241 * try to get us some more buffers
243 create_buffers(RECV_INC);
245 #endif
248 * try to grab a full buffer
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
256 * Make sure we reset the full count to 0
258 full_recvbufs = 0;
259 UNLOCK();
260 return (rbuf);
264 * Checks to see if there are buffers to process
266 isc_boolean_t has_full_recv_buffer(void)
268 if (ISC_LIST_HEAD(full_recv_list) != NULL)
269 return (ISC_TRUE);
270 else
271 return (ISC_FALSE);