xref: /freebsd/contrib/ntp/libntp/recvbuff.c (revision 5129159789cc9d7bc514e4546b88e3427695002d)
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4 
5 #include <stdio.h>
6 #include "ntp_machine.h"
7 #include "ntp_fp.h"
8 #include "ntp_stdlib.h"
9 #include "ntp_syslog.h"
10 #include "ntp_io.h"
11 #include "recvbuff.h"
12 #include "iosignal.h"
13 
14 /*
15  * Memory allocation
16  */
17 static u_long volatile full_recvbufs;		/* number of recvbufs on fulllist */
18 static u_long volatile free_recvbufs;		/* number of recvbufs on freelist */
19 static u_long volatile total_recvbufs;		/* total recvbufs currently in use */
20 static u_long volatile lowater_adds;	/* number of times we have added memory */
21 
22 static	struct recvbuf *volatile freelist;  /* free buffers */
23 static	struct recvbuf *volatile fulllist;  /* lifo buffers with data */
24 static	struct recvbuf *volatile beginlist; /* fifo buffers with data */
25 
26 #if defined(HAVE_IO_COMPLETION_PORT)
27 static HANDLE fulldatabufferevent;
28 static CRITICAL_SECTION RecvCritSection;
29 # define RECV_BLOCK_IO()	EnterCriticalSection(&RecvCritSection)
30 # define RECV_UNBLOCK_IO()	LeaveCriticalSection(&RecvCritSection)
31 #else
32 # define RECV_BLOCK_IO()
33 # define RECV_UNBLOCK_IO()
34 #endif
35 
36 u_long
37 free_recvbuffs (void)
38 {
39 	return free_recvbufs;
40 }
41 
42 u_long
43 full_recvbuffs (void)
44 {
45 	return free_recvbufs;
46 }
47 
48 u_long
49 total_recvbuffs (void)
50 {
51 	return free_recvbufs;
52 }
53 
54 u_long
55 lowater_additions(void)
56 {
57 	return lowater_adds;
58 }
59 
60 static void
61 initialise_buffer(struct recvbuf *buff)
62 {
63 	memset((char *) buff, 0, sizeof(struct recvbuf));
64 
65 #if defined HAVE_IO_COMPLETION_PORT
66 	buff->iocompletioninfo.overlapped.hEvent = CreateEvent(NULL, FALSE,FALSE, NULL);
67 	buff->wsabuff.len = RX_BUFF_SIZE;
68 	buff->wsabuff.buf = (char *) buff->recv_buffer;
69 #endif
70 }
71 
72 static void
73 create_buffers(void)
74 {
75 	register struct recvbuf *buf;
76 	int i;
77 	buf = (struct recvbuf *)
78 	    emalloc(RECV_INC*sizeof(struct recvbuf));
79 	for (i = 0; i < RECV_INC; i++)
80 	{
81 		initialise_buffer(buf);
82 		buf->next = (struct recvbuf *) freelist;
83 		freelist = buf;
84 		buf++;
85 	}
86 
87 	free_recvbufs += RECV_INC;
88 	total_recvbufs += RECV_INC;
89 	lowater_adds++;
90 }
91 
92 void
93 init_recvbuff(int nbufs)
94 {
95 	register struct recvbuf *buf;
96 	int i;
97 
98 	/*
99 	 * Init buffer free list and stat counters
100 	 */
101 	freelist = 0;
102 
103 	buf = (struct recvbuf *)
104 	    emalloc(nbufs*sizeof(struct recvbuf));
105 	for (i = 0; i < nbufs; i++)
106 	{
107 		initialise_buffer(buf);
108 		buf->next = (struct recvbuf *) freelist;
109 		freelist = buf;
110 		buf++;
111 	}
112 
113 	fulllist = 0;
114 	free_recvbufs = total_recvbufs = nbufs;
115 	full_recvbufs = lowater_adds = 0;
116 
117 #if defined(HAVE_IO_COMPLETION_PORT)
118 	InitializeCriticalSection(&RecvCritSection);
119 	fulldatabufferevent = CreateEvent(NULL, FALSE,FALSE, NULL);
120 #endif
121 
122 }
123 
124 #if defined(HAVE_IO_COMPLETION_PORT)
125 
126 /*  Return the new full buffer event handle . This handle is
127  *  signalled when a recv buffer is placed in the full list.
128  */
129 HANDLE
130 get_recv_buff_event()
131 {
132 	return fulldatabufferevent;
133 }
134 #endif
135 
136 /*
137  * getrecvbufs - get receive buffers which have data in them
138  *
139  *
140  */
141 
142 struct recvbuf *
143 getrecvbufs(void)
144 {
145 	struct recvbuf *rb = NULL; /* nothing has arrived */;
146 
147 	RECV_BLOCK_IO();
148 	if (full_recvbufs == 0)
149 	{
150 #ifdef DEBUG
151 		if (debug > 4)
152 		    printf("getrecvbufs called, no action here\n");
153 #endif
154 	}
155 	else {
156 
157 		/*
158 		 * Get the fulllist chain and mark it empty
159 		 */
160 #ifdef DEBUG
161 		if (debug > 4)
162 		    printf("getrecvbufs returning %ld buffers\n", full_recvbufs);
163 #endif
164 		rb = beginlist;
165 		fulllist = 0;
166 		full_recvbufs = 0;
167 
168 		/*
169 		 * Check to see if we're below the low water mark.
170 		 */
171 		if (free_recvbufs <= RECV_LOWAT)
172 		{
173 			if (total_recvbufs >= RECV_TOOMANY)
174 			    msyslog(LOG_ERR, "too many recvbufs allocated (%ld)",
175 				    total_recvbufs);
176 			else
177 			{
178 				create_buffers();
179 			}
180 		}
181 	}
182 	RECV_UNBLOCK_IO();
183 
184 	/*
185 	 * Return the chain
186 	 */
187 	return rb;
188 }
189 
190 /*
191  * freerecvbuf - make a single recvbuf available for reuse
192  */
193 void
194 freerecvbuf(
195 	struct recvbuf *rb
196 	)
197 {
198 	RECV_BLOCK_IO();
199 	BLOCKIO();
200 	rb->next = (struct recvbuf *) freelist;
201 	freelist = rb;
202 	free_recvbufs++;
203 	UNBLOCKIO();
204 	RECV_UNBLOCK_IO();
205 }
206 
207 
208 void
209 add_full_recv_buffer(
210 	struct recvbuf *rb
211 	)
212 {
213 	RECV_BLOCK_IO();
214 	if (full_recvbufs == 0)
215 	{
216 		beginlist = rb;
217 		rb->next = 0;
218 	}
219 	else
220 	{
221 		rb->next = fulllist->next;
222 		fulllist->next = rb;
223 	}
224 	fulllist = rb;
225 	full_recvbufs++;
226 
227 #if defined(HAVE_IO_COMPLETION_PORT)
228 	if (!SetEvent(fulldatabufferevent)) {
229 		msyslog(LOG_ERR, "Can't set receive buffer event");
230 	}
231 #endif
232 	RECV_UNBLOCK_IO();
233 }
234 
235 struct recvbuf *
236 get_free_recv_buffer(void)
237 {
238 	struct recvbuf * buffer = NULL;
239 	RECV_BLOCK_IO();
240 	if (free_recvbufs <= RECV_LOWAT)
241 		{
242 			if (total_recvbufs >= RECV_TOOMANY) {
243 			    msyslog(LOG_ERR, "too many recvbufs allocated (%ld)",
244 				    total_recvbufs);
245 			}
246 			else
247 			{
248 				create_buffers();
249 			}
250 		}
251 
252 	if (free_recvbufs > 0)
253 	{
254 		buffer = freelist;
255 		freelist = buffer->next;
256 		buffer->next = NULL;
257 		--free_recvbufs;
258 	}
259 
260 	RECV_UNBLOCK_IO();
261 	return buffer;
262 }
263 
264 struct recvbuf *
265 get_full_recv_buffer(void)
266 {
267 	struct recvbuf * buffer = NULL;
268 	RECV_BLOCK_IO();
269 	if (full_recvbufs > 0) {
270 		--full_recvbufs;
271 		buffer = beginlist;
272 		beginlist = buffer->next;
273 		buffer->next = NULL;
274 	}
275 	RECV_UNBLOCK_IO();
276 	return buffer;
277 }
278