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