AIX

 View Only
  • 1.  System signals cause some functions(select/nanosleep) to fail

    Posted Wed January 18, 2023 07:38 PM
    Hello, I want to encapsulate a function, such as select(),nanosleep(),sleep(), to achieve a general delay function.
    But on my AIX platform, the system signals will cause these functions to fail.
    I have tested with other systems and found that the signals sent to the process do not cause these functions used in the same process to end prematurely.
    On AIX, I've found that signals seem to be caught and handled twice, first by my signal_handler(), and second by these functions ending early with errno=EINTR set. Is there a way to prevent these functions from getting these signals, thanks.

    oslevel -s
    7200-04-04-2114

    Demo code:
    // File: ibm.cpp
    //
    // Build: g++ -std=c++11 -w -g -maix64 -o delay ibm.cpp
    //
    // Start with ./delay
    //
    // Send a signal SIGUSR2 to the process with command:
    // ps aux | grep delay | grep -v grep | awk '{print $2}' | xargs kill -USR2
    // then the select() nor nanosleep() will be interrupted.
    
    #include <stdio.h>
    #include <unistd.h>
    #include <signal.h>
    #include <string.h>
    #include <errno.h>
    
    #include <sys/time.h>
    #include <sys/select.h>
    #include <sys/types.h>
    
    #include <pthread.h>
    
    //delay for n microseconds, 1000000=1s
    //using nanosleep()
    void delay_using_nanosleep(int n, const char* p="")
    {
        int n0 = n;
        int ret = 0;
    
        time_t t0;
        ::time(&t0);
    
        struct timespec req;
        req.tv_sec = n / 1000000;
        req.tv_nsec = n % 1000000 * 1000;
        while(1)
        {
            //req.tv_sec = n / 1000000;
            //req.tv_nsec = n % 1000000 * 1000;
            ret = nanosleep(&req, &req);
            if(ret != 0) {
                int no = errno;
                printf("\ndelay_t()-nanosleep() thread:%s @@@@@@@@@@@@\n", p);
                printf("nanosleep return %d, errno=%d, left:%d-%d\n\n\n",
                    ret, no, req.tv_sec, req.tv_nsec);
                if(no == EINTR)
                    continue;
            }
    
            break;
        }
        time_t t1;
        ::time(&t1);
        if(t1 - t0 < n0 / 1000000)
            printf("delay()-nanosleep() failed, t1-t0=%d\n", t1-t0);
    }
    
    
    //delay for n microseconds, 1000000=1s
    //using select()
    void delay_using_select(int n, const char* p="")
    {
    #if defined (WIN32)
        Sleep(n / 1000);
    #else
        struct timeval tt;
        int ret;
        int n0 = n;
        time_t t0;
        ::time(&t0);
        tt.tv_sec = n / 1000000;
        tt.tv_usec = n % 1000000;
        while(1)
        {
            //tt.tv_sec = n / 1000000;
            //tt.tv_usec = n % 1000000;
            ret=select(0, 0, 0, 0, &tt);
            if(ret<0){
                int no = errno;
                printf("\ndelay_t()-select() thread:%s @@@@@@@@\n", p);
                printf("select return %d, errno=%d, left:%d-%d\n\n\n",
                    ret, no, tt.tv_sec, tt.tv_usec);
                if(no == EINTR) {
                    //n = n / 2;
                    //if(n >= 50000)
                        continue;
                }
            }
            break;
        }
        time_t t1;
        ::time(&t1);
        if(t1 - t0 < n0 / 1000000)
            printf("delay()-select() failed, t1-t0=%d\n", t1-t0);
    #endif
    }
    
    void signal_handler(int sig)
    {
        if(sig == SIGUSR2) {
            write(1, "SIGUSR2\n", 8);
            //signal_count++;
        }
    }
    
    int main(int argc, char const* argv[])
    {
        int ret = 0;
    
        sigset(SIGUSR2, signal_handler);
    
        while(1) {
            printf("main loop...\n");
            delay_using_select(3000000, "");     // ---SIGUSR2 will interrupt select()
            //delay_using_nanosleep(3000000, "");  // --SIGUSR2 will interrupt sleep()
        }
    
        return 0;
    }


    ------------------------------
    dou fu
    ------------------------------


  • 2.  RE: System signals cause some functions(select/nanosleep) to fail

    IBM Champion
    Posted Thu January 19, 2023 05:10 AM

    Those functions are supposed to exit on signals, returning -1 and setting errno==EINTR.

    nanosleep()

    At least for nanosleep, the correct way to handle this is to loop while rc==-1 andf errno==EINTR, using the second argument (it gets updated with the remaining time).

    ex:
    struct timespec standard, arg, remain;

    // Initialize standard to your desired value
    standard = whatever;

    arg=standard;
    while(nanosleep(&arg, &remain) == -1 && errno==EINTR) {
      // We were interrupted by a signal (you may want to check a global variable to see if you want to actually break the loop)
      arg=remain; // Load the remaining time as the next nanosleep argument.
    }

    If you never need to know the difference between the requested time and remaining time, you can just do this:

    arg=standard;
    while(nanosleep(&arg, &arg) == -1 && errno==EINTR) { // On interrupt, arg gets updated with the remaining time.
      // We were interrupted by a signal (you may want to check a global variable to see if you want to actually break the loop)
    }


    If you have no use for the "standard" timespec, you can assign arg directly.

    Alternatively: have you tried setting SIG_IGN (ignore) or using sighld()/sigignore() ?

    select()

    From the select() manpage:  EINTR - A signal was caught during the select subroutine and the signal handler was installed with an indication that subroutines are not to be restarted

    If timing isn't critical, just loop while rc==-1 and errno=EINTR.

    If timing is critical, get the nanotime before starting the loop, loop while (rc==-1 and errno=EINTR), then inside the loop look at the difference between the current nanotime and the beforenanotime to decide if you've gone over the nanotime budget.

    sleep()

    sleep is implemented with nsleep(), use the same trick as the select().



    ------------------------------
    José Pina Coelho
    IT Specialist at Kyndryl
    ------------------------------



  • 3.  RE: System signals cause some functions(select/nanosleep) to fail

    Posted Thu January 19, 2023 08:08 AM
    Thank you for your reply, I will add judgment on EINTR within my code.
    I originally thought that if there was a way to prevent my own signals (such as SIGUSR2, which actually have nothing to do with these functions) from being passed to these functions, but only be handled by the methods registered in the main function, it seems that there is no.

    ------------------------------
    dou fu
    ------------------------------



  • 4.  RE: System signals cause some functions(select/nanosleep) to fail

    Posted Thu January 19, 2023 02:16 PM
    Old school UNIX C code to do this would be to call
    signal(SIGUSR2, SIG_IGN)​

    to ignore the SIGUSR2 signal, but these days you'd use sigaction() instead. If you want to use your own signal handler, pass its address instead of SIG_IGN.



    ------------------------------
    Dave Marquardt
    Sr. Software Engineer
    IBM
    Austin TX
    ------------------------------



  • 5.  RE: System signals cause some functions(select/nanosleep) to fail

    Posted Thu January 19, 2023 09:08 PM
    1. If signal(SIGUSR2, SIG_IGN)​ is used, these functions will indeed not be interrupted, but all SIGUSR2 in the whole process will no longer be caught, which is not what I expect.
    2.If sigset(SIGUSR2, signal_handler) is used, signal_handler() can catch SIGUSR2, but at the same time, the select() call in an uncertain thread(assume that each thread is in select() blocking) in my process will be interrupted too. This is also not what I expect, my goal is that SIGUSR2 does not cause any select() interrupts.

    ------------------------------
    dou fu
    ------------------------------



  • 6.  RE: System signals cause some functions(select/nanosleep) to fail

    Posted Fri January 20, 2023 08:46 AM
    So you're using threads? pthreads? Check out sigthreadmask() or pthread_sigmask().

    ------------------------------
    Dave Marquardt
    Sr. Software Engineer
    IBM
    Austin TX
    ------------------------------