Merge ~info-martin-konrad/epics-base:fix-log-issues into ~epics-core/epics-base/+git/epics-base:3.15

Proposed by Martin Konrad
Status: Merged
Approved by: Andrew Johnson
Approved revision: e6914f3b8089a417c9efc31940906854be182e6b
Merged at revision: 9df39475cd70ac8449cbc4406c08766fc8d9c0cc
Proposed branch: ~info-martin-konrad/epics-base:fix-log-issues
Merge into: ~epics-core/epics-base/+git/epics-base:3.15
Diff against target: 708 lines (+238/-153)
11 files modified
src/ioc/misc/dbCore.dbd (+3/-0)
src/libCom/log/iocLog.c (+25/-0)
src/libCom/log/logClient.c (+103/-152)
src/libCom/log/logClient.h (+0/-1)
src/libCom/osi/Makefile (+1/-0)
src/libCom/osi/os/Darwin/osdSockUnsentCount.c (+19/-0)
src/libCom/osi/os/Linux/osdSockUnsentCount.c (+19/-0)
src/libCom/osi/os/WIN32/osdSockUnsentCount.c (+26/-0)
src/libCom/osi/os/default/osdSockUnsentCount.c (+15/-0)
src/libCom/osi/os/iOS/osdSockUnsentCount.c (+19/-0)
src/libCom/osi/osiSock.h (+8/-0)
Reviewer Review Type Date Requested Status
Andrew Johnson Approve
mdavidsaver Approve
Review via email: mp+375509@code.launchpad.net

Description of the change

Fix lp:1841608 + some other logging issues (cherry-picked from 7.0 branch).

To post a comment you must log in.
Revision history for this message
mdavidsaver (mdavidsaver) wrote :
Revision history for this message
mdavidsaver (mdavidsaver) wrote :

appveyor test build fails, looks like a missing header. I recall seeing this before, so maybe a missing patch.

https://ci.appveyor.com/project/mdavidsaver/epics-base/builds/30809445/job/g7ql4ckj825c4sqm

Revision history for this message
Freddie Akeroyd (freddie-akeroyd) wrote :

I think the header is there, two possibilities:

The function wasn't available in original W10 so may need to check windows DDK version too i.e. add

#if NTDDI_VERSION >= NTDDI_WIN10_RS2

to the other macro checks.

The failed build is also an old Visual Studio, maybe the option isn't enabled in the MS header for that old a VC? If so then there would need to be a check on the value of the _MSC_VER macro too.

Revision history for this message
Freddie Akeroyd (freddie-akeroyd) wrote :

Or maybe just

#ifdef SIO_TCP_INFO

which might cover MinGW too

Revision history for this message
Andrew Johnson (anj) wrote :

My MinGW cross-build fails on RHEL-7.6, gcc version 4.9.3 20150626 (Fedora MinGW 4.9.3-1.el7):

../osi/os/WIN32/osdSockUnsentCount.c: In function 'epicsSocketUnsentCount':
../osi/os/WIN32/osdSockUnsentCount.c:19:5: error: unknown type name 'TCP_INFO_v0'
     TCP_INFO_v0 tcpInfo;
     ^
