From 85b6b5c50750b61c54a53cb2b019cf0f5cd552da Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 13 Mar 2017 19:22:50 -0400 Subject: [PATCH 1/9] ca: support alloc larger than max array bytes automatically try to allocate a custom buffer when a message larger than ca max array bytes is encountered. --- src/ca/client/tcpiiu.cpp | 62 ++++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/src/ca/client/tcpiiu.cpp b/src/ca/client/tcpiiu.cpp index 7fd848b20..9581baa4c 100644 --- a/src/ca/client/tcpiiu.cpp +++ b/src/ca/client/tcpiiu.cpp @@ -26,6 +26,9 @@ #include #include + +#include + #include "errlog.h" #define epicsExportSharedSymbols @@ -1023,12 +1026,15 @@ tcpiiu :: ~tcpiiu () // free message body cache if ( this->pCurData ) { - if ( this->curDataMax == MAX_TCP ) { + if ( this->curDataMax <= MAX_TCP ) { this->cacRef.releaseSmallBufferTCP ( this->pCurData ); } - else { + else if ( this->curDataMax <= cacRef.largeBufferSizeTCP()) { this->cacRef.releaseLargeBufferTCP ( this->pCurData ); } + else { + free ( this->pCurData ); + } } } @@ -1197,18 +1203,44 @@ bool tcpiiu::processIncoming ( // make sure we have a large enough message body cache // if ( this->curMsg.m_postsize > this->curDataMax ) { - if ( this->curDataMax == MAX_TCP && - this->cacRef.largeBufferSizeTCP() >= this->curMsg.m_postsize ) { - char * pBuf = this->cacRef.allocateLargeBufferTCP (); - if ( pBuf ) { + assert (this->curMsg.m_postsize > MAX_TCP); + + char * newbuf = NULL; + arrayElementCount newsize; + + if ( this->curMsg.m_postsize <= this->cacRef.largeBufferSizeTCP() ) { + newbuf = this->cacRef.allocateLargeBufferTCP (); + newsize = this->cacRef.largeBufferSizeTCP(); + } +#ifndef NO_HUGE + else { + // round size up to multiple of 4K + newsize = ((this->curMsg.m_postsize-1)|0xfff)+1; + + if (this->curDataMax > this->cacRef.largeBufferSizeTCP()) { + // expand existing huge buffer + newbuf = (char*)realloc(this->pCurData, newsize); + } else { + // trade up from small or large + newbuf = (char*)malloc(newsize); + } + } +#endif + + if ( newbuf) { + if (this->curDataMax <= MAX_TCP) { this->cacRef.releaseSmallBufferTCP ( this->pCurData ); - this->pCurData = pBuf; - this->curDataMax = this->cacRef.largeBufferSizeTCP (); - } - else { - this->printFormated ( mgr.cbGuard, - "CAC: not enough memory for message body cache (ignoring response message)\n"); + } else if (this->curDataMax <= this->cacRef.largeBufferSizeTCP()) { + this->cacRef.releaseLargeBufferTCP ( this->pCurData ); + } else { + // called realloc() } + this->pCurData = newbuf; + this->curDataMax = newsize; + + } else { + this->printFormated ( mgr.cbGuard, + "CAC: not enough memory for message body cache (ignoring response message)\n"); } } @@ -1426,7 +1458,7 @@ void tcpiiu::readNotifyRequest ( epicsGuard < epicsMutex > & guard, } arrayElementCount maxBytes; if ( CA_V49 ( this->minorProtocolVersion ) ) { - maxBytes = this->cacRef.largeBufferSizeTCP (); + maxBytes = 0xfffffff0; } else { maxBytes = MAX_TCP; @@ -1537,7 +1569,7 @@ void tcpiiu::subscriptionRequest ( guard, CA_V413(this->minorProtocolVersion) ); arrayElementCount maxBytes; if ( CA_V49 ( this->minorProtocolVersion ) ) { - maxBytes = this->cacRef.largeBufferSizeTCP (); + maxBytes = 0xfffffff0; } else { maxBytes = MAX_TCP; @@ -1584,7 +1616,7 @@ void tcpiiu::subscriptionUpdateRequest ( guard, CA_V413(this->minorProtocolVersion) ); arrayElementCount maxBytes; if ( CA_V49 ( this->minorProtocolVersion ) ) { - maxBytes = this->cacRef.largeBufferSizeTCP (); + maxBytes = 0xfffffff0; } else { maxBytes = MAX_TCP; From b783427bf7e3a6f28fc6c3a5bbff0484964a23ee Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 13 Mar 2017 19:22:53 -0400 Subject: [PATCH 2/9] pcas: support larger than max array bytes clientBufMemoryManager already supports allocations larger than max array bytes, adjust callers inBuf/outBuf to actually request larger allocations. --- src/ca/legacy/pcas/generic/casStrmClient.cc | 2 +- .../pcas/generic/clientBufMemoryManager.cpp | 5 ----- .../pcas/generic/clientBufMemoryManager.h | 2 +- src/ca/legacy/pcas/generic/inBuf.cc | 18 +++++++++++++----- src/ca/legacy/pcas/generic/inBuf.h | 4 ++-- src/ca/legacy/pcas/generic/outBuf.cc | 16 +++++++++++----- src/ca/legacy/pcas/generic/outBuf.h | 2 +- 7 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/ca/legacy/pcas/generic/casStrmClient.cc b/src/ca/legacy/pcas/generic/casStrmClient.cc index ff12e889e..2da59b9d4 100644 --- a/src/ca/legacy/pcas/generic/casStrmClient.cc +++ b/src/ca/legacy/pcas/generic/casStrmClient.cc @@ -205,7 +205,7 @@ caStatus casStrmClient :: processMsg () if ( bytesLeft < msgSize ) { status = S_cas_success; if ( msgSize > this->in.bufferSize() ) { - this->in.expandBuffer (); + this->in.expandBuffer (msgSize); // msg to large - set up message drain if ( msgSize > this->in.bufferSize() ) { caServerI::dumpMsg ( this->pHostName, this->pUserName, & msgTmp, 0, diff --git a/src/ca/legacy/pcas/generic/clientBufMemoryManager.cpp b/src/ca/legacy/pcas/generic/clientBufMemoryManager.cpp index 2f5fc128b..53a638735 100644 --- a/src/ca/legacy/pcas/generic/clientBufMemoryManager.cpp +++ b/src/ca/legacy/pcas/generic/clientBufMemoryManager.cpp @@ -16,11 +16,6 @@ #define epicsExportSharedSymbols #include "clientBufMemoryManager.h" -bufSizeT clientBufMemoryManager::maxSize () const -{ - return bufferFactory.largeBufferSize (); -} - casBufferParm clientBufMemoryManager::allocate ( bufSizeT newMinSize ) { casBufferParm parm; diff --git a/src/ca/legacy/pcas/generic/clientBufMemoryManager.h b/src/ca/legacy/pcas/generic/clientBufMemoryManager.h index 9d63431e7..8a2db0da5 100644 --- a/src/ca/legacy/pcas/generic/clientBufMemoryManager.h +++ b/src/ca/legacy/pcas/generic/clientBufMemoryManager.h @@ -39,9 +39,9 @@ struct casBufferParm { class clientBufMemoryManager { public: + //! @throws std::bad_alloc on failure casBufferParm allocate ( bufSizeT newMinSize ); void release ( char * pBuf, bufSizeT bufSize ); - bufSizeT maxSize () const; private: casBufferFactory bufferFactory; }; diff --git a/src/ca/legacy/pcas/generic/inBuf.cc b/src/ca/legacy/pcas/generic/inBuf.cc index db97a082c..43250d6e4 100644 --- a/src/ca/legacy/pcas/generic/inBuf.cc +++ b/src/ca/legacy/pcas/generic/inBuf.cc @@ -13,6 +13,8 @@ * 505 665 1831 */ +#include + #include #include @@ -155,11 +157,17 @@ bufSizeT inBuf::popCtx ( const inBufCtx &ctx ) } } -void inBuf::expandBuffer () +void inBuf::expandBuffer (bufSizeT needed) { - bufSizeT max = this->memMgr.maxSize(); - if ( this->bufSize < max ) { - casBufferParm bufParm = this->memMgr.allocate ( max ); + if (needed > bufSize) { + casBufferParm bufParm; + try { + bufParm = this->memMgr.allocate ( needed ); + } catch (std::bad_alloc& e) { + // caller must check that buffer size has expended + return; + } + bufSizeT unprocessedBytes = this->bytesPresent (); memcpy ( bufParm.pBuf, &this->pBuf[this->nextReadIndex], unprocessedBytes ); this->bytesInBuffer = unprocessedBytes; @@ -170,7 +178,7 @@ void inBuf::expandBuffer () } } -unsigned inBuf::bufferSize () const +bufSizeT inBuf::bufferSize() const { return this->bufSize; } diff --git a/src/ca/legacy/pcas/generic/inBuf.h b/src/ca/legacy/pcas/generic/inBuf.h index 180fc5a6d..8098ad26e 100644 --- a/src/ca/legacy/pcas/generic/inBuf.h +++ b/src/ca/legacy/pcas/generic/inBuf.h @@ -82,8 +82,8 @@ public: // const inBufCtx pushCtx ( bufSizeT headerSize, bufSizeT bodySize ); bufSizeT popCtx ( const inBufCtx & ); // returns actual size - unsigned bufferSize () const; - void expandBuffer (); + bufSizeT bufferSize () const; + void expandBuffer (bufSizeT needed); private: class inBufClient & client; class clientBufMemoryManager & memMgr; diff --git a/src/ca/legacy/pcas/generic/outBuf.cc b/src/ca/legacy/pcas/generic/outBuf.cc index e755753e8..ed9cd8505 100644 --- a/src/ca/legacy/pcas/generic/outBuf.cc +++ b/src/ca/legacy/pcas/generic/outBuf.cc @@ -59,7 +59,7 @@ caStatus outBuf::allocRawMsg ( bufSizeT msgsize, void **ppMsg ) msgsize = CA_MESSAGE_ALIGN ( msgsize ); if ( msgsize > this->bufSize ) { - this->expandBuffer (); + this->expandBuffer (msgsize); if ( msgsize > this->bufSize ) { return S_cas_hugeRequest; } @@ -316,11 +316,17 @@ void outBuf::show (unsigned level) const } } -void outBuf::expandBuffer () +void outBuf::expandBuffer (bufSizeT needed) { - bufSizeT max = this->memMgr.maxSize(); - if ( this->bufSize < max ) { - casBufferParm bufParm = this->memMgr.allocate ( max ); + if (needed > bufSize) { + casBufferParm bufParm; + try { + bufParm = this->memMgr.allocate ( needed ); + } catch (std::bad_alloc& e) { + // caller must check that buffer size has expended + return; + } + memcpy ( bufParm.pBuf, this->pBuf, this->stack ); this->memMgr.release ( this->pBuf, this->bufSize ); this->pBuf = bufParm.pBuf; diff --git a/src/ca/legacy/pcas/generic/outBuf.h b/src/ca/legacy/pcas/generic/outBuf.h index 849964bf2..87a428bbe 100644 --- a/src/ca/legacy/pcas/generic/outBuf.h +++ b/src/ca/legacy/pcas/generic/outBuf.h @@ -122,7 +122,7 @@ private: bufSizeT stack; unsigned ctxRecursCount; - void expandBuffer (); + void expandBuffer (bufSizeT needed); outBuf ( const outBuf & ); outBuf & operator = ( const outBuf & ); From 3009f88f6486e7e63445b03664b4638859cd8f3e Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 13 Mar 2017 19:22:56 -0400 Subject: [PATCH 3/9] rsrv: support larger than max. array bytes --- src/ioc/rsrv/caservertask.c | 109 ++++++++++++++++++++++++++---------- src/ioc/rsrv/server.h | 2 +- 2 files changed, 79 insertions(+), 32 deletions(-) diff --git a/src/ioc/rsrv/caservertask.c b/src/ioc/rsrv/caservertask.c index a18abafe2..a138fbba9 100644 --- a/src/ioc/rsrv/caservertask.c +++ b/src/ioc/rsrv/caservertask.c @@ -1060,6 +1060,9 @@ void destroy_client ( struct client *client ) else if ( client->send.type == mbtLargeTCP ) { freeListFree ( rsrvLargeBufFreeListTCP, client->send.buf ); } + else if (client->send.type == mbtHugeTCP ) { + free ( client->send.buf ); + } else { errlogPrintf ( "CAS: Corrupt send buffer free list type code=%u during client cleanup?\n", client->send.type ); @@ -1072,6 +1075,9 @@ void destroy_client ( struct client *client ) else if ( client->recv.type == mbtLargeTCP ) { freeListFree ( rsrvLargeBufFreeListTCP, client->recv.buf ); } + else if (client->recv.type == mbtHugeTCP ) { + free ( client->recv.buf ); + } else { errlogPrintf ( "CAS: Corrupt recv buffer free list type code=%u during client cleanup?\n", client->send.type ); @@ -1301,43 +1307,84 @@ void casAttachThreadToClient ( struct client *pClient ) taskwdInsert ( pClient->tid, NULL, NULL ); } +static +void casExpandBuffer ( struct message_buffer *buf, ca_uint32_t size, int sendbuf ) +{ + char *newbuf = NULL; + unsigned newsize; + enum messageBufferType newtype; + + assert (size > MAX_TCP); + + if ( size <= buf->maxstk || buf->type == mbtUDP ) return; + + /* try to alloc new buffer */ + if (size <= MAX_TCP) { + return; /* shouldn't happen */ + } else if (size <= rsrvSizeofLargeBufTCP) { + newbuf = freeListCalloc ( rsrvLargeBufFreeListTCP ); + newsize = rsrvSizeofLargeBufTCP; + newtype = mbtLargeTCP; + } +#ifndef NO_HUGE + else { + size = ((size-1)|0xfff)+1; + + if (buf->type==mbtHugeTCP) + newbuf = realloc (buf->buf, size); + else + newbuf = malloc (size); + newtype = mbtHugeTCP; + newsize = size; + } +#endif + + if (newbuf) { + /* copy existing buffer */ + if (sendbuf) { + /* send buffer uses [0, stk) */ + if (buf->type==mbtHugeTCP) { + /* realloc already copied */ + } else { + memcpy ( newbuf, buf->buf, buf->stk ); + } + } else { + /* recv buffer uses [stk, cnt) */ + unsigned used; + assert ( buf->cnt >= buf->stk ); + used = buf->cnt - buf->stk; + + /* buf->buf may be the same as newbuf if realloc() used */ + memmove ( newbuf, &buf->buf[buf->stk], used ); + + buf->cnt = used; + buf->stk = 0; + + } + + /* free existing buffer */ + if(buf->type==mbtSmallTCP) { + freeListFree ( rsrvSmallBufFreeListTCP, buf->buf ); + } else if(buf->type==mbtLargeTCP) { + freeListFree ( rsrvLargeBufFreeListTCP, buf->buf ); + } else { + /* realloc() already free()'d if necessary */ + } + + buf->buf = newbuf; + buf->type = newtype; + buf->maxstk = newsize; + } +} + void casExpandSendBuffer ( struct client *pClient, ca_uint32_t size ) { - if ( pClient->send.type == mbtSmallTCP && rsrvSizeofLargeBufTCP > MAX_TCP - && size <= rsrvSizeofLargeBufTCP ) { - int spaceAvailOnFreeList = freeListItemsAvail ( rsrvLargeBufFreeListTCP ) > 0; - if ( osiSufficentSpaceInPool(rsrvSizeofLargeBufTCP) || spaceAvailOnFreeList ) { - char *pNewBuf = ( char * ) freeListCalloc ( rsrvLargeBufFreeListTCP ); - if ( pNewBuf ) { - memcpy ( pNewBuf, pClient->send.buf, pClient->send.stk ); - freeListFree ( rsrvSmallBufFreeListTCP, pClient->send.buf ); - pClient->send.buf = pNewBuf; - pClient->send.maxstk = rsrvSizeofLargeBufTCP; - pClient->send.type = mbtLargeTCP; - } - } - } + casExpandBuffer (&pClient->send, size, 1); } void casExpandRecvBuffer ( struct client *pClient, ca_uint32_t size ) { - if ( pClient->recv.type == mbtSmallTCP && rsrvSizeofLargeBufTCP > MAX_TCP - && size <= rsrvSizeofLargeBufTCP) { - int spaceAvailOnFreeList = freeListItemsAvail ( rsrvLargeBufFreeListTCP ) > 0; - if ( osiSufficentSpaceInPool(rsrvSizeofLargeBufTCP) || spaceAvailOnFreeList ) { - char *pNewBuf = ( char * ) freeListCalloc ( rsrvLargeBufFreeListTCP ); - if ( pNewBuf ) { - assert ( pClient->recv.cnt >= pClient->recv.stk ); - memcpy ( pNewBuf, &pClient->recv.buf[pClient->recv.stk], pClient->recv.cnt - pClient->recv.stk ); - freeListFree ( rsrvSmallBufFreeListTCP, pClient->recv.buf ); - pClient->recv.buf = pNewBuf; - pClient->recv.cnt = pClient->recv.cnt - pClient->recv.stk; - pClient->recv.stk = 0u; - pClient->recv.maxstk = rsrvSizeofLargeBufTCP; - pClient->recv.type = mbtLargeTCP; - } - } - } + casExpandBuffer (&pClient->recv, size, 0); } /* diff --git a/src/ioc/rsrv/server.h b/src/ioc/rsrv/server.h index d2a1cf3f4..86407a8c5 100644 --- a/src/ioc/rsrv/server.h +++ b/src/ioc/rsrv/server.h @@ -60,7 +60,7 @@ typedef struct caHdrLargeArray { * Eight-byte alignment is required by the Sparc 5 and other RISC * processors. */ -enum messageBufferType { mbtUDP, mbtSmallTCP, mbtLargeTCP }; +enum messageBufferType { mbtUDP, mbtSmallTCP, mbtLargeTCP, mbtHugeTCP }; struct message_buffer { char *buf; unsigned stk; From 2096c60652fedeef109cdd5472a6b12741ab114c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 18 Mar 2017 15:45:03 -0400 Subject: [PATCH 4/9] ca: large array free list is optional --- src/ca/client/cac.cpp | 22 +++++++++++++------- src/ca/client/cac.h | 38 +++------------------------------ src/ca/client/tcpiiu.cpp | 45 ++++++++++++++++++++++------------------ 3 files changed, 43 insertions(+), 62 deletions(-) diff --git a/src/ca/client/cac.cpp b/src/ca/client/cac.cpp index bdfc68c73..d13b5766c 100644 --- a/src/ca/client/cac.cpp +++ b/src/ca/client/cac.cpp @@ -54,6 +54,12 @@ static const char pVersionCAC[] = "@(#) " EPICS_VERSION_STRING ", CA Client Library " __DATE__; +// when set, respect EPICS_CA_MAX_ARRAY_BYTES +// when clear, ignore it +extern "C" { +int caLimitArray; +} + // TCP response dispatch table const cac::pProtoStubTCP cac::tcpJumpTableCAC [] = { @@ -218,9 +224,11 @@ cac::cac ( throw std::bad_alloc (); } - freeListInitPvt ( &this->tcpLargeRecvBufFreeList, this->maxRecvBytesTCP, 1 ); - if ( ! this->tcpLargeRecvBufFreeList ) { - throw std::bad_alloc (); + if(caLimitArray) { + freeListInitPvt ( &this->tcpLargeRecvBufFreeList, this->maxRecvBytesTCP, 1 ); + if ( ! this->tcpLargeRecvBufFreeList ) { + throw std::bad_alloc (); + } } unsigned bufsPerArray = this->maxRecvBytesTCP / comBuf::capacityBytes (); if ( bufsPerArray > 1u ) { @@ -231,9 +239,7 @@ cac::cac ( catch ( ... ) { osiSockRelease (); delete [] this->pUserName; - if ( this->tcpSmallRecvBufFreeList ) { - freeListCleanup ( this->tcpSmallRecvBufFreeList ); - } + freeListCleanup ( this->tcpSmallRecvBufFreeList ); if ( this->tcpLargeRecvBufFreeList ) { freeListCleanup ( this->tcpLargeRecvBufFreeList ); } @@ -318,7 +324,9 @@ cac::~cac () } freeListCleanup ( this->tcpSmallRecvBufFreeList ); - freeListCleanup ( this->tcpLargeRecvBufFreeList ); + if ( this->tcpLargeRecvBufFreeList ) { + freeListCleanup ( this->tcpLargeRecvBufFreeList ); + } delete [] this->pUserName; diff --git a/src/ca/client/cac.h b/src/ca/client/cac.h index 99c3d3d27..7db5c6ddc 100644 --- a/src/ca/client/cac.h +++ b/src/ca/client/cac.h @@ -51,6 +51,7 @@ class netWriteNotifyIO; class netReadNotifyIO; class netSubscription; +class tcpiiu; // used to control access to cac's recycle routines which // should only be indirectly invoked by CAC when its lock @@ -193,12 +194,6 @@ public: const char *pformat, va_list args ) const; double connectionTimeout ( epicsGuard < epicsMutex > & ); - // buffer management - char * allocateSmallBufferTCP (); - void releaseSmallBufferTCP ( char * ); - unsigned largeBufferSizeTCP () const; - char * allocateLargeBufferTCP (); - void releaseLargeBufferTCP ( char * ); unsigned maxContiguousFrames ( epicsGuard < epicsMutex > & ) const; // misc @@ -355,6 +350,8 @@ private: cac ( const cac & ); cac & operator = ( const cac & ); + + friend class tcpiiu; }; inline const char * cac::userNamePointer () const @@ -385,35 +382,6 @@ inline void cac::attachToClientCtx () this->notify.attachToClientCtx (); } -inline char * cac::allocateSmallBufferTCP () -{ - // this locks internally - return ( char * ) freeListMalloc ( this->tcpSmallRecvBufFreeList ); -} - -inline void cac::releaseSmallBufferTCP ( char *pBuf ) -{ - // this locks internally - freeListFree ( this->tcpSmallRecvBufFreeList, pBuf ); -} - -inline unsigned cac::largeBufferSizeTCP () const -{ - return this->maxRecvBytesTCP; -} - -inline char * cac::allocateLargeBufferTCP () -{ - // this locks internally - return ( char * ) freeListMalloc ( this->tcpLargeRecvBufFreeList ); -} - -inline void cac::releaseLargeBufferTCP ( char *pBuf ) -{ - // this locks internally - freeListFree ( this->tcpLargeRecvBufFreeList, pBuf ); -} - inline unsigned cac::beaconAnomaliesSinceProgramStart ( epicsGuard < epicsMutex > & guard ) const { diff --git a/src/ca/client/tcpiiu.cpp b/src/ca/client/tcpiiu.cpp index 9581baa4c..045f8d57e 100644 --- a/src/ca/client/tcpiiu.cpp +++ b/src/ca/client/tcpiiu.cpp @@ -690,7 +690,7 @@ tcpiiu::tcpiiu ( curDataBytes ( 0ul ), comBufMemMgr ( comBufMemMgrIn ), cacRef ( cac ), - pCurData ( cac.allocateSmallBufferTCP () ), + pCurData ( (char*) freeListMalloc(this->cacRef.tcpSmallRecvBufFreeList) ), pSearchDest ( pSearchDestIn ), mutex ( mutexIn ), cbMutex ( cbMutexIn ), @@ -714,9 +714,12 @@ tcpiiu::tcpiiu ( socketHasBeenClosed ( false ), unresponsiveCircuit ( false ) { + if(!pCurData) + throw std::bad_alloc(); + this->sock = epicsSocketCreate ( AF_INET, SOCK_STREAM, IPPROTO_TCP ); if ( this->sock == INVALID_SOCKET ) { - cac.releaseSmallBufferTCP ( this->pCurData ); + freeListFree(this->cacRef.tcpSmallRecvBufFreeList, this->pCurData); char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); @@ -1027,10 +1030,10 @@ tcpiiu :: ~tcpiiu () // free message body cache if ( this->pCurData ) { if ( this->curDataMax <= MAX_TCP ) { - this->cacRef.releaseSmallBufferTCP ( this->pCurData ); + freeListFree(this->cacRef.tcpSmallRecvBufFreeList, this->pCurData); } - else if ( this->curDataMax <= cacRef.largeBufferSizeTCP()) { - this->cacRef.releaseLargeBufferTCP ( this->pCurData ); + else if ( this->cacRef.tcpLargeRecvBufFreeList ) { + freeListFree(this->cacRef.tcpLargeRecvBufFreeList, this->pCurData); } else { free ( this->pCurData ); @@ -1208,30 +1211,32 @@ bool tcpiiu::processIncoming ( char * newbuf = NULL; arrayElementCount newsize; - if ( this->curMsg.m_postsize <= this->cacRef.largeBufferSizeTCP() ) { - newbuf = this->cacRef.allocateLargeBufferTCP (); - newsize = this->cacRef.largeBufferSizeTCP(); - } -#ifndef NO_HUGE - else { + if ( !this->cacRef.tcpLargeRecvBufFreeList ) { // round size up to multiple of 4K newsize = ((this->curMsg.m_postsize-1)|0xfff)+1; - if (this->curDataMax > this->cacRef.largeBufferSizeTCP()) { - // expand existing huge buffer - newbuf = (char*)realloc(this->pCurData, newsize); - } else { - // trade up from small or large + if ( this->curDataMax <= MAX_TCP ) { + // small -> large newbuf = (char*)malloc(newsize); + + } else { + // expand large to larger + newbuf = (char*)realloc(this->pCurData, newsize); } + + } else if ( this->curMsg.m_postsize <= this->cacRef.maxRecvBytesTCP ) { + newbuf = (char*) freeListMalloc(this->cacRef.tcpLargeRecvBufFreeList); + newsize = this->cacRef.maxRecvBytesTCP; + } -#endif if ( newbuf) { if (this->curDataMax <= MAX_TCP) { - this->cacRef.releaseSmallBufferTCP ( this->pCurData ); - } else if (this->curDataMax <= this->cacRef.largeBufferSizeTCP()) { - this->cacRef.releaseLargeBufferTCP ( this->pCurData ); + freeListFree(this->cacRef.tcpSmallRecvBufFreeList, this->pCurData ); + + } else if (this->cacRef.tcpLargeRecvBufFreeList) { + freeListFree(this->cacRef.tcpLargeRecvBufFreeList, this->pCurData ); + } else { // called realloc() } From 1e7c80c9095f52f59723f1c6c53f2cfdbd016f2d Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 18 Mar 2017 16:17:19 -0400 Subject: [PATCH 5/9] cas: simplify buffer alloc eliminate casBufferFactory. move small buffer free list into clientBufMemoryManager --- src/ca/legacy/pcas/build/Makefile | 1 - .../legacy/pcas/generic/casBufferFactory.cpp | 104 ------------------ .../pcas/generic/clientBufMemoryManager.cpp | 45 +++++--- .../pcas/generic/clientBufMemoryManager.h | 22 +--- 4 files changed, 36 insertions(+), 136 deletions(-) delete mode 100644 src/ca/legacy/pcas/generic/casBufferFactory.cpp diff --git a/src/ca/legacy/pcas/build/Makefile b/src/ca/legacy/pcas/build/Makefile index 707344d02..e30560882 100644 --- a/src/ca/legacy/pcas/build/Makefile +++ b/src/ca/legacy/pcas/build/Makefile @@ -53,7 +53,6 @@ LIBSRCS += outBuf.cc LIBSRCS += casCtx.cc LIBSRCS += casEventMask.cc LIBSRCS += ioBlocked.cc -LIBSRCS += casBufferFactory.cc LIBSRCS += pvExistReturn.cc LIBSRCS += pvAttachReturn.cc LIBSRCS += caNetAddr.cc diff --git a/src/ca/legacy/pcas/generic/casBufferFactory.cpp b/src/ca/legacy/pcas/generic/casBufferFactory.cpp deleted file mode 100644 index 9f311a091..000000000 --- a/src/ca/legacy/pcas/generic/casBufferFactory.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/*************************************************************************\ -* Copyright (c) 2002 The University of Chicago, as Operator of Argonne -* National Laboratory. -* Copyright (c) 2002 The Regents of the University of California, as -* Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. -\*************************************************************************/ -/* - * Author Jeffrey O. Hill - * johill@lanl.gov - * 505 665 1831 - */ - -#include - -#include "envDefs.h" -#include "freeList.h" -#include "errlog.h" - -#define epicsExportSharedSymbols -#include "clientBufMemoryManager.h" -#include "caProto.h" - -casBufferFactory::casBufferFactory () : - smallBufFreeList ( 0 ), largeBufFreeList ( 0 ), largeBufferSizePriv ( 0u ) -{ - long maxBytesAsALong; - long status = envGetLongConfigParam ( & EPICS_CA_MAX_ARRAY_BYTES, & maxBytesAsALong ); - if ( status || maxBytesAsALong < 0 ) { - errlogPrintf ( "cas: EPICS_CA_MAX_ARRAY_BYTES was not a positive integer\n" ); - this->largeBufferSizePriv = MAX_TCP; - } - else { - /* allow room for the protocol header so that they get the array size they requested */ - static const unsigned headerSize = sizeof ( caHdr ) + 2 * sizeof ( ca_uint32_t ); - ca_uint32_t maxBytes = ( unsigned ) maxBytesAsALong; - if ( maxBytes < 0xffffffff - headerSize ) { - maxBytes += headerSize; - } - else { - maxBytes = 0xffffffff; - } - if ( maxBytes < MAX_TCP ) { - errlogPrintf ( "cas: EPICS_CA_MAX_ARRAY_BYTES was rounded up to %u\n", MAX_TCP ); - this->largeBufferSizePriv = MAX_TCP; - } - else { - this->largeBufferSizePriv = maxBytes; - } - } - - freeListInitPvt ( & this->smallBufFreeList, MAX_MSG_SIZE, 8 ); - freeListInitPvt ( & this->largeBufFreeList, this->largeBufferSizePriv, 1 ); -} - -casBufferFactory::~casBufferFactory () -{ - freeListCleanup ( this->smallBufFreeList ); - freeListCleanup ( this->largeBufFreeList ); -} - -unsigned casBufferFactory::smallBufferSize () const -{ - return MAX_MSG_SIZE; -} - -char * casBufferFactory::newSmallBuffer () -{ - void * pBuf = freeListCalloc ( this->smallBufFreeList ); - if ( ! pBuf ) { - throw std::bad_alloc(); - } - return static_cast < char * > ( pBuf ); -} - -void casBufferFactory::destroySmallBuffer ( char * pBuf ) -{ - if ( pBuf ) { - freeListFree ( this->smallBufFreeList, pBuf ); - } -} - -unsigned casBufferFactory::largeBufferSize () const -{ - return this->largeBufferSizePriv; -} - -char * casBufferFactory::newLargeBuffer () -{ - void * pBuf = freeListCalloc ( this->largeBufFreeList ); - if ( ! pBuf ) { - throw std::bad_alloc(); - } - return static_cast < char * > ( pBuf ); -} - -void casBufferFactory::destroyLargeBuffer ( char * pBuf ) -{ - if ( pBuf ) { - freeListFree ( this->largeBufFreeList, pBuf ); - } -} diff --git a/src/ca/legacy/pcas/generic/clientBufMemoryManager.cpp b/src/ca/legacy/pcas/generic/clientBufMemoryManager.cpp index 53a638735..167995f91 100644 --- a/src/ca/legacy/pcas/generic/clientBufMemoryManager.cpp +++ b/src/ca/legacy/pcas/generic/clientBufMemoryManager.cpp @@ -13,37 +13,54 @@ * 505 665 1831 */ +#include + +#include + +#include "epicsAssert.h" +#include "freeList.h" + #define epicsExportSharedSymbols #include "clientBufMemoryManager.h" +#include "caProto.h" + +clientBufMemoryManager::clientBufMemoryManager() + :smallBufFreeList ( 0 ) +{ + freeListInitPvt ( & this->smallBufFreeList, MAX_MSG_SIZE, 8 ); +} + +clientBufMemoryManager::~clientBufMemoryManager() +{ + freeListCleanup ( this->smallBufFreeList ); +} casBufferParm clientBufMemoryManager::allocate ( bufSizeT newMinSize ) { casBufferParm parm; - if ( newMinSize <= bufferFactory.smallBufferSize () ) { - parm.pBuf = bufferFactory.newSmallBuffer (); - parm.bufSize = bufferFactory.smallBufferSize (); - } - else if ( newMinSize <= bufferFactory.largeBufferSize () ) { - parm.pBuf = bufferFactory.newLargeBuffer (); - parm.bufSize = bufferFactory.largeBufferSize (); + if ( newMinSize <= MAX_MSG_SIZE ) { + parm.pBuf = (char*)freeListMalloc(this->smallBufFreeList); + parm.bufSize = MAX_MSG_SIZE; } else { - parm.pBuf = static_cast < char * > ( ::operator new ( newMinSize ) ); + // round size up to multiple of 4K + newMinSize = ((newMinSize-1)|0xfff)+1; + parm.pBuf = (char*)malloc(newMinSize); parm.bufSize = newMinSize; } + if(!parm.pBuf) + throw std::bad_alloc(); return parm; } void clientBufMemoryManager::release ( char * pBuf, bufSizeT bufSize ) { - if ( bufSize == bufferFactory.smallBufferSize () ) { - bufferFactory.destroySmallBuffer ( pBuf ); - } - else if ( bufSize == bufferFactory.largeBufferSize () ) { - bufferFactory.destroyLargeBuffer ( pBuf ); + assert(pBuf); + if (bufSize <= MAX_MSG_SIZE) { + freeListFree(this->smallBufFreeList, pBuf); } else { - ::operator delete ( pBuf ); + free(pBuf); } } diff --git a/src/ca/legacy/pcas/generic/clientBufMemoryManager.h b/src/ca/legacy/pcas/generic/clientBufMemoryManager.h index 8a2db0da5..9a823484d 100644 --- a/src/ca/legacy/pcas/generic/clientBufMemoryManager.h +++ b/src/ca/legacy/pcas/generic/clientBufMemoryManager.h @@ -16,22 +16,6 @@ typedef unsigned bufSizeT; static const unsigned bufSizeT_MAX = UINT_MAX; -class casBufferFactory { -public: - casBufferFactory (); - ~casBufferFactory (); - unsigned smallBufferSize () const; - char * newSmallBuffer (); - void destroySmallBuffer ( char * pBuf ); - unsigned largeBufferSize () const; - char * newLargeBuffer (); - void destroyLargeBuffer ( char * pBuf ); -private: - void * smallBufFreeList; - void * largeBufFreeList; - unsigned largeBufferSizePriv; -}; - struct casBufferParm { char * pBuf; bufSizeT bufSize; @@ -39,11 +23,15 @@ struct casBufferParm { class clientBufMemoryManager { public: + clientBufMemoryManager(); + ~clientBufMemoryManager(); + //! @throws std::bad_alloc on failure casBufferParm allocate ( bufSizeT newMinSize ); void release ( char * pBuf, bufSizeT bufSize ); private: - casBufferFactory bufferFactory; + + void * smallBufFreeList; }; #endif // clientBufMemoryManagerh From 1636f3d9feb36a47a5d64571b272f8958782727b Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 18 Mar 2017 16:32:08 -0400 Subject: [PATCH 6/9] rsrv: optional max_array_bytes use of large array free list is optional --- src/ioc/rsrv/caservertask.c | 59 +++++++++++++++++++++---------------- src/ioc/rsrv/server.h | 2 +- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/src/ioc/rsrv/caservertask.c b/src/ioc/rsrv/caservertask.c index a138fbba9..c890a8e16 100644 --- a/src/ioc/rsrv/caservertask.c +++ b/src/ioc/rsrv/caservertask.c @@ -47,6 +47,10 @@ epicsThreadPrivateId rsrvCurrentClient; +// defined in cac.cpp +extern int caLimitArray; + + /* * * req_server() @@ -525,7 +529,10 @@ int rsrv_init (void) rsrvSizeofLargeBufTCP = maxBytes; } } - freeListInitPvt ( &rsrvLargeBufFreeListTCP, rsrvSizeofLargeBufTCP, 1 ); + if (caLimitArray) + freeListInitPvt ( &rsrvLargeBufFreeListTCP, rsrvSizeofLargeBufTCP, 1 ); + else + rsrvLargeBufFreeListTCP = NULL; pCaBucket = bucketCreate(CAS_HASH_TABLE_SIZE); if (!pCaBucket) cantProceed("RSRV failed to allocate ID lookup table\n"); @@ -1012,8 +1019,10 @@ void casr (unsigned level) freeListItemsAvail (rsrvEventFreeList); bytes_reserved += MAX_TCP * freeListItemsAvail ( rsrvSmallBufFreeListTCP ); - bytes_reserved += rsrvSizeofLargeBufTCP * - freeListItemsAvail ( rsrvLargeBufFreeListTCP ); + if(rsrvLargeBufFreeListTCP) { + bytes_reserved += rsrvSizeofLargeBufTCP * + freeListItemsAvail ( rsrvLargeBufFreeListTCP ); + } bytes_reserved += rsrvSizeOfPutNotify ( 0 ) * freeListItemsAvail ( rsrvPutNotifyFreeList ); printf( "Free-lists total %u bytes, comprising\n", @@ -1026,7 +1035,7 @@ void casr (unsigned level) printf( " %u small (%u byte) buffers, %u jumbo (%u byte) buffers\n", (unsigned int) freeListItemsAvail ( rsrvSmallBufFreeListTCP ), MAX_TCP, - (unsigned int) freeListItemsAvail ( rsrvLargeBufFreeListTCP ), + (unsigned int)(rsrvLargeBufFreeListTCP ? freeListItemsAvail ( rsrvLargeBufFreeListTCP ) : -1), rsrvSizeofLargeBufTCP ); printf( "Server resource id table:\n"); LOCK_CLIENTQ; @@ -1058,10 +1067,10 @@ void destroy_client ( struct client *client ) freeListFree ( rsrvSmallBufFreeListTCP, client->send.buf ); } else if ( client->send.type == mbtLargeTCP ) { - freeListFree ( rsrvLargeBufFreeListTCP, client->send.buf ); - } - else if (client->send.type == mbtHugeTCP ) { - free ( client->send.buf ); + if(rsrvLargeBufFreeListTCP) + freeListFree ( rsrvLargeBufFreeListTCP, client->send.buf ); + else + free(client->send.buf); } else { errlogPrintf ( "CAS: Corrupt send buffer free list type code=%u during client cleanup?\n", @@ -1073,10 +1082,10 @@ void destroy_client ( struct client *client ) freeListFree ( rsrvSmallBufFreeListTCP, client->recv.buf ); } else if ( client->recv.type == mbtLargeTCP ) { - freeListFree ( rsrvLargeBufFreeListTCP, client->recv.buf ); - } - else if (client->recv.type == mbtHugeTCP ) { - free ( client->recv.buf ); + if(rsrvLargeBufFreeListTCP) + freeListFree ( rsrvLargeBufFreeListTCP, client->recv.buf ); + else + free(client->recv.buf); } else { errlogPrintf ( "CAS: Corrupt recv buffer free list type code=%u during client cleanup?\n", @@ -1321,29 +1330,29 @@ void casExpandBuffer ( struct message_buffer *buf, ca_uint32_t size, int sendbuf /* try to alloc new buffer */ if (size <= MAX_TCP) { return; /* shouldn't happen */ + + } else if(!rsrvLargeBufFreeListTCP) { + // round up to multiple of 4K + size = ((size-1)|0xfff)+1; + + if (buf->type==mbtLargeTCP) + newbuf = realloc (buf->buf, size); + else + newbuf = malloc (size); + newtype = mbtLargeTCP; + newsize = size; + } else if (size <= rsrvSizeofLargeBufTCP) { newbuf = freeListCalloc ( rsrvLargeBufFreeListTCP ); newsize = rsrvSizeofLargeBufTCP; newtype = mbtLargeTCP; } -#ifndef NO_HUGE - else { - size = ((size-1)|0xfff)+1; - - if (buf->type==mbtHugeTCP) - newbuf = realloc (buf->buf, size); - else - newbuf = malloc (size); - newtype = mbtHugeTCP; - newsize = size; - } -#endif if (newbuf) { /* copy existing buffer */ if (sendbuf) { /* send buffer uses [0, stk) */ - if (buf->type==mbtHugeTCP) { + if (!rsrvLargeBufFreeListTCP && buf->type==mbtLargeTCP) { /* realloc already copied */ } else { memcpy ( newbuf, buf->buf, buf->stk ); diff --git a/src/ioc/rsrv/server.h b/src/ioc/rsrv/server.h index 86407a8c5..d2a1cf3f4 100644 --- a/src/ioc/rsrv/server.h +++ b/src/ioc/rsrv/server.h @@ -60,7 +60,7 @@ typedef struct caHdrLargeArray { * Eight-byte alignment is required by the Sparc 5 and other RISC * processors. */ -enum messageBufferType { mbtUDP, mbtSmallTCP, mbtLargeTCP, mbtHugeTCP }; +enum messageBufferType { mbtUDP, mbtSmallTCP, mbtLargeTCP }; struct message_buffer { char *buf; unsigned stk; From 675c2aff14e13b9845ad01ee4eccdb2c249c30ed Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 18 Mar 2017 16:59:23 -0400 Subject: [PATCH 7/9] rsrv: export variable caLimitArray --- src/ioc/misc/dbCore.dbd | 3 +++ src/ioc/rsrv/caservertask.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/ioc/misc/dbCore.dbd b/src/ioc/misc/dbCore.dbd index a2ce45806..067145a01 100644 --- a/src/ioc/misc/dbCore.dbd +++ b/src/ioc/misc/dbCore.dbd @@ -22,3 +22,6 @@ variable(callbackParallelThreadsDefault,int) # Real-time operation variable(dbThreadRealtimeLock,int) + +# RSRV and dbCa (all local ca contexts) +variable(caLimitArray, int) diff --git a/src/ioc/rsrv/caservertask.c b/src/ioc/rsrv/caservertask.c index c890a8e16..53f4a32d9 100644 --- a/src/ioc/rsrv/caservertask.c +++ b/src/ioc/rsrv/caservertask.c @@ -33,6 +33,7 @@ #include "osiSock.h" #include "taskwd.h" #include "cantProceed.h" +#include "epicsExport.h" #define epicsExportSharedSymbols #include "dbChannel.h" @@ -50,6 +51,7 @@ epicsThreadPrivateId rsrvCurrentClient; // defined in cac.cpp extern int caLimitArray; +epicsExportAddress(int, caLimitArray); /* * From 4f1b24458967f453a172ee025623531c4caf23a9 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 20 Apr 2017 09:54:05 -0400 Subject: [PATCH 8/9] ca: fix export caLimitArray on win32 --- src/ca/client/cac.cpp | 3 +++ src/ioc/rsrv/caservertask.c | 9 ++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/ca/client/cac.cpp b/src/ca/client/cac.cpp index d13b5766c..c174b8992 100644 --- a/src/ca/client/cac.cpp +++ b/src/ca/client/cac.cpp @@ -32,6 +32,7 @@ #include "envDefs.h" #include "locationException.h" #include "errlog.h" +#include "epicsExport.h" #define epicsExportSharedSymbols #include "addrList.h" @@ -57,7 +58,9 @@ static const char pVersionCAC[] = // when set, respect EPICS_CA_MAX_ARRAY_BYTES // when clear, ignore it extern "C" { +epicsShareExtern int caLimitArray; int caLimitArray; +epicsExportAddress(int, caLimitArray); } // TCP response dispatch table diff --git a/src/ioc/rsrv/caservertask.c b/src/ioc/rsrv/caservertask.c index 53f4a32d9..3766d421d 100644 --- a/src/ioc/rsrv/caservertask.c +++ b/src/ioc/rsrv/caservertask.c @@ -33,6 +33,10 @@ #include "osiSock.h" #include "taskwd.h" #include "cantProceed.h" + +// defined in cac.cpp +epicsShareExtern int caLimitArray; + #include "epicsExport.h" #define epicsExportSharedSymbols @@ -48,11 +52,6 @@ epicsThreadPrivateId rsrvCurrentClient; -// defined in cac.cpp -extern int caLimitArray; - -epicsExportAddress(int, caLimitArray); - /* * * req_server() From 9fd8eec2e25fb4b035711689e1b6fc2a86ab35e1 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 2 May 2017 19:31:21 -0400 Subject: [PATCH 9/9] replace caLimitArray with EPICS_CA_AUTO_MAX_ARRAY_BYTES --- configure/CONFIG_ENV | 1 + src/ca/client/cac.cpp | 12 ++++-------- src/ioc/misc/dbCore.dbd | 3 --- src/ioc/rsrv/caservertask.c | 8 +++++--- src/libCom/env/envDefs.h | 1 + 5 files changed, 11 insertions(+), 14 deletions(-) diff --git a/configure/CONFIG_ENV b/configure/CONFIG_ENV index 173dceaca..22ace0090 100644 --- a/configure/CONFIG_ENV +++ b/configure/CONFIG_ENV @@ -35,6 +35,7 @@ EPICS_CA_CONN_TMO=30.0 EPICS_CA_REPEATER_PORT=5065 EPICS_CA_SERVER_PORT=5064 EPICS_CA_MAX_ARRAY_BYTES=16384 +EPICS_CA_AUTO_MAX_ARRAY_BYTES=NO EPICS_CA_BEACON_PERIOD=15.0 EPICS_CA_MAX_SEARCH_PERIOD=300.0 EPICS_CAS_BEACON_PERIOD= diff --git a/src/ca/client/cac.cpp b/src/ca/client/cac.cpp index c174b8992..f1d7f0903 100644 --- a/src/ca/client/cac.cpp +++ b/src/ca/client/cac.cpp @@ -55,14 +55,6 @@ static const char pVersionCAC[] = "@(#) " EPICS_VERSION_STRING ", CA Client Library " __DATE__; -// when set, respect EPICS_CA_MAX_ARRAY_BYTES -// when clear, ignore it -extern "C" { -epicsShareExtern int caLimitArray; -int caLimitArray; -epicsExportAddress(int, caLimitArray); -} - // TCP response dispatch table const cac::pProtoStubTCP cac::tcpJumpTableCAC [] = { @@ -227,6 +219,10 @@ cac::cac ( throw std::bad_alloc (); } + int caLimitArray; + if(envGetBoolConfigParam(&EPICS_CA_AUTO_MAX_ARRAY_BYTES, &caLimitArray)) + caLimitArray = 0; + if(caLimitArray) { freeListInitPvt ( &this->tcpLargeRecvBufFreeList, this->maxRecvBytesTCP, 1 ); if ( ! this->tcpLargeRecvBufFreeList ) { diff --git a/src/ioc/misc/dbCore.dbd b/src/ioc/misc/dbCore.dbd index 067145a01..a2ce45806 100644 --- a/src/ioc/misc/dbCore.dbd +++ b/src/ioc/misc/dbCore.dbd @@ -22,6 +22,3 @@ variable(callbackParallelThreadsDefault,int) # Real-time operation variable(dbThreadRealtimeLock,int) - -# RSRV and dbCa (all local ca contexts) -variable(caLimitArray, int) diff --git a/src/ioc/rsrv/caservertask.c b/src/ioc/rsrv/caservertask.c index 3766d421d..0ca74c5b5 100644 --- a/src/ioc/rsrv/caservertask.c +++ b/src/ioc/rsrv/caservertask.c @@ -34,9 +34,6 @@ #include "taskwd.h" #include "cantProceed.h" -// defined in cac.cpp -epicsShareExtern int caLimitArray; - #include "epicsExport.h" #define epicsExportSharedSymbols @@ -472,6 +469,7 @@ int rsrv_init (void) long maxBytesAsALong; long status; SOCKET *socks; + int caLimitArray; clientQlock = epicsMutexMustCreate(); @@ -530,6 +528,10 @@ int rsrv_init (void) rsrvSizeofLargeBufTCP = maxBytes; } } + + if(envGetBoolConfigParam(&EPICS_CA_AUTO_MAX_ARRAY_BYTES, &caLimitArray)) + caLimitArray = 0; + if (caLimitArray) freeListInitPvt ( &rsrvLargeBufFreeListTCP, rsrvSizeofLargeBufTCP, 1 ); else diff --git a/src/libCom/env/envDefs.h b/src/libCom/env/envDefs.h index 536e63635..0c9002d71 100644 --- a/src/libCom/env/envDefs.h +++ b/src/libCom/env/envDefs.h @@ -48,6 +48,7 @@ epicsShareExtern const ENV_PARAM EPICS_CA_AUTO_ADDR_LIST; epicsShareExtern const ENV_PARAM EPICS_CA_REPEATER_PORT; epicsShareExtern const ENV_PARAM EPICS_CA_SERVER_PORT; epicsShareExtern const ENV_PARAM EPICS_CA_MAX_ARRAY_BYTES; +epicsShareExtern const ENV_PARAM EPICS_CA_AUTO_MAX_ARRAY_BYTES; epicsShareExtern const ENV_PARAM EPICS_CA_MAX_SEARCH_PERIOD; epicsShareExtern const ENV_PARAM EPICS_CA_NAME_SERVERS; epicsShareExtern const ENV_PARAM EPICS_CAS_INTF_ADDR_LIST;