@@ -723,9 +723,13 @@ static void thread_free(struct thread_master *master, struct thread *thread)
723723 XFREE (MTYPE_THREAD , thread );
724724}
725725
726- static int fd_poll (struct thread_master * m , struct pollfd * pfds , nfds_t pfdsize ,
727- nfds_t count , const struct timeval * timer_wait )
726+ static int fd_poll (struct thread_master * m , const struct timeval * timer_wait ,
727+ bool * eintr_p )
728728{
729+ sigset_t origsigs ;
730+ unsigned char trash [64 ];
731+ nfds_t count = m -> handler .copycount ;
732+
729733 /*
730734 * If timer_wait is null here, that means poll() should block
731735 * indefinitely, unless the thread_master has overridden it by setting
@@ -756,15 +760,58 @@ static int fd_poll(struct thread_master *m, struct pollfd *pfds, nfds_t pfdsize,
756760 rcu_assert_read_unlocked ();
757761
758762 /* add poll pipe poker */
759- assert (count + 1 < pfdsize );
760- pfds [count ].fd = m -> io_pipe [0 ];
761- pfds [count ].events = POLLIN ;
762- pfds [count ].revents = 0x00 ;
763+ assert (count + 1 < m -> handler .pfdsize );
764+ m -> handler .copy [count ].fd = m -> io_pipe [0 ];
765+ m -> handler .copy [count ].events = POLLIN ;
766+ m -> handler .copy [count ].revents = 0x00 ;
767+
768+ /* We need to deal with a signal-handling race here: we
769+ * don't want to miss a crucial signal, such as SIGTERM or SIGINT,
770+ * that may arrive just before we enter poll(). We will block the
771+ * key signals, then check whether any have arrived - if so, we return
772+ * before calling poll(). If not, we'll re-enable the signals
773+ * in the ppoll() call.
774+ */
763775
764- num = poll (pfds , count + 1 , timeout );
776+ sigemptyset (& origsigs );
777+ if (m -> handle_signals ) {
778+ /* Main pthread that handles the app signals */
779+ if (frr_sigevent_check (& origsigs )) {
780+ /* Signal to process - restore signal mask and return */
781+ pthread_sigmask (SIG_SETMASK , & origsigs , NULL );
782+ num = -1 ;
783+ * eintr_p = true;
784+ goto done ;
785+ }
786+ } else {
787+ /* Don't make any changes for the non-main pthreads */
788+ pthread_sigmask (SIG_SETMASK , NULL , & origsigs );
789+ }
765790
766- unsigned char trash [64 ];
767- if (num > 0 && pfds [count ].revents != 0 && num -- )
791+ #if defined(HAVE_PPOLL )
792+ struct timespec ts , * tsp ;
793+
794+ if (timeout >= 0 ) {
795+ ts .tv_sec = timeout / 1000 ;
796+ ts .tv_nsec = (timeout % 1000 ) * 1000000 ;
797+ tsp = & ts ;
798+ } else
799+ tsp = NULL ;
800+
801+ num = ppoll (m -> handler .copy , count + 1 , tsp , & origsigs );
802+ pthread_sigmask (SIG_SETMASK , & origsigs , NULL );
803+ #else
804+ /* Not ideal - there is a race after we restore the signal mask */
805+ pthread_sigmask (SIG_SETMASK , & origsigs , NULL );
806+ num = poll (m -> handler .copy , count + 1 , timeout );
807+ #endif
808+
809+ done :
810+
811+ if (num < 0 && errno == EINTR )
812+ * eintr_p = true;
813+
814+ if (num > 0 && m -> handler .copy [count ].revents != 0 && num -- )
768815 while (read (m -> io_pipe [0 ], & trash , sizeof (trash )) > 0 )
769816 ;
770817
@@ -1391,7 +1438,7 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch)
13911438 struct timeval zerotime = {0 , 0 };
13921439 struct timeval tv ;
13931440 struct timeval * tw = NULL ;
1394-
1441+ bool eintr_p = false;
13951442 int num = 0 ;
13961443
13971444 do {
@@ -1463,14 +1510,14 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch)
14631510
14641511 pthread_mutex_unlock (& m -> mtx );
14651512 {
1466- num = fd_poll ( m , m -> handler . copy , m -> handler . pfdsize ,
1467- m -> handler . copycount , tw );
1513+ eintr_p = false;
1514+ num = fd_poll ( m , tw , & eintr_p );
14681515 }
14691516 pthread_mutex_lock (& m -> mtx );
14701517
14711518 /* Handle any errors received in poll() */
14721519 if (num < 0 ) {
1473- if (errno == EINTR ) {
1520+ if (eintr_p ) {
14741521 pthread_mutex_unlock (& m -> mtx );
14751522 /* loop around to signal handler */
14761523 continue ;
@@ -1656,3 +1703,49 @@ void funcname_thread_execute(struct thread_master *m,
16561703 /* Give back or free thread. */
16571704 thread_add_unuse (m , thread );
16581705}
1706+
1707+ /* Debug signal mask - if 'sigs' is NULL, use current effective mask. */
1708+ void debug_signals (const sigset_t * sigs )
1709+ {
1710+ int i , found ;
1711+ sigset_t tmpsigs ;
1712+ char buf [300 ];
1713+
1714+ /*
1715+ * We're only looking at the non-realtime signals here, so we need
1716+ * some limit value. Platform differences mean at some point we just
1717+ * need to pick a reasonable value.
1718+ */
1719+ #if defined SIGRTMIN
1720+ # define LAST_SIGNAL SIGRTMIN
1721+ #else
1722+ # define LAST_SIGNAL 32
1723+ #endif
1724+
1725+
1726+ if (sigs == NULL ) {
1727+ sigemptyset (& tmpsigs );
1728+ pthread_sigmask (SIG_BLOCK , NULL , & tmpsigs );
1729+ sigs = & tmpsigs ;
1730+ }
1731+
1732+ found = 0 ;
1733+ buf [0 ] = '\0' ;
1734+
1735+ for (i = 0 ; i < LAST_SIGNAL ; i ++ ) {
1736+ char tmp [20 ];
1737+
1738+ if (sigismember (sigs , i ) > 0 ) {
1739+ if (found > 0 )
1740+ strlcat (buf , "," , sizeof (buf ));
1741+ snprintf (tmp , sizeof (tmp ), "%d" , i );
1742+ strlcat (buf , tmp , sizeof (buf ));
1743+ found ++ ;
1744+ }
1745+ }
1746+
1747+ if (found == 0 )
1748+ snprintf (buf , sizeof (buf ), "<none>" );
1749+
1750+ zlog_debug ("%s: %s" , __func__ , buf );
1751+ }
0 commit comments