../osi/os/WIN32/osdSockUnsentCount.c:21:34: error: 'SIO_TCP_INFO' undeclared (first use in this function)
     if ((status = WSAIoctl(sock, SIO_TCP_INFO, &infoVersion, sizeof(infoVersion),
                                  ^
../osi/os/WIN32/osdSockUnsentCount.c:21:34: note: each undeclared identifier is reported only once for each function it appears in
../osi/os/WIN32/osdSockUnsentCount.c:23:23: error: request for member 'BytesInFlight' in something not a structure or union
         return tcpInfo.BytesInFlight;
                       ^
../osi/os/WIN32/osdSockUnsentCount.c:20:9: warning: variable 'status' set but not used [-Wunused-but-set-variable]
     int status;
         ^

review: Needs Fixing
Revision history for this message
Freddie Akeroyd (freddie-akeroyd) wrote :

I guess it gets compiled on MinGW as neither macro is defined and 0 >= 0 It may be simplest to use

#if defined(_WIN32) && defined(SIO_TCP_INFO)

Revision history for this message
mdavidsaver (mdavidsaver) wrote :

Sorry for the vague comment. It was 10 min. before I left for the airport. I think it will be sufficient to pick 5e6226e595975753f3f7a256982c0d77f6643394 as well. Please do a CI test run travis+appveyor to confirm.

Revision history for this message
Martin Konrad (info-martin-konrad) wrote :

Thanks Michael for the hint, I added this commit to my branch.

Revision history for this message
Martin Konrad (info-martin-konrad) wrote :

I need some help with AppVeyor. My builds keep failing due to some CI issue: https://ci.appveyor.com/project/MartinKonrad/epics-base-github/build/job/iotr6sf955irn1gh I guess something must be wrong with my AppVeyor configuration.

Revision history for this message
mdavidsaver (mdavidsaver) wrote :

Have you somehow changed the default image? It seems to be 2019, however the assumed default is 2015 (the default default).

Revision history for this message
Martin Konrad (info-martin-konrad) wrote :

AppVeyor build succeeded: https://ci.appveyor.com/project/MartinKonrad/epics-base/builds/32153795 Ready for final review.

Revision history for this message
mdavidsaver (mdavidsaver) wrote :

That's enough for me.

review: Approve
Revision history for this message
Andrew Johnson (anj) wrote :

Merging.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/src/ioc/misc/dbCore.dbd b/src/ioc/misc/dbCore.dbd
index 9d5ae94..898bb59 100644
--- a/src/ioc/misc/dbCore.dbd
+++ b/src/ioc/misc/dbCore.dbd
@@ -25,3 +25,6 @@ variable(callbackParallelThreadsDefault,int)
2525
26# Real-time operation26# Real-time operation
27variable(dbThreadRealtimeLock,int)27variable(dbThreadRealtimeLock,int)
28
29# show logClient network activity
30variable(logClientDebug,int)
diff --git a/src/libCom/log/iocLog.c b/src/libCom/log/iocLog.c
index e62da20..ba78041 100644
--- a/src/libCom/log/iocLog.c
+++ b/src/libCom/log/iocLog.c
@@ -18,8 +18,10 @@
1818
19#define epicsExportSharedSymbols19#define epicsExportSharedSymbols
20#include "envDefs.h"20#include "envDefs.h"
21#include "errlog.h"
21#include "logClient.h"22#include "logClient.h"
22#include "iocLog.h"23#include "iocLog.h"
24#include "epicsExit.h"
2325
24int iocLogDisable = 0;26int iocLogDisable = 0;
2527
@@ -75,6 +77,24 @@ void epicsShareAPI epicsShareAPI iocLogFlush (void)
75}77}
7678
77/*79/*
80 * logClientSendMessage ()
81 */
82static void logClientSendMessage ( logClientId id, const char * message )
83{
84 if ( !iocLogDisable ) {
85 logClientSend (id, message);
86 }
87}
88
89/*
90 * iocLogClientDestroy()
91 */
92static void iocLogClientDestroy (logClientId id)
93{
94 errlogRemoveListeners (logClientSendMessage, id);
95}
96
97/*
78 * iocLogClientInit()98 * iocLogClientInit()
79 */99 */
80static logClientId iocLogClientInit (void)100static logClientId iocLogClientInit (void)
@@ -89,6 +109,10 @@ static logClientId iocLogClientInit (void)
89 return NULL;109 return NULL;
90 }110 }
91 id = logClientCreate (addr, port);111 id = logClientCreate (addr, port);
112 if (id != NULL) {
113 errlogAddListener (logClientSendMessage, id);
114 epicsAtExit (iocLogClientDestroy, id);
115 }
92 return id;116 return id;
93}117}
94118
@@ -135,3 +159,4 @@ logClientId epicsShareAPI logClientInit (void)
135{159{
136 return iocLogClientInit ();160 return iocLogClientInit ();
137}161}
162
diff --git a/src/libCom/log/logClient.c b/src/libCom/log/logClient.c
index 99ee671..9a09ef7 100644
--- a/src/libCom/log/logClient.c
+++ b/src/libCom/log/logClient.c
@@ -21,11 +21,11 @@
21#include <string.h>21#include <string.h>
22#include <stdio.h>22#include <stdio.h>
2323
24#define EPICS_PRIVATE_API
24#define epicsExportSharedSymbols25#define epicsExportSharedSymbols
25#include "dbDefs.h"26#include "dbDefs.h"
26#include "epicsEvent.h"27#include "epicsEvent.h"
27#include "iocLog.h"28#include "iocLog.h"
28#include "errlog.h"
29#include "epicsMutex.h"29#include "epicsMutex.h"
30#include "epicsThread.h"30#include "epicsThread.h"
31#include "epicsTime.h"31#include "epicsTime.h"
@@ -33,9 +33,13 @@
33#include "epicsAssert.h"33#include "epicsAssert.h"
34#include "epicsExit.h"34#include "epicsExit.h"
35#include "epicsSignal.h"35#include "epicsSignal.h"
36#include "epicsExport.h"
3637
37#include "logClient.h"38#include "logClient.h"
3839
40int logClientDebug = 0;
41epicsExportAddress (int, logClientDebug);
42
39typedef struct {43typedef struct {
40 char msgBuf[0x4000];44 char msgBuf[0x4000];
41 struct sockaddr_in addr;45 struct sockaddr_in addr;
@@ -44,8 +48,10 @@ typedef struct {
44 SOCKET sock;48 SOCKET sock;
45 epicsThreadId restartThreadId;49 epicsThreadId restartThreadId;
46 epicsEventId stateChangeNotify;50 epicsEventId stateChangeNotify;
51 epicsEventId shutdownNotify;
47 unsigned connectCount;52 unsigned connectCount;
48 unsigned nextMsgIndex;53 unsigned nextMsgIndex;
54 unsigned backlog;
49 unsigned connected;55 unsigned connected;
50 unsigned shutdown;56 unsigned shutdown;
51 unsigned shutdownConfirm;57 unsigned shutdownConfirm;
@@ -53,7 +59,6 @@ typedef struct {
53} logClient;59} logClient;
5460
55static const double LOG_RESTART_DELAY = 5.0; /* sec */61static const double LOG_RESTART_DELAY = 5.0; /* sec */
56static const double LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT = 5.0; /* sec */
57static const double LOG_SERVER_SHUTDOWN_TIMEOUT = 30.0; /* sec */62static const double LOG_SERVER_SHUTDOWN_TIMEOUT = 30.0; /* sec */
5863
59/*64/*
@@ -66,10 +71,10 @@ static char* logClientPrefix = NULL;
66 */71 */
67static void logClientClose ( logClient *pClient )72static void logClientClose ( logClient *pClient )
68{73{
69# ifdef DEBUG74 if (logClientDebug) {
70 fprintf (stderr, "log client: lingering for connection close...");75 fprintf (stderr, "log client: lingering for connection close...");
71 fflush (stderr);76 fflush (stderr);
72# endif77 }
7378
74 /*79 /*
75 * mutex on80 * mutex on
@@ -84,8 +89,6 @@ static void logClientClose ( logClient *pClient )
84 pClient->sock = INVALID_SOCKET;89 pClient->sock = INVALID_SOCKET;
85 }90 }
8691
87 pClient->nextMsgIndex = 0u;
88 memset ( pClient->msgBuf, '\0', sizeof ( pClient->msgBuf ) );
89 pClient->connected = 0u;92 pClient->connected = 0u;
9093
91 /*94 /*
@@ -93,9 +96,8 @@ static void logClientClose ( logClient *pClient )
93 */96 */
94 epicsMutexUnlock (pClient->mutex);97 epicsMutexUnlock (pClient->mutex);
9598
96# ifdef DEBUG99 if (logClientDebug)
97 fprintf (stderr, "done\n");100 fprintf (stderr, "done\n");
98# endif
99}101}
100102
101/*103/*
@@ -113,6 +115,7 @@ static void logClientDestroy (logClientId id)
113 epicsMutexMustLock ( pClient->mutex );115 epicsMutexMustLock ( pClient->mutex );
114 pClient->shutdown = 1u;116 pClient->shutdown = 1u;
115 epicsMutexUnlock ( pClient->mutex );117 epicsMutexUnlock ( pClient->mutex );
118 epicsEventSignal ( pClient->shutdownNotify );
116119
117 /* unblock log client thread blocking in send() or connect() */120 /* unblock log client thread blocking in send() or connect() */
118 interruptInfo =121 interruptInfo =
@@ -154,13 +157,11 @@ static void logClientDestroy (logClientId id)
154 return;157 return;
155 }158 }
156159
157 errlogRemoveListeners ( logClientSendMessage, (void *) pClient );
158
159 logClientClose ( pClient );160 logClientClose ( pClient );
160161
161 epicsMutexDestroy ( pClient->mutex );162 epicsMutexDestroy ( pClient->mutex );
162
163 epicsEventDestroy ( pClient->stateChangeNotify );163 epicsEventDestroy ( pClient->stateChangeNotify );
164 epicsEventDestroy ( pClient->shutdownNotify );
164165
165 free ( pClient );166 free ( pClient );
166}167}
@@ -176,61 +177,26 @@ static void sendMessageChunk(logClient * pClient, const char * message) {
176 unsigned msgBufBytesLeft = 177 unsigned msgBufBytesLeft =
177 sizeof ( pClient->msgBuf ) - pClient->nextMsgIndex;178 sizeof ( pClient->msgBuf ) - pClient->nextMsgIndex;
178179
179 if ( strSize > msgBufBytesLeft ) {180 if ( msgBufBytesLeft < strSize && pClient->nextMsgIndex != 0u && pClient->connected)
180 int status;181 {
181182 /* buffer is full, thus flush it */
182 if ( ! pClient->connected ) {183 logClientFlush ( pClient );
183 break;184 msgBufBytesLeft = sizeof ( pClient->msgBuf ) - pClient->nextMsgIndex;
184 }
185
186 if ( msgBufBytesLeft > 0u ) {
187 memcpy ( & pClient->msgBuf[pClient->nextMsgIndex],
188 message, msgBufBytesLeft );
189 pClient->nextMsgIndex += msgBufBytesLeft;
190 strSize -= msgBufBytesLeft;
191 message += msgBufBytesLeft;
192 }
193
194 status = send ( pClient->sock, pClient->msgBuf,
195 pClient->nextMsgIndex, 0 );
196 if ( status > 0 ) {
197 unsigned nSent = (unsigned) status;
198 if ( nSent < pClient->nextMsgIndex ) {
199 unsigned newNextMsgIndex = pClient->nextMsgIndex - nSent;
200 memmove ( pClient->msgBuf, & pClient->msgBuf[nSent],
201 newNextMsgIndex );
202 pClient->nextMsgIndex = newNextMsgIndex;
203 }
204 else {
205 pClient->nextMsgIndex = 0u;
206 }
207 }
208 else {
209 if ( ! pClient->shutdown ) {
210 char sockErrBuf[64];
211 if ( status ) {
212 epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
213 }
214 else {
215 strcpy ( sockErrBuf, "server initiated disconnect" );
216 }
217 fprintf ( stderr, "log client: lost contact with log server at \"%s\" because \"%s\"\n",
218 pClient->name, sockErrBuf );
219 }
220 logClientClose ( pClient );
221 break;
222 }
223 }185 }
224 else {186 if ( msgBufBytesLeft == 0u ) {
225 memcpy ( & pClient->msgBuf[pClient->nextMsgIndex],187 fprintf ( stderr, "log client: messages to \"%s\" are lost\n",
226 message, strSize );188 pClient->name );
227 pClient->nextMsgIndex += strSize;
228 break;189 break;
229 }190 }
191 if ( msgBufBytesLeft > strSize) msgBufBytesLeft = strSize;
192 memcpy ( & pClient->msgBuf[pClient->nextMsgIndex],
193 message, msgBufBytesLeft );
194 pClient->nextMsgIndex += msgBufBytesLeft;
195 strSize -= msgBufBytesLeft;
196 message += msgBufBytesLeft;
230 }197 }
231}198}
232199
233
234/* 200/*
235 * logClientSend ()201 * logClientSend ()
236 */202 */
@@ -255,43 +221,54 @@ void epicsShareAPI logClientSend ( logClientId id, const char * message )
255221
256void epicsShareAPI logClientFlush ( logClientId id )222void epicsShareAPI logClientFlush ( logClientId id )
257{223{
224 unsigned nSent;
225 int status = 0;
226
258 logClient * pClient = ( logClient * ) id;227 logClient * pClient = ( logClient * ) id;
259228
260 if ( ! pClient ) {229 if ( ! pClient || ! pClient->connected ) {
261 return;230 return;
262 }231 }
263232
264 epicsMutexMustLock ( pClient->mutex );233 epicsMutexMustLock ( pClient->mutex );
265234
266 while ( pClient->nextMsgIndex && pClient->connected ) {235 nSent = pClient->backlog;
267 int status = send ( pClient->sock, pClient->msgBuf, 236 while ( nSent < pClient->nextMsgIndex && pClient->connected ) {
268 pClient->nextMsgIndex, 0 );237 status = send ( pClient->sock, pClient->msgBuf + nSent,
269 if ( status > 0 ) {238 pClient->nextMsgIndex - nSent, 0 );
270 unsigned nSent = (unsigned) status;239 if ( status < 0 ) break;
271 if ( nSent < pClient->nextMsgIndex ) {240 nSent += status;
272 unsigned newNextMsgIndex = pClient->nextMsgIndex - nSent;241 }
273 memmove ( pClient->msgBuf, & pClient->msgBuf[nSent], 242
274 newNextMsgIndex );243 if ( pClient->backlog > 0 && status >= 0 )
275 pClient->nextMsgIndex = newNextMsgIndex;244 {
276 }245 /* On Linux send 0 bytes can detect EPIPE */
277 else {246 /* NOOP on Windows, fails on vxWorks */
278 pClient->nextMsgIndex = 0u;247 errno = 0;
279 }248 status = send ( pClient->sock, NULL, 0, 0 );
249 if (!(errno == ECONNRESET || errno == EPIPE)) status = 0;
250 }
251
252 if ( status < 0 ) {
253 if ( ! pClient->shutdown ) {
254 char sockErrBuf[128];
255 epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
256 fprintf ( stderr, "log client: lost contact with log server at \"%s\" because \"%s\"\n",
257 pClient->name, sockErrBuf );
280 }258 }
281 else {259 pClient->backlog = 0;
282 if ( ! pClient->shutdown ) {260 logClientClose ( pClient );
283 char sockErrBuf[64];261 }
284 if ( status ) {262 else if ( nSent > 0 && pClient->nextMsgIndex > 0 ) {
285 epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );263 int backlog = epicsSocketUnsentCount ( pClient->sock );
286 }264 if (backlog >= 0) {
287 else {265 pClient->backlog = backlog;
288 strcpy ( sockErrBuf, "server initiated disconnect" );266 nSent -= backlog;
289 }267 }
290 fprintf ( stderr, "log client: lost contact with log server at \"%s\" because \"%s\"\n", 268 pClient->nextMsgIndex -= nSent;
291 pClient->name, sockErrBuf );269 if ( nSent > 0 && pClient->nextMsgIndex > 0 ) {
292 }270 memmove ( pClient->msgBuf, & pClient->msgBuf[nSent],
293 logClientClose ( pClient );271 pClient->nextMsgIndex );
294 break;
295 }272 }
296 }273 }
297 epicsMutexUnlock ( pClient->mutex );274 epicsMutexUnlock ( pClient->mutex );
@@ -302,10 +279,10 @@ void epicsShareAPI logClientFlush ( logClientId id )
302 */279 */
303static void logClientMakeSock (logClient *pClient)280static void logClientMakeSock (logClient *pClient)
304{281{
305 282 if (logClientDebug) {
306# ifdef DEBUG
307 fprintf (stderr, "log client: creating socket...");283 fprintf (stderr, "log client: creating socket...");
308# endif284 fflush (stderr);
285 }
309286
310 epicsMutexMustLock (pClient->mutex);287 epicsMutexMustLock (pClient->mutex);
311 288
@@ -314,7 +291,7 @@ static void logClientMakeSock (logClient *pClient)
314 */291 */
315 pClient->sock = epicsSocketCreate ( AF_INET, SOCK_STREAM, 0 );292 pClient->sock = epicsSocketCreate ( AF_INET, SOCK_STREAM, 0 );
316 if ( pClient->sock == INVALID_SOCKET ) {293 if ( pClient->sock == INVALID_SOCKET ) {
317 char sockErrBuf[64];294 char sockErrBuf[128];
318 epicsSocketConvertErrnoToString ( 295 epicsSocketConvertErrnoToString (
319 sockErrBuf, sizeof ( sockErrBuf ) );296 sockErrBuf, sizeof ( sockErrBuf ) );
320 fprintf ( stderr, "log client: no socket error %s\n", 297 fprintf ( stderr, "log client: no socket error %s\n",
@@ -323,10 +300,8 @@ static void logClientMakeSock (logClient *pClient)
323 300
324 epicsMutexUnlock (pClient->mutex);301 epicsMutexUnlock (pClient->mutex);
325302
326# ifdef DEBUG303 if (logClientDebug)
327 fprintf (stderr, "done\n");304 fprintf (stderr, "done\n");
328# endif
329
330}305}
331306
332/*307/*
@@ -366,7 +341,7 @@ static void logClientConnect (logClient *pClient)
366 }341 }
367 else {342 else {
368 if ( pClient->connFailStatus != errnoCpy && ! pClient->shutdown ) {343 if ( pClient->connFailStatus != errnoCpy && ! pClient->shutdown ) {
369 char sockErrBuf[64];344 char sockErrBuf[128];
370 epicsSocketConvertErrnoToString (345 epicsSocketConvertErrnoToString (
371 sockErrBuf, sizeof ( sockErrBuf ) );346 sockErrBuf, sizeof ( sockErrBuf ) );
372 fprintf (stderr,347 fprintf (stderr,
@@ -392,7 +367,7 @@ static void logClientConnect (logClient *pClient)
392 optval = TRUE;367 optval = TRUE;
393 status = setsockopt (pClient->sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(optval));368 status = setsockopt (pClient->sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(optval));
394 if (status<0) {369 if (status<0) {
395 char sockErrBuf[64];370 char sockErrBuf[128];
396 epicsSocketConvertErrnoToString ( 371 epicsSocketConvertErrnoToString (
397 sockErrBuf, sizeof ( sockErrBuf ) );372 sockErrBuf, sizeof ( sockErrBuf ) );
398 fprintf (stderr, "log client: unable to enable keepalive option because \"%s\"\n", sockErrBuf);373 fprintf (stderr, "log client: unable to enable keepalive option because \"%s\"\n", sockErrBuf);
@@ -404,11 +379,11 @@ static void logClientConnect (logClient *pClient)
404 */379 */
405 status = shutdown (pClient->sock, SHUT_RD);380 status = shutdown (pClient->sock, SHUT_RD);
406 if (status < 0) {381 if (status < 0) {
407 char sockErrBuf[64];382 char sockErrBuf[128];
408 epicsSocketConvertErrnoToString ( 383 epicsSocketConvertErrnoToString (
409 sockErrBuf, sizeof ( sockErrBuf ) );384 sockErrBuf, sizeof ( sockErrBuf ) );
410 fprintf (stderr, "%s:%d shutdown(%d,SHUT_RD) error was \"%s\"\n", 385 fprintf (stderr, "%s:%d shutdown(sock,SHUT_RD) error was \"%s\"\n",
411 __FILE__, __LINE__, pClient->sock, sockErrBuf);386 __FILE__, __LINE__, sockErrBuf);
412 /* not fatal (although it shouldn't happen) */387 /* not fatal (although it shouldn't happen) */
413 }388 }
414389
@@ -425,7 +400,7 @@ static void logClientConnect (logClient *pClient)
425 lingerval.l_linger = 60*5; 400 lingerval.l_linger = 60*5;
426 status = setsockopt (pClient->sock, SOL_SOCKET, SO_LINGER, (char *) &lingerval, sizeof(lingerval));401 status = setsockopt (pClient->sock, SOL_SOCKET, SO_LINGER, (char *) &lingerval, sizeof(lingerval));
427 if (status<0) {402 if (status<0) {
428 char sockErrBuf[64];403 char sockErrBuf[128];
429 epicsSocketConvertErrnoToString ( 404 epicsSocketConvertErrnoToString (
430 sockErrBuf, sizeof ( sockErrBuf ) );405 sockErrBuf, sizeof ( sockErrBuf ) );
431 fprintf (stderr, "log client: unable to set linger options because \"%s\"\n", sockErrBuf);406 fprintf (stderr, "log client: unable to set linger options because \"%s\"\n", sockErrBuf);
@@ -457,14 +432,10 @@ static void logClientRestart ( logClientId id )
457432
458 epicsMutexUnlock ( pClient->mutex );433 epicsMutexUnlock ( pClient->mutex );
459434
460 if ( isConn ) {435 if ( ! isConn ) logClientConnect ( pClient );
461 logClientFlush ( pClient );436 logClientFlush ( pClient );
462 }437
463 else {438 epicsEventWaitWithTimeout ( pClient->shutdownNotify, LOG_RESTART_DELAY);
464 logClientConnect ( pClient );
465 }
466
467 epicsThreadSleep ( LOG_RESTART_DELAY );
468439
469 epicsMutexMustLock ( pClient->mutex );440 epicsMutexMustLock ( pClient->mutex );
470 }441 }
@@ -480,9 +451,7 @@ static void logClientRestart ( logClientId id )
480logClientId epicsShareAPI logClientCreate (451logClientId epicsShareAPI logClientCreate (
481 struct in_addr server_addr, unsigned short server_port)452 struct in_addr server_addr, unsigned short server_port)
482{453{
483 epicsTimeStamp begin, current;
484 logClient *pClient;454 logClient *pClient;
485 double diff;
486455
487 pClient = calloc (1, sizeof (*pClient));456 pClient = calloc (1, sizeof (*pClient));
488 if (pClient==NULL) {457 if (pClient==NULL) {
@@ -507,14 +476,22 @@ logClientId epicsShareAPI logClientCreate (
507 pClient->shutdownConfirm = 0;476 pClient->shutdownConfirm = 0;
508477
509 epicsAtExit (logClientDestroy, (void*) pClient);478 epicsAtExit (logClientDestroy, (void*) pClient);
510 479
511 pClient->stateChangeNotify = epicsEventCreate (epicsEventEmpty);480 pClient->stateChangeNotify = epicsEventCreate (epicsEventEmpty);
512 if ( ! pClient->stateChangeNotify ) {481 if ( ! pClient->stateChangeNotify ) {
513 epicsMutexDestroy ( pClient->mutex );482 epicsMutexDestroy ( pClient->mutex );
514 free ( pClient );483 free ( pClient );
515 return NULL;484 return NULL;
516 }485 }
517 486
487 pClient->shutdownNotify = epicsEventCreate (epicsEventEmpty);
488 if ( ! pClient->shutdownNotify ) {
489 epicsMutexDestroy ( pClient->mutex );
490 epicsEventDestroy ( pClient->stateChangeNotify );
491 free ( pClient );
492 return NULL;
493 }
494
518 pClient->restartThreadId = epicsThreadCreate (495 pClient->restartThreadId = epicsThreadCreate (
519 "logRestart", epicsThreadPriorityLow, 496 "logRestart", epicsThreadPriorityLow,
520 epicsThreadGetStackSize(epicsThreadStackSmall),497 epicsThreadGetStackSize(epicsThreadStackSmall),
@@ -522,35 +499,12 @@ logClientId epicsShareAPI logClientCreate (
522 if ( pClient->restartThreadId == NULL ) {499 if ( pClient->restartThreadId == NULL ) {
523 epicsMutexDestroy ( pClient->mutex );500 epicsMutexDestroy ( pClient->mutex );
524 epicsEventDestroy ( pClient->stateChangeNotify );501 epicsEventDestroy ( pClient->stateChangeNotify );
502 epicsEventDestroy ( pClient->shutdownNotify );
525 free (pClient);503 free (pClient);
526 fprintf(stderr, "log client: unable to start log client connection watch dog thread\n");504 fprintf(stderr, "log client: unable to start log client connection watch dog thread\n");
527 return NULL;505 return NULL;
528 }506 }
529507
530 /*
531 * attempt to synchronize with circuit connect
532 */
533 epicsTimeGetCurrent ( & begin );
534 epicsMutexMustLock ( pClient->mutex );
535 do {
536 epicsMutexUnlock ( pClient->mutex );
537 epicsEventWaitWithTimeout (
538 pClient->stateChangeNotify,
539 LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT / 10.0 );
540 epicsTimeGetCurrent ( & current );
541 diff = epicsTimeDiffInSeconds ( & current, & begin );
542 epicsMutexMustLock ( pClient->mutex );
543 }
544 while ( ! pClient->connected && diff < LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT );
545 epicsMutexUnlock ( pClient->mutex );
546
547 if ( ! pClient->connected ) {
548 fprintf (stderr, "log client create: timed out synchronizing with circuit connect to \"%s\" after %.1f seconds\n",
549 pClient->name, LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT );
550 }
551
552 errlogAddListener ( logClientSendMessage, (void *) pClient );
553
554 return (void *) pClient;508 return (void *) pClient;
555}509}
556510
@@ -568,24 +522,21 @@ void epicsShareAPI logClientShow (logClientId id, unsigned level)
568 printf ("log client: disconnected from log server at \"%s\"\n", pClient->name);522 printf ("log client: disconnected from log server at \"%s\"\n", pClient->name);
569 }523 }
570524
571 if (level>1) {
572 printf ("log client: sock=%s, connect cycles = %u\n",
573 pClient->sock==INVALID_SOCKET?"INVALID":"OK",
574 pClient->connectCount);
575 }
576
577 if (logClientPrefix) {525 if (logClientPrefix) {
578 printf ("log client: prefix is \"%s\"\n", logClientPrefix);526 printf ("log client: prefix is \"%s\"\n", logClientPrefix);
579 }527 }
580}
581528
582/*529 if (level>0) {
583 * logClientSendMessage (); deprecated530 printf ("log client: sock %s, connect cycles = %u\n",
584 */531 pClient->sock==INVALID_SOCKET?"INVALID":"OK",
585void logClientSendMessage ( logClientId id, const char * message )532 pClient->connectCount);
586{533 }
587 if ( !iocLogDisable ) {534 if (level>1) {
588 logClientSend (id, message);535 printf ("log client: %u bytes in buffer\n", pClient->nextMsgIndex);
536 if (pClient->nextMsgIndex)
537 printf("-------------------------\n"
538 "%.*s-------------------------\n",
539 (int)(pClient->nextMsgIndex), pClient->msgBuf);
589 }540 }
590}541}
591542
diff --git a/src/libCom/log/logClient.h b/src/libCom/log/logClient.h
index 1797bbb..3b3f63a 100644
--- a/src/libCom/log/logClient.h
+++ b/src/libCom/log/logClient.h
@@ -38,7 +38,6 @@ epicsShareFunc void epicsShareAPI iocLogPrefix(const char* prefix);
38/* deprecated interface; retained for backward compatibility */38/* deprecated interface; retained for backward compatibility */
39/* note: implementations are in iocLog.c, not logClient.c */39/* note: implementations are in iocLog.c, not logClient.c */
40epicsShareFunc logClientId epicsShareAPI logClientInit (void);40epicsShareFunc logClientId epicsShareAPI logClientInit (void);
41epicsShareFunc void logClientSendMessage (logClientId id, const char *message);
4241
43#ifdef __cplusplus42#ifdef __cplusplus
44}43}
diff --git a/src/libCom/osi/Makefile b/src/libCom/osi/Makefile
index e05aec3..00685d8 100644
--- a/src/libCom/osi/Makefile
+++ b/src/libCom/osi/Makefile
@@ -86,6 +86,7 @@ endif
8686
87Com_SRCS += osdSock.c87Com_SRCS += osdSock.c
88Com_SRCS += osdSockAddrReuse.cpp88Com_SRCS += osdSockAddrReuse.cpp
89Com_SRCS += osdSockUnsentCount.c
89Com_SRCS += osiSock.c90Com_SRCS += osiSock.c
90Com_SRCS += systemCallIntMech.cpp91Com_SRCS += systemCallIntMech.cpp
91Com_SRCS += epicsSocketConvertErrnoToString.cpp92Com_SRCS += epicsSocketConvertErrnoToString.cpp
diff --git a/src/libCom/osi/os/Darwin/osdSockUnsentCount.c b/src/libCom/osi/os/Darwin/osdSockUnsentCount.c
92new file mode 10064493new file mode 100644
index 0000000..20bd82b
--- /dev/null
+++ b/src/libCom/osi/os/Darwin/osdSockUnsentCount.c
@@ -0,0 +1,19 @@
1/*************************************************************************\
2* EPICS BASE is distributed subject to a Software License Agreement found
3* in file LICENSE that is included with this distribution.
4\*************************************************************************/
5
6#define EPICS_PRIVATE_API
7#include "osiSock.h"
8
9/*
10 * epicsSocketUnsentCount ()
11 * See https://www.unix.com/man-page/osx/2/setsockopt
12 */
13int epicsSocketUnsentCount(SOCKET sock) {
14 int unsent;
15 socklen_t len = sizeof(unsent);
16 if (getsockopt(sock, SOL_SOCKET, SO_NWRITE, &unsent, &len) == 0)
17 return unsent;
18 return -1;
19}
diff --git a/src/libCom/osi/os/Linux/osdSockUnsentCount.c b/src/libCom/osi/os/Linux/osdSockUnsentCount.c
0new file mode 10064420new file mode 100644
index 0000000..3c0a8f9
--- /dev/null
+++ b/src/libCom/osi/os/Linux/osdSockUnsentCount.c
@@ -0,0 +1,19 @@
1/*************************************************************************\
2* EPICS BASE is distributed subject to a Software License Agreement found
3* in file LICENSE that is included with this distribution.
4\*************************************************************************/
5
6#include <linux/sockios.h>
7#define EPICS_PRIVATE_API
8#include "osiSock.h"
9
10/*
11 * epicsSocketUnsentCount ()
12 * See https://linux.die.net/man/7/tcp
13 */
14int epicsSocketUnsentCount(SOCKET sock) {
15 int unsent;
16 if (ioctl(sock, SIOCOUTQ, &unsent) == 0)
17 return unsent;
18 return -1;
19}
diff --git a/src/libCom/osi/os/WIN32/osdSockUnsentCount.c b/src/libCom/osi/os/WIN32/osdSockUnsentCount.c
0new file mode 10064420new file mode 100644
index 0000000..3f4ab3e
--- /dev/null
+++ b/src/libCom/osi/os/WIN32/osdSockUnsentCount.c
@@ -0,0 +1,26 @@
1/*************************************************************************\
2* EPICS BASE is distributed subject to a Software License Agreement found
3* in file LICENSE that is included with this distribution.
4\*************************************************************************/
5
6#define epicsExportSharedSymbols
7#define EPICS_PRIVATE_API
8#include "osiSock.h"
9#include <mstcpip.h>
10
11/*
12 * epicsSocketUnsentCount ()
13 * See https://docs.microsoft.com/en-us/windows/win32/api/mstcpip/ns-mstcpip-tcp_info_v0
14 */
15int epicsSocketUnsentCount(SOCKET sock) {
16#ifdef SIO_TCP_INFO
17/* Windows 10 Version 1703 / Server 2016 */
18 DWORD infoVersion = 0, bytesReturned;
19 TCP_INFO_v0 tcpInfo;
20 int status;
21 if ((status = WSAIoctl(sock, SIO_TCP_INFO, &infoVersion, sizeof(infoVersion),
22 &tcpInfo, sizeof(tcpInfo), &bytesReturned, NULL, NULL)) == 0)
23 return tcpInfo.BytesInFlight;
24#endif
25 return -1;
26}
diff --git a/src/libCom/osi/os/default/osdSockUnsentCount.c b/src/libCom/osi/os/default/osdSockUnsentCount.c
0new file mode 10064427new file mode 100644
index 0000000..ef01e9b
--- /dev/null
+++ b/src/libCom/osi/os/default/osdSockUnsentCount.c
@@ -0,0 +1,15 @@
1/*************************************************************************\
2* EPICS BASE is distributed subject to a Software License Agreement found
3* in file LICENSE that is included with this distribution.
4\*************************************************************************/
5
6#define EPICS_PRIVATE_API
7#include "osiSock.h"
8
9/*
10 * epicsSocketUnsentCount ()
11 */
12int epicsSocketUnsentCount(SOCKET sock) {
13 /* not implemented */
14 return -1;
15}
diff --git a/src/libCom/osi/os/iOS/osdSockUnsentCount.c b/src/libCom/osi/os/iOS/osdSockUnsentCount.c
0new file mode 10064416new file mode 100644
index 0000000..20bd82b
--- /dev/null
+++ b/src/libCom/osi/os/iOS/osdSockUnsentCount.c
@@ -0,0 +1,19 @@
1/*************************************************************************\
2* EPICS BASE is distributed subject to a Software License Agreement found
3* in file LICENSE that is included with this distribution.
4\*************************************************************************/
5
6#define EPICS_PRIVATE_API
7#include "osiSock.h"
8
9/*
10 * epicsSocketUnsentCount ()
11 * See https://www.unix.com/man-page/osx/2/setsockopt
12 */
13int epicsSocketUnsentCount(SOCKET sock) {
14 int unsent;
15 socklen_t len = sizeof(unsent);
16 if (getsockopt(sock, SOL_SOCKET, SO_NWRITE, &unsent, &len) == 0)
17 return unsent;
18 return -1;
19}
diff --git a/src/libCom/osi/osiSock.h b/src/libCom/osi/osiSock.h
index 061619e..6e3b053 100644
--- a/src/libCom/osi/osiSock.h
+++ b/src/libCom/osi/osiSock.h
@@ -52,6 +52,14 @@ enum epicsSocketSystemCallInterruptMechanismQueryInfo {
52epicsShareFunc enum epicsSocketSystemCallInterruptMechanismQueryInfo 52epicsShareFunc enum epicsSocketSystemCallInterruptMechanismQueryInfo
53 epicsSocketSystemCallInterruptMechanismQuery ();53 epicsSocketSystemCallInterruptMechanismQuery ();
5454
55#ifdef EPICS_PRIVATE_API
56/*
57 * Some systems (e.g Linux and Windows 10) allow to check the amount
58 * of unsent data in the output queue.
59 * Returns -1 if the information is not available.
60 */
61epicsShareFunc int epicsSocketUnsentCount(SOCKET sock);
62#endif
5563
56/*64/*
57 * convert socket address to ASCII in this order65 * convert socket address to ASCII in this order

Subscribers

People subscribed via source and target branches