]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ntp/libntp/recvbuff.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ntp / libntp / recvbuff.c
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 #include <isc/list.h>
15 /*
16  * Memory allocation
17  */
18 static u_long volatile full_recvbufs;   /* number of recvbufs on fulllist */
19 static u_long volatile free_recvbufs;   /* number of recvbufs on freelist */
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 ISC_LIST(recvbuf_t)      full_recv_list; /* Currently used recv buffers */
26 static ISC_LIST(recvbuf_t)      free_recv_list; /* Currently unused buffers */
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() 
40 # define UNLOCK()       
41 #endif
42
43 u_long
44 free_recvbuffs (void)
45 {
46         return free_recvbufs;
47 }
48
49 u_long
50 full_recvbuffs (void)
51 {
52         return full_recvbufs;
53 }
54
55 u_long
56 total_recvbuffs (void)
57 {
58         return total_recvbufs;
59 }
60
61 u_long
62 lowater_additions(void)
63 {
64         return lowater_adds;
65 }
66
67 static void 
68 initialise_buffer(recvbuf_t *buff)
69 {
70         memset((char *) buff, 0, sizeof(recvbuf_t));
71
72 #if defined SYS_WINNT
73         buff->wsabuff.len = RX_BUFF_SIZE;
74         buff->wsabuff.buf = (char *) buff->recv_buffer;
75 #endif
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         bufp = (recvbuf_t *) emalloc(abuf*sizeof(recvbuf_t));
88
89         for (i = 0; i < abuf; i++)
90         {
91                 memset((char *) bufp, 0, sizeof(recvbuf_t));
92                 ISC_LIST_APPEND(free_recv_list, bufp, link);
93                 bufp++;
94                 free_recvbufs++;
95                 total_recvbufs++;
96         }
97         lowater_adds++;
98 }
99
100 void
101 init_recvbuff(int nbufs)
102 {
103
104         /*
105          * Init buffer free list and stat counters
106          */
107         ISC_LIST_INIT(full_recv_list);
108         ISC_LIST_INIT(free_recv_list);
109         free_recvbufs = total_recvbufs = 0;
110         full_recvbufs = lowater_adds = 0;
111
112         create_buffers(nbufs);
113
114 #if defined(SYS_WINNT)
115         InitializeCriticalSection(&RecvLock);
116 #endif
117
118 }
119
120 /*
121  * freerecvbuf - make a single recvbuf available for reuse
122  */
123 void
124 freerecvbuf(recvbuf_t *rb)
125 {
126         if (rb == NULL) {
127                 msyslog(LOG_ERR, "freerecvbuff received NULL buffer");
128                 return;
129         }
130
131         LOCK();
132         (rb->used)--;
133         if (rb->used != 0)
134                 msyslog(LOG_ERR, "******** freerecvbuff non-zero usage: %d *******", rb->used);
135         ISC_LIST_APPEND(free_recv_list, rb, link);
136 #if defined SYS_WINNT
137         rb->wsabuff.len = RX_BUFF_SIZE;
138         rb->wsabuff.buf = (char *) rb->recv_buffer;
139 #endif
140         free_recvbufs++;
141         UNLOCK();
142 }
143
144         
145 void
146 add_full_recv_buffer(recvbuf_t *rb)
147 {
148         if (rb == NULL) {
149                 msyslog(LOG_ERR, "add_full_recv_buffer received NULL buffer");
150                 return;
151         }
152         LOCK();
153         ISC_LIST_APPEND(full_recv_list, rb, link);
154         full_recvbufs++;
155         UNLOCK();
156 }
157
158 recvbuf_t *
159 get_free_recv_buffer(void)
160 {
161         recvbuf_t * buffer = NULL;
162         LOCK();
163         buffer = ISC_LIST_HEAD(free_recv_list);
164         if (buffer != NULL)
165         {
166                 ISC_LIST_DEQUEUE(free_recv_list, buffer, link);
167                 free_recvbufs--;
168                 initialise_buffer(buffer);
169                 (buffer->used)++;
170         }
171         else
172         {
173                 buffer_shortfall++;
174         }
175         UNLOCK();
176         return (buffer);
177 }
178
179 #ifdef HAVE_IO_COMPLETION_PORT
180 recvbuf_t *
181 get_free_recv_buffer_alloc(void)
182 {
183         recvbuf_t * buffer = get_free_recv_buffer();
184         if (buffer == NULL)
185         {
186                 create_buffers(RECV_INC);
187                 buffer = get_free_recv_buffer();
188         }
189         return (buffer);
190 }
191 #endif
192
193 recvbuf_t *
194 get_full_recv_buffer(void)
195 {
196         recvbuf_t *rbuf;
197         LOCK();
198         
199 #ifdef HAVE_SIGNALED_IO
200         /*
201          * make sure there are free buffers when we
202          * wander off to do lengthy paket processing with
203          * any buffer we grab from the full list.
204          * 
205          * fixes malloc() interrupted by SIGIO risk
206          * (Bug 889)
207          */
208         rbuf = ISC_LIST_HEAD(free_recv_list);
209         if (rbuf == NULL || buffer_shortfall > 0) {
210                 /*
211                  * try to get us some more buffers
212                  */
213                 create_buffers(RECV_INC);
214         }
215 #endif
216
217         /*
218          * try to grab a full buffer
219          */
220         rbuf = ISC_LIST_HEAD(full_recv_list);
221         if (rbuf != NULL)
222         {
223                 ISC_LIST_DEQUEUE(full_recv_list, rbuf, link);
224                 --full_recvbufs;
225         }
226         else
227         {
228                 /*
229                  * Make sure we reset the full count to 0
230                  */
231                 full_recvbufs = 0;
232         }
233         UNLOCK();
234         return (rbuf);
235 }
236
237 /*
238  * Checks to see if there are buffers to process
239  */
240 isc_boolean_t has_full_recv_buffer(void)
241 {
242         if (ISC_LIST_HEAD(full_recv_list) != NULL)
243                 return (ISC_TRUE);
244         else
245                 return (ISC_FALSE);
246 }