]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ntp/libntp/recvbuff.c
Upgrade NTP to 4.2.8p4.
[FreeBSD/releng/10.2.git] / contrib / ntp / libntp / recvbuff.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <stdio.h>
6
7 #include "ntp_assert.h"
8 #include "ntp_syslog.h"
9 #include "ntp_stdlib.h"
10 #include "ntp_lists.h"
11 #include "recvbuff.h"
12 #include "iosignal.h"
13
14
15 /*
16  * Memory allocation
17  */
18 static u_long volatile full_recvbufs;   /* recvbufs on full_recv_fifo */
19 static u_long volatile free_recvbufs;   /* recvbufs on free_recv_list */
20 static u_long volatile total_recvbufs;  /* total recvbufs currently in use */
21 static u_long volatile lowater_adds;    /* number of times we have added memory */
22 static u_long volatile buffer_shortfall;/* number of missed free receive buffers
23                                            between replenishments */
24
25 static DECL_FIFO_ANCHOR(recvbuf_t) full_recv_fifo;
26 static recvbuf_t *                 free_recv_list;
27         
28 #if defined(SYS_WINNT)
29
30 /*
31  * For Windows we need to set up a lock to manipulate the
32  * recv buffers to prevent corruption. We keep it lock for as
33  * short a time as possible
34  */
35 static CRITICAL_SECTION RecvLock;
36 # define LOCK()         EnterCriticalSection(&RecvLock)
37 # define UNLOCK()       LeaveCriticalSection(&RecvLock)
38 #else
39 # define LOCK()         do {} while (FALSE)
40 # define UNLOCK()       do {} while (FALSE)
41 #endif
42
43 #ifdef DEBUG
44 static void uninit_recvbuff(void);
45 #endif
46
47
48 u_long
49 free_recvbuffs (void)
50 {
51         return free_recvbufs;
52 }
53
54 u_long
55 full_recvbuffs (void)
56 {
57         return full_recvbufs;
58 }
59
60 u_long
61 total_recvbuffs (void)
62 {
63         return total_recvbufs;
64 }
65
66 u_long
67 lowater_additions(void)
68 {
69         return lowater_adds;
70 }
71
72 static inline void 
73 initialise_buffer(recvbuf_t *buff)
74 {
75         ZERO(*buff);
76 }
77
78 static void
79 create_buffers(int nbufs)
80 {
81         register recvbuf_t *bufp;
82         int i, abuf;
83
84         abuf = nbufs + buffer_shortfall;
85         buffer_shortfall = 0;
86
87 #ifndef DEBUG
88         bufp = emalloc_zero(abuf * sizeof(*bufp));
89 #endif
90
91         for (i = 0; i < abuf; i++) {
92 #ifdef DEBUG
93                 /*
94                  * Allocate each buffer individually so they can be
95                  * free()d during ntpd shutdown on DEBUG builds to
96                  * keep them out of heap leak reports.
97                  */
98                 bufp = emalloc_zero(sizeof(*bufp));
99 #endif
100                 LINK_SLIST(free_recv_list, bufp, link);
101                 bufp++;
102                 free_recvbufs++;
103                 total_recvbufs++;
104         }
105         lowater_adds++;
106 }
107
108 void
109 init_recvbuff(int nbufs)
110 {
111
112         /*
113          * Init buffer free list and stat counters
114          */
115         free_recvbufs = total_recvbufs = 0;
116         full_recvbufs = lowater_adds = 0;
117
118         create_buffers(nbufs);
119
120 #if defined(SYS_WINNT)
121         InitializeCriticalSection(&RecvLock);
122 #endif
123
124 #ifdef DEBUG
125         atexit(&uninit_recvbuff);
126 #endif
127 }
128
129
130 #ifdef DEBUG
131 static void
132 uninit_recvbuff(void)
133 {
134         recvbuf_t *rbunlinked;
135
136         for (;;) {
137                 UNLINK_FIFO(rbunlinked, full_recv_fifo, link);
138                 if (rbunlinked == NULL)
139                         break;
140                 free(rbunlinked);
141         }
142
143         for (;;) {
144                 UNLINK_HEAD_SLIST(rbunlinked, free_recv_list, link);
145                 if (rbunlinked == NULL)
146                         break;
147                 free(rbunlinked);
148         }
149 }
150 #endif  /* DEBUG */
151
152
153 /*
154  * freerecvbuf - make a single recvbuf available for reuse
155  */
156 void
157 freerecvbuf(recvbuf_t *rb)
158 {
159         if (rb == NULL) {
160                 msyslog(LOG_ERR, "freerecvbuff received NULL buffer");
161                 return;
162         }
163
164         LOCK();
165         rb->used--;
166         if (rb->used != 0)
167                 msyslog(LOG_ERR, "******** freerecvbuff non-zero usage: %d *******", rb->used);
168         LINK_SLIST(free_recv_list, rb, link);
169         free_recvbufs++;
170         UNLOCK();
171 }
172
173         
174 void
175 add_full_recv_buffer(recvbuf_t *rb)
176 {
177         if (rb == NULL) {
178                 msyslog(LOG_ERR, "add_full_recv_buffer received NULL buffer");
179                 return;
180         }
181         LOCK();
182         LINK_FIFO(full_recv_fifo, rb, link);
183         full_recvbufs++;
184         UNLOCK();
185 }
186
187
188 recvbuf_t *
189 get_free_recv_buffer(void)
190 {
191         recvbuf_t *buffer;
192
193         LOCK();
194         UNLINK_HEAD_SLIST(buffer, free_recv_list, link);
195         if (buffer != NULL) {
196                 free_recvbufs--;
197                 initialise_buffer(buffer);
198                 buffer->used++;
199         } else {
200                 buffer_shortfall++;
201         }
202         UNLOCK();
203
204         return buffer;
205 }
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         ENSURE(buffer != NULL);
220         return (buffer);
221 }
222 #endif
223
224
225 recvbuf_t *
226 get_full_recv_buffer(void)
227 {
228         recvbuf_t *     rbuf;
229
230         LOCK();
231         
232 #ifdef HAVE_SIGNALED_IO
233         /*
234          * make sure there are free buffers when we
235          * wander off to do lengthy packet processing with
236          * any buffer we grab from the full list.
237          * 
238          * fixes malloc() interrupted by SIGIO risk
239          * (Bug 889)
240          */
241         if (NULL == free_recv_list || buffer_shortfall > 0) {
242                 /*
243                  * try to get us some more buffers
244                  */
245                 create_buffers(RECV_INC);
246         }
247 #endif
248
249         /*
250          * try to grab a full buffer
251          */
252         UNLINK_FIFO(rbuf, full_recv_fifo, link);
253         if (rbuf != NULL)
254                 full_recvbufs--;
255         UNLOCK();
256
257         return rbuf;
258 }
259
260
261 /*
262  * purge_recv_buffers_for_fd() - purges any previously-received input
263  *                               from a given file descriptor.
264  */
265 void
266 purge_recv_buffers_for_fd(
267         SOCKET  fd
268         )
269 {
270         recvbuf_t *rbufp;
271         recvbuf_t *next;
272         recvbuf_t *punlinked;
273
274         LOCK();
275
276         for (rbufp = HEAD_FIFO(full_recv_fifo);
277              rbufp != NULL;
278              rbufp = next) {
279                 next = rbufp->link;
280                 if (rbufp->fd == fd) {
281                         UNLINK_MID_FIFO(punlinked, full_recv_fifo,
282                                         rbufp, link, recvbuf_t);
283                         INSIST(punlinked == rbufp);
284                         full_recvbufs--;
285                         freerecvbuf(rbufp);
286                 }
287         }
288
289         UNLOCK();
290 }
291
292
293 /*
294  * Checks to see if there are buffers to process
295  */
296 isc_boolean_t has_full_recv_buffer(void)
297 {
298         if (HEAD_FIFO(full_recv_fifo) != NULL)
299                 return (ISC_TRUE);
300         else
301                 return (ISC_FALSE);
302 }
303
304
305 #ifdef NTP_DEBUG_LISTS_H
306 void
307 check_gen_fifo_consistency(void *fifo)
308 {
309         gen_fifo *pf;
310         gen_node *pthis;
311         gen_node **pptail;
312
313         pf = fifo;
314         REQUIRE((NULL == pf->phead && NULL == pf->pptail) ||
315                 (NULL != pf->phead && NULL != pf->pptail));
316
317         pptail = &pf->phead;
318         for (pthis = pf->phead;
319              pthis != NULL;
320              pthis = pthis->link)
321                 if (NULL != pthis->link)
322                         pptail = &pthis->link;
323
324         REQUIRE(NULL == pf->pptail || pptail == pf->pptail);
325 }
326 #endif  /* NTP_DEBUG_LISTS_H */