recvbuff.c (ntp-4.2.8p14) | : | recvbuff.c (ntp-4.2.8p15) | ||
---|---|---|---|---|
skipping to change at line 14 | skipping to change at line 14 | |||
#include <stdio.h> | #include <stdio.h> | |||
#include "ntp_assert.h" | #include "ntp_assert.h" | |||
#include "ntp_syslog.h" | #include "ntp_syslog.h" | |||
#include "ntp_stdlib.h" | #include "ntp_stdlib.h" | |||
#include "ntp_lists.h" | #include "ntp_lists.h" | |||
#include "recvbuff.h" | #include "recvbuff.h" | |||
#include "iosignal.h" | #include "iosignal.h" | |||
#if (RECV_INC & (RECV_INC-1)) | ||||
# error RECV_INC not a power of 2! | ||||
#endif | ||||
#if (RECV_BATCH & (RECV_BATCH - 1)) | ||||
#error RECV_BATCH not a power of 2! | ||||
#endif | ||||
#if (RECV_BATCH < RECV_INC) | ||||
#error RECV_BATCH must be >= RECV_INC! | ||||
#endif | ||||
/* | /* | |||
* Memory allocation | * Memory allocation | |||
*/ | */ | |||
static u_long volatile full_recvbufs; /* recvbufs on full_recv_fifo */ | static u_long volatile full_recvbufs; /* recvbufs on full_recv_fifo */ | |||
static u_long volatile free_recvbufs; /* recvbufs on free_recv_list */ | static u_long volatile free_recvbufs; /* recvbufs on free_recv_list */ | |||
static u_long volatile total_recvbufs; /* total recvbufs currently in use */ | static u_long volatile total_recvbufs; /* total recvbufs currently in use */ | |||
static u_long volatile lowater_adds; /* number of times we have added memory * / | static u_long volatile lowater_adds; /* number of times we have added memory * / | |||
static u_long volatile buffer_shortfall;/* number of missed free receive buffers | static u_long volatile buffer_shortfall;/* number of missed free receive buffers | |||
between replenishments */ | between replenishments */ | |||
static u_long limit_recvbufs; /* maximum total of receive buffers */ | ||||
static u_long emerg_recvbufs; /* emergency/urgent buffers to keep */ | ||||
static DECL_FIFO_ANCHOR(recvbuf_t) full_recv_fifo; | static DECL_FIFO_ANCHOR(recvbuf_t) full_recv_fifo; | |||
static recvbuf_t * free_recv_list; | static recvbuf_t * free_recv_list; | |||
#if defined(SYS_WINNT) | #if defined(SYS_WINNT) | |||
/* | /* | |||
* For Windows we need to set up a lock to manipulate the | * For Windows we need to set up a lock to manipulate the | |||
* recv buffers to prevent corruption. We keep it lock for as | * recv buffers to prevent corruption. We keep it lock for as | |||
* short a time as possible | * short a time as possible | |||
*/ | */ | |||
static CRITICAL_SECTION RecvLock; | static CRITICAL_SECTION RecvLock; | |||
# define LOCK() EnterCriticalSection(&RecvLock) | static CRITICAL_SECTION FreeLock; | |||
# define UNLOCK() LeaveCriticalSection(&RecvLock) | # define LOCK_R() EnterCriticalSection(&RecvLock) | |||
# define UNLOCK_R() LeaveCriticalSection(&RecvLock) | ||||
# define LOCK_F() EnterCriticalSection(&FreeLock) | ||||
# define UNLOCK_F() LeaveCriticalSection(&FreeLock) | ||||
#else | #else | |||
# define LOCK() do {} while (FALSE) | # define LOCK_R() do {} while (FALSE) | |||
# define UNLOCK() do {} while (FALSE) | # define UNLOCK_R() do {} while (FALSE) | |||
# define LOCK_F() do {} while (FALSE) | ||||
# define UNLOCK_F() do {} while (FALSE) | ||||
#endif | #endif | |||
#ifdef DEBUG | #ifdef DEBUG | |||
static void uninit_recvbuff(void); | static void uninit_recvbuff(void); | |||
#endif | #endif | |||
u_long | u_long | |||
free_recvbuffs (void) | free_recvbuffs (void) | |||
{ | { | |||
return free_recvbufs; | return free_recvbufs; | |||
skipping to change at line 77 | skipping to change at line 94 | |||
return lowater_adds; | return lowater_adds; | |||
} | } | |||
static inline void | static inline void | |||
initialise_buffer(recvbuf_t *buff) | initialise_buffer(recvbuf_t *buff) | |||
{ | { | |||
ZERO(*buff); | ZERO(*buff); | |||
} | } | |||
static void | static void | |||
create_buffers(int nbufs) | create_buffers( | |||
size_t nbufs) | ||||
{ | { | |||
# ifndef DEBUG | ||||
static const u_int chunk = RECV_INC; | ||||
# else | ||||
/* Allocate each buffer individually so they can be free()d | ||||
* during ntpd shutdown on DEBUG builds to keep them out of heap | ||||
* leak reports. | ||||
*/ | ||||
static const u_int chunk = 1; | ||||
# endif | ||||
register recvbuf_t *bufp; | register recvbuf_t *bufp; | |||
int i, abuf; | u_int i; | |||
size_t abuf; | ||||
if (limit_recvbufs <= total_recvbufs) | ||||
return; | ||||
abuf = nbufs + buffer_shortfall; | abuf = nbufs + buffer_shortfall; | |||
buffer_shortfall = 0; | buffer_shortfall = 0; | |||
#ifndef DEBUG | if (abuf < nbufs || abuf > RECV_BATCH) | |||
bufp = eallocarray(abuf, sizeof(*bufp)); | abuf = RECV_BATCH; /* clamp on overflow */ | |||
#endif | else | |||
abuf += (~abuf + 1) & (RECV_INC - 1); /* round up */ | ||||
for (i = 0; i < abuf; i++) { | if (abuf > (limit_recvbufs - total_recvbufs)) | |||
#ifdef DEBUG | abuf = limit_recvbufs - total_recvbufs; | |||
/* | abuf += (~abuf + 1) & (chunk - 1); /* round up */ | |||
* Allocate each buffer individually so they can be | ||||
* free()d during ntpd shutdown on DEBUG builds to | while (abuf) { | |||
* keep them out of heap leak reports. | bufp = calloc(chunk, sizeof(*bufp)); | |||
*/ | if (!bufp) { | |||
bufp = emalloc_zero(sizeof(*bufp)); | limit_recvbufs = total_recvbufs; | |||
#endif | break; | |||
LINK_SLIST(free_recv_list, bufp, link); | } | |||
bufp++; | for (i = chunk; i; --i,++bufp) { | |||
free_recvbufs++; | LINK_SLIST(free_recv_list, bufp, link); | |||
total_recvbufs++; | } | |||
free_recvbufs += chunk; | ||||
total_recvbufs += chunk; | ||||
abuf -= chunk; | ||||
} | } | |||
lowater_adds++; | ++lowater_adds; | |||
} | } | |||
void | void | |||
init_recvbuff(int nbufs) | init_recvbuff(int nbufs) | |||
{ | { | |||
/* | /* | |||
* Init buffer free list and stat counters | * Init buffer free list and stat counters | |||
*/ | */ | |||
free_recvbufs = total_recvbufs = 0; | free_recvbufs = total_recvbufs = 0; | |||
full_recvbufs = lowater_adds = 0; | full_recvbufs = lowater_adds = 0; | |||
limit_recvbufs = RECV_TOOMANY; | ||||
emerg_recvbufs = RECV_CLOCK; | ||||
create_buffers(nbufs); | create_buffers(nbufs); | |||
#if defined(SYS_WINNT) | # if defined(SYS_WINNT) | |||
InitializeCriticalSection(&RecvLock); | InitializeCriticalSection(&RecvLock); | |||
#endif | InitializeCriticalSection(&FreeLock); | |||
# endif | ||||
#ifdef DEBUG | # ifdef DEBUG | |||
atexit(&uninit_recvbuff); | atexit(&uninit_recvbuff); | |||
#endif | # endif | |||
} | } | |||
#ifdef DEBUG | #ifdef DEBUG | |||
static void | static void | |||
uninit_recvbuff(void) | uninit_recvbuff(void) | |||
{ | { | |||
recvbuf_t *rbunlinked; | recvbuf_t *rbunlinked; | |||
for (;;) { | for (;;) { | |||
UNLINK_FIFO(rbunlinked, full_recv_fifo, link); | UNLINK_FIFO(rbunlinked, full_recv_fifo, link); | |||
skipping to change at line 146 | skipping to change at line 186 | |||
break; | break; | |||
free(rbunlinked); | free(rbunlinked); | |||
} | } | |||
for (;;) { | for (;;) { | |||
UNLINK_HEAD_SLIST(rbunlinked, free_recv_list, link); | UNLINK_HEAD_SLIST(rbunlinked, free_recv_list, link); | |||
if (rbunlinked == NULL) | if (rbunlinked == NULL) | |||
break; | break; | |||
free(rbunlinked); | free(rbunlinked); | |||
} | } | |||
# if defined(SYS_WINNT) | ||||
DeleteCriticalSection(&FreeLock); | ||||
DeleteCriticalSection(&RecvLock); | ||||
# endif | ||||
} | } | |||
#endif /* DEBUG */ | #endif /* DEBUG */ | |||
/* | /* | |||
* freerecvbuf - make a single recvbuf available for reuse | * freerecvbuf - make a single recvbuf available for reuse | |||
*/ | */ | |||
void | void | |||
freerecvbuf(recvbuf_t *rb) | freerecvbuf(recvbuf_t *rb) | |||
{ | { | |||
if (rb) { | if (rb) { | |||
LOCK(); | if (--rb->used != 0) { | |||
rb->used--; | ||||
if (rb->used != 0) | ||||
msyslog(LOG_ERR, "******** freerecvbuff non-zero usage: % d *******", rb->used); | msyslog(LOG_ERR, "******** freerecvbuff non-zero usage: % d *******", rb->used); | |||
rb->used = 0; | ||||
} | ||||
LOCK_F(); | ||||
LINK_SLIST(free_recv_list, rb, link); | LINK_SLIST(free_recv_list, rb, link); | |||
free_recvbufs++; | ++free_recvbufs; | |||
UNLOCK(); | UNLOCK_F(); | |||
} | } | |||
} | } | |||
void | void | |||
add_full_recv_buffer(recvbuf_t *rb) | add_full_recv_buffer(recvbuf_t *rb) | |||
{ | { | |||
if (rb == NULL) { | if (rb == NULL) { | |||
msyslog(LOG_ERR, "add_full_recv_buffer received NULL buffer"); | msyslog(LOG_ERR, "add_full_recv_buffer received NULL buffer"); | |||
return; | return; | |||
} | } | |||
LOCK(); | LOCK_R(); | |||
LINK_FIFO(full_recv_fifo, rb, link); | LINK_FIFO(full_recv_fifo, rb, link); | |||
full_recvbufs++; | ++full_recvbufs; | |||
UNLOCK(); | UNLOCK_R(); | |||
} | } | |||
recvbuf_t * | recvbuf_t * | |||
get_free_recv_buffer(void) | get_free_recv_buffer( | |||
{ | int /*BOOL*/ urgent | |||
recvbuf_t *buffer; | ) | |||
{ | ||||
recvbuf_t *buffer = NULL; | ||||
LOCK_F(); | ||||
if (free_recvbufs > (urgent ? emerg_recvbufs : 0)) { | ||||
UNLINK_HEAD_SLIST(buffer, free_recv_list, link); | ||||
} | ||||
LOCK(); | ||||
UNLINK_HEAD_SLIST(buffer, free_recv_list, link); | ||||
if (buffer != NULL) { | if (buffer != NULL) { | |||
free_recvbufs--; | if (free_recvbufs) | |||
--free_recvbufs; | ||||
initialise_buffer(buffer); | initialise_buffer(buffer); | |||
buffer->used++; | ++buffer->used; | |||
} else { | } else { | |||
buffer_shortfall++; | ++buffer_shortfall; | |||
} | } | |||
UNLOCK(); | UNLOCK_F(); | |||
return buffer; | return buffer; | |||
} | } | |||
#ifdef HAVE_IO_COMPLETION_PORT | #ifdef HAVE_IO_COMPLETION_PORT | |||
recvbuf_t * | recvbuf_t * | |||
get_free_recv_buffer_alloc(void) | get_free_recv_buffer_alloc( | |||
int /*BOOL*/ urgent | ||||
) | ||||
{ | { | |||
recvbuf_t *buffer; | LOCK_F(); | |||
if (free_recvbufs <= emerg_recvbufs || buffer_shortfall > 0) | ||||
buffer = get_free_recv_buffer(); | ||||
if (NULL == buffer) { | ||||
create_buffers(RECV_INC); | create_buffers(RECV_INC); | |||
buffer = get_free_recv_buffer(); | UNLOCK_F(); | |||
} | return get_free_recv_buffer(urgent); | |||
ENSURE(buffer != NULL); | ||||
return (buffer); | ||||
} | } | |||
#endif | #endif | |||
recvbuf_t * | recvbuf_t * | |||
get_full_recv_buffer(void) | get_full_recv_buffer(void) | |||
{ | { | |||
recvbuf_t * rbuf; | recvbuf_t * rbuf; | |||
LOCK(); | ||||
/* | /* | |||
* make sure there are free buffers when we | * make sure there are free buffers when we wander off to do | |||
* wander off to do lengthy packet processing with | * lengthy packet processing with any buffer we grab from the | |||
* any buffer we grab from the full list. | * full list. | |||
* | * | |||
* fixes malloc() interrupted by SIGIO risk | * fixes malloc() interrupted by SIGIO risk (Bug 889) | |||
* (Bug 889) | ||||
*/ | */ | |||
if (NULL == free_recv_list || buffer_shortfall > 0) { | LOCK_F(); | |||
/* | if (free_recvbufs <= emerg_recvbufs || buffer_shortfall > 0) | |||
* try to get us some more buffers | ||||
*/ | ||||
create_buffers(RECV_INC); | create_buffers(RECV_INC); | |||
} | UNLOCK_F(); | |||
/* | /* | |||
* try to grab a full buffer | * try to grab a full buffer | |||
*/ | */ | |||
LOCK_R(); | ||||
UNLINK_FIFO(rbuf, full_recv_fifo, link); | UNLINK_FIFO(rbuf, full_recv_fifo, link); | |||
if (rbuf != NULL) | if (rbuf != NULL && full_recvbufs) | |||
full_recvbufs--; | --full_recvbufs; | |||
UNLOCK(); | UNLOCK_R(); | |||
return rbuf; | return rbuf; | |||
} | } | |||
/* | /* | |||
* purge_recv_buffers_for_fd() - purges any previously-received input | * purge_recv_buffers_for_fd() - purges any previously-received input | |||
* from a given file descriptor. | * from a given file descriptor. | |||
*/ | */ | |||
void | void | |||
purge_recv_buffers_for_fd( | purge_recv_buffers_for_fd( | |||
int fd | int fd | |||
) | ) | |||
{ | { | |||
recvbuf_t *rbufp; | recvbuf_t *rbufp; | |||
recvbuf_t *next; | recvbuf_t *next; | |||
recvbuf_t *punlinked; | recvbuf_t *punlinked; | |||
recvbuf_t *freelist = NULL; | ||||
LOCK(); | /* We want to hold only one lock at a time. So we do a scan on | |||
* the full buffer queue, collecting items as we go, and when | ||||
* done we spool the the collected items to 'freerecvbuf()'. | ||||
*/ | ||||
LOCK_R(); | ||||
for (rbufp = HEAD_FIFO(full_recv_fifo); | for (rbufp = HEAD_FIFO(full_recv_fifo); | |||
rbufp != NULL; | rbufp != NULL; | |||
rbufp = next) { | rbufp = next) | |||
{ | ||||
next = rbufp->link; | next = rbufp->link; | |||
# ifdef HAVE_IO_COMPLETION_PORT | # ifdef HAVE_IO_COMPLETION_PORT | |||
if (rbufp->dstadr == NULL && rbufp->fd == fd) | if (rbufp->dstadr == NULL && rbufp->fd == fd) | |||
# else | # else | |||
if (rbufp->fd == fd) | if (rbufp->fd == fd) | |||
# endif | # endif | |||
{ | { | |||
UNLINK_MID_FIFO(punlinked, full_recv_fifo, | UNLINK_MID_FIFO(punlinked, full_recv_fifo, | |||
rbufp, link, recvbuf_t); | rbufp, link, recvbuf_t); | |||
INSIST(punlinked == rbufp); | INSIST(punlinked == rbufp); | |||
full_recvbufs--; | if (full_recvbufs) | |||
freerecvbuf(rbufp); | --full_recvbufs; | |||
rbufp->link = freelist; | ||||
freelist = rbufp; | ||||
} | } | |||
} | } | |||
UNLOCK(); | UNLOCK_R(); | |||
while (freelist) { | ||||
next = freelist->link; | ||||
freerecvbuf(freelist); | ||||
freelist = next; | ||||
} | ||||
} | } | |||
/* | /* | |||
* Checks to see if there are buffers to process | * Checks to see if there are buffers to process | |||
*/ | */ | |||
isc_boolean_t has_full_recv_buffer(void) | isc_boolean_t has_full_recv_buffer(void) | |||
{ | { | |||
if (HEAD_FIFO(full_recv_fifo) != NULL) | if (HEAD_FIFO(full_recv_fifo) != NULL) | |||
return (ISC_TRUE); | return (ISC_TRUE); | |||
else | else | |||
End of changes. 42 change blocks. | ||||
73 lines changed or deleted | 132 lines changed or added |