A real time signal is frequently sent as a SIGIO signal instead of its assigned real-time signal number.

Bug #2054817 reported by Thomas L VonDerHaar
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
Raspbian
New
Undecided
Unassigned

Bug Description

   I use real-time signals on several network sockets(accepts and receives.) I recently updated from Stretch to Bullseye via Buster and noticed that Bullseye's and Buster's kernels do not process real-time signals the same as stretch. It appears the kernel will frequently replace the real-time signals with a SIGIO signal. This should only occur when the kernel real-time signal queue is full. These signal are only generated a few at a time in slow intervals of more than a few seconds between socket stream accept/receive event pairs. I have increased the process real-time queue size by 1000 successfully using "setrlimit(RLIMIT_SIGPENDING,&rlim)" with no effect. This increase may only affect queued signals, but the documentation isn't clear and now I'm trying anything to restore the kernels previous ability to properly send these signals. I now have to intercept every SIGIO signal and poll all my sockets to know who caused the signal. Some times the kernel sends the real-time signal properly, and other times it just sends a general SIGIO signal. This defeats the main reason for me using real-time signals(i.e. knowing the source of the signal.)

   Because the code was not changed between OS changes and the code has run almost continuously(except for power fails) since 2020 without a single signal problem I conclude that a kernel bug or restriction must have been introduced.

    Tom

Hardware: RPI 2

uname -a
Linux garage 6.1.54-v7+ #1682 SMP Wed Sep 20 15:16:25 BST 2023 armv7l GNU/Linux

/etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 11 (bullseye)"
NAME="Raspbian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"

My program is over 11,000+ lines of C++ code in 48 files so won't send it, but this routine show the essential signal setup:
---------------------------------------------------------------------------------------

/*********************************Start-set_io_async***************************/
/*This Function sets up a signal call back function '(*call_back)()' to be
  called asynchronously when I/O is available on the file descriptor 'fd'.
  The siganl system is set to restart if possible any system calls that are
  interrupted and to send the signal information data with the call back
  function 'call_back_func()'. (See sigaction() in Linux manuals.) This
  signal is blocked until we return or use the signal masking functions
  to change the signals blocking state. The signal call back function is
  retained until specifically changed(unlike when using 'signal()'.)
  Real Time signals are queued to a MAX depth set by the system. There are
  approximtely 32 RT signals available SIGRTMIN to SIGRTMAX.

 Input:
            wait: 0 => Set I/O mode non-blocking on file descriptor 'fd'.
                    1 => Set I/O mode blocking on file descriptor 'fd'.
       rt_sig_no: Real time signal number to use. If 'rt_sig_no' is
                    less than SIGRTMIM or greater than SIGRTMAX the then
                    signal queue depth reverts to '1' and the signal
                    info structure may or may not apply. Specifically
                    CYGWIN does not seem to offer a 'fcntl()'
                    'F_SETSIG' signal option, but does support signal
                    information at least via 'sigqueue()'.
   Return:
         0 => Success.
        -1 => Failure, global variable "errno" has error code.
*/
int set_io_async(int fd,void (*call_back)(int signum, siginfo_t *siginfo,
                 void *ucontext),int rt_sig_no,u_char wait)
{
int flags;
struct rlimit rlim;
struct sigaction new_signal_handler;
struct sigaction org_signal_handler;

   DBPRINTF(2,"set_io_async(fd=%d,call_back=%ul,rt_sig_no=%d,wait=%d)\n",
            fd,call_back,rt_sig_no,wait);

   {static bool first_time=TRUE;
    if(first_time){
       first_time=FALSE;
    /*Show SIGPOLL real-time signal queue size.*/
    if(getrlimit(RLIMIT_SIGPENDING,&rlim)<0){
       LPRINTF("getrlimit(RLIMIT_SIGPENDING,) failed.\n");
       DBPRINTF(1,"getrlimit(RLIMIT_SIGPENDING,) failed.\n");
    }
    else{
       LPRINTF("Real-time signal queue length limits(RLIM_INFINITY=%u):\n"
               " (soft=%u,hard=%u).\n",RLIM_INFINITY,
               rlim.rlim_cur, /*Soft limit*/
        rlim.rlim_max);/*Hard limit (ceiling for rlim_cur)*/
       DBPRINTF(1,"Real-time signal queue length limits(RLIM_INFINITY=%u)\n:"
                "(rlim type bsize=%d,soft=%u,hard=%u).\n",
         RLIM_INFINITY,
         sizeof(rlim.rlim_cur),
                rlim.rlim_cur, /*Soft limit*/
         rlim.rlim_max);/*Hard limit (ceiling for rlim_cur)*/
    }

#if (NETIO_SIGPENDING_QSZ > 0)
    if((rlim.rlim_max+NETIO_SIGPENDING_QSZ)<rlim.rlim_max)
       rlim.rlim_cur=rlim.rlim_max=RLIM_INFINITY;
    else
       rlim.rlim_cur=(rlim.rlim_max+=NETIO_SIGPENDING_QSZ);

    /*Set new RT signal queue size.*/
    if(setrlimit(RLIMIT_SIGPENDING,&rlim)<0){
      LPRINTF("setrlimit(RLIMIT_SIGPENDING,s=h=%u) failed.\n",rlim.rlim_cur);
      DBPRINTF(1,"setrlimit(RLIMIT_SIGPENDING,s=h=%u) failed.\n",rlim.rlim_cur);
    }
    else{
      LPRINTF("setrlimit(RLIMIT_SIGPENDING,s=h=%u) success.\n",rlim.rlim_cur);
      DBPRINTF(1,"setrlimit(RLIMIT_SIGPENDING,s=h=%u) success.\n",rlim.rlim_cur);
    }
#endif
   }
  }

#ifdef NETIO_MONITOR_SIGIO
   {
   struct sigaction sigio_signal_handler;

      /*Setup new sigio signal handler struct.*/
      sigio_signal_handler.sa_sigaction=sigio_monitor;
      sigemptyset(&sigio_signal_handler.sa_mask);
      sigio_signal_handler.sa_flags= SA_SIGINFO|SA_RESTART;

      /*Setup our sigio signal handler.*/
      if(sigaction(SIGIO,&sigio_signal_handler,NULL)<0){
         DBPRINTF(1,"sigaction() failed.\n");
         return(-1);
      }
   }
#endif //NETIO_MONITOR_SIGIO

   /*Setup new signal handler struct.*/
   new_signal_handler.sa_sigaction=call_back;
   sigemptyset(&new_signal_handler.sa_mask);
   new_signal_handler.sa_flags= SA_SIGINFO|SA_RESTART;

   /*Setup our signal handler.*/
   if(sigaction(rt_sig_no,&new_signal_handler,&org_signal_handler)<0){
      DBPRINTF(1,"sigaction() failed.\n");
      return(-1);
   }

-------------------------------------------------------------------------------------------------
logged output from initial call to above routine:

[02/01/24 10:01:52]netiov2.c.set_io_async():[2095]{
Real-time signal queue length limits(RLIM_INFINITY=4294967295):
 (soft=6858,hard=6858).
}
[02/01/24 10:01:52]netiov2.c.set_io_async():[2119]{
setrlimit(RLIMIT_SIGPENDING,s=h=7858) success.
}

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.