1: #ifdef HAVE_CONFIG_H
2: # include <config.h>
3: #endif
4:
5: #include <stdio.h>
6: #include "ntp_machine.h"
7: #include "ntp_assert.h"
8: #include "ntp_fp.h"
9: #include "ntp_syslog.h"
10: #include "ntp_stdlib.h"
11: #include "ntp_io.h"
12: #include "ntp_lists.h"
13: #include "recvbuff.h"
14: #include "iosignal.h"
15:
16:
17:
18: #ifdef DEBUG
19: static void uninit_recvbuff(void);
20: #endif
21:
22: /*
23: * Memory allocation
24: */
25: static u_long volatile full_recvbufs; /* number of recvbufs on fulllist */
26: static u_long volatile free_recvbufs; /* number of recvbufs on freelist */
27: static u_long volatile total_recvbufs; /* total recvbufs currently in use */
28: static u_long volatile lowater_adds; /* number of times we have added memory */
29: static u_long volatile buffer_shortfall;/* number of missed free receive buffers
30: between replenishments */
31:
32: static ISC_LIST(recvbuf_t) full_recv_list; /* Currently used recv buffers */
33: static recvbuf_t * free_recv_list; /* Currently unused buffers */
34:
35: #if defined(SYS_WINNT)
36:
37: /*
38: * For Windows we need to set up a lock to manipulate the
39: * recv buffers to prevent corruption. We keep it lock for as
40: * short a time as possible
41: */
42: static CRITICAL_SECTION RecvLock;
43: # define LOCK() EnterCriticalSection(&RecvLock)
44: # define UNLOCK() LeaveCriticalSection(&RecvLock)
45: #else
46: # define LOCK()
47: # define UNLOCK()
48: #endif
49:
50: u_long
51: free_recvbuffs (void)
52: {
53: return free_recvbufs;
54: }
55:
56: u_long
57: full_recvbuffs (void)
58: {
59: return full_recvbufs;
60: }
61:
62: u_long
63: total_recvbuffs (void)
64: {
65: return total_recvbufs;
66: }
67:
68: u_long
69: lowater_additions(void)
70: {
71: return lowater_adds;
72: }
73:
74: static inline void
75: initialise_buffer(recvbuf_t *buff)
76: {
77: memset(buff, 0, sizeof(*buff));
78: }
79:
80: static void
81: create_buffers(int nbufs)
82: {
83: register recvbuf_t *bufp;
84: int i, abuf;
85:
86: abuf = nbufs + buffer_shortfall;
87: buffer_shortfall = 0;
88:
89: #ifndef DEBUG
90: bufp = emalloc(abuf * sizeof(*bufp));
91: #endif
92:
93: for (i = 0; i < abuf; i++) {
94: #ifdef DEBUG
95: /*
96: * Allocate each buffer individually so they can be
97: * free()d during ntpd shutdown on DEBUG builds to
98: * keep them out of heap leak reports.
99: */
100: bufp = emalloc(sizeof(*bufp));
101: #endif
102: memset(bufp, 0, sizeof(*bufp));
103: LINK_SLIST(free_recv_list, bufp, link.next);
104: bufp++;
105: free_recvbufs++;
106: total_recvbufs++;
107: }
108: lowater_adds++;
109: }
110:
111: void
112: init_recvbuff(int nbufs)
113: {
114:
115: /*
116: * Init buffer free list and stat counters
117: */
118: ISC_LIST_INIT(full_recv_list);
119: free_recvbufs = total_recvbufs = 0;
120: full_recvbufs = lowater_adds = 0;
121:
122: create_buffers(nbufs);
123:
124: #if defined(SYS_WINNT)
125: InitializeCriticalSection(&RecvLock);
126: #endif
127:
128: #ifdef DEBUG
129: atexit(&uninit_recvbuff);
130: #endif
131: }
132:
133:
134: #ifdef DEBUG
135: static void
136: uninit_recvbuff(void)
137: {
138: recvbuf_t *rbunlinked;
139:
140: while ((rbunlinked = ISC_LIST_HEAD(full_recv_list)) != NULL) {
141: ISC_LIST_DEQUEUE_TYPE(full_recv_list, rbunlinked, link, recvbuf_t);
142: free(rbunlinked);
143: }
144:
145: do {
146: UNLINK_HEAD_SLIST(rbunlinked, free_recv_list, link.next);
147: if (rbunlinked != NULL)
148: free(rbunlinked);
149: } while (rbunlinked != NULL);
150: }
151: #endif /* DEBUG */
152:
153:
154: /*
155: * freerecvbuf - make a single recvbuf available for reuse
156: */
157: void
158: freerecvbuf(recvbuf_t *rb)
159: {
160: if (rb == NULL) {
161: msyslog(LOG_ERR, "freerecvbuff received NULL buffer");
162: return;
163: }
164:
165: LOCK();
166: (rb->used)--;
167: if (rb->used != 0)
168: msyslog(LOG_ERR, "******** freerecvbuff non-zero usage: %d *******", rb->used);
169: LINK_SLIST(free_recv_list, rb, link.next);
170: free_recvbufs++;
171: UNLOCK();
172: }
173:
174:
175: void
176: add_full_recv_buffer(recvbuf_t *rb)
177: {
178: if (rb == NULL) {
179: msyslog(LOG_ERR, "add_full_recv_buffer received NULL buffer");
180: return;
181: }
182: LOCK();
183: ISC_LINK_INIT(rb, link);
184: ISC_LIST_APPEND(full_recv_list, rb, link);
185: full_recvbufs++;
186: UNLOCK();
187: }
188:
189: recvbuf_t *
190: get_free_recv_buffer(void)
191: {
192: recvbuf_t *buffer;
193:
194: LOCK();
195: UNLINK_HEAD_SLIST(buffer, free_recv_list, link.next);
196: if (buffer != NULL) {
197: free_recvbufs--;
198: initialise_buffer(buffer);
199: (buffer->used)++;
200: } else
201: buffer_shortfall++;
202: UNLOCK();
203: return (buffer);
204: }
205:
206: #ifdef HAVE_IO_COMPLETION_PORT
207: recvbuf_t *
208: get_free_recv_buffer_alloc(void)
209: {
210: recvbuf_t *buffer;
211:
212: buffer = get_free_recv_buffer();
213: if (NULL == buffer) {
214: create_buffers(RECV_INC);
215: buffer = get_free_recv_buffer();
216: }
217: NTP_ENSURE(buffer != NULL);
218: return (buffer);
219: }
220: #endif
221:
222: recvbuf_t *
223: get_full_recv_buffer(void)
224: {
225: recvbuf_t *rbuf;
226: LOCK();
227:
228: #ifdef HAVE_SIGNALED_IO
229: /*
230: * make sure there are free buffers when we
231: * wander off to do lengthy packet processing with
232: * any buffer we grab from the full list.
233: *
234: * fixes malloc() interrupted by SIGIO risk
235: * (Bug 889)
236: */
237: if (NULL == free_recv_list || buffer_shortfall > 0) {
238: /*
239: * try to get us some more buffers
240: */
241: create_buffers(RECV_INC);
242: }
243: #endif
244:
245: /*
246: * try to grab a full buffer
247: */
248: rbuf = ISC_LIST_HEAD(full_recv_list);
249: if (rbuf != NULL) {
250: ISC_LIST_DEQUEUE_TYPE(full_recv_list, rbuf, link, recvbuf_t);
251: --full_recvbufs;
252: } else
253: /*
254: * Make sure we reset the full count to 0
255: */
256: full_recvbufs = 0;
257: UNLOCK();
258: return (rbuf);
259: }
260:
261: /*
262: * Checks to see if there are buffers to process
263: */
264: isc_boolean_t has_full_recv_buffer(void)
265: {
266: if (ISC_LIST_HEAD(full_recv_list) != NULL)
267: return (ISC_TRUE);
268: else
269: return (ISC_FALSE);
270: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>