xref: /netbsd-src/external/bsd/ntp/dist/libntp/recvbuff.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
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