nanosleep is better than sleep and usleep

Don’t know whether you aware of the example code at Tap the interrupt signal, I am using sleep(1) within endless loop at the first sample of code.

The example of the code is to illustrate the tapping Interrupt signal while I hit control+c and ignores the termination of the program. When I hit control+c, I discover a problem. the sleep process elapse straight away although its not yet pass a second where it support to sleep for one second.

It happens to usleep function as well, where both sleep and usleep doesn’t seems to be a good sleep function to use. And I discover a better sleep function from time.h. That is nanosleep. Refers to nanosleep man page, it briefly state that it can cater the problem by storing the remaining time at second param, and with that you can use the remaining to to call nanosleep again.

That means, its not like sleep or usleep, you can use it straight away. Well, I have write a wrapper for miliseconds sleep. With the signal tap handler function in sample code, use to test for usleep and my own msleep.

#include<stdio.h>
#include<time.h>
#include<signal.h>

void sigfunc(int sig_no)
{

}

int __nsleep(const struct timespec *req, struct timespec *rem)
{
    struct timespec temp_rem;
    if(nanosleep(req,rem)==-1)
        __nsleep(rem,&temp_rem);
    else
        return 1;
}

int msleep(unsigned long milisec)
{
    struct timespec req={0},rem={0};
    time_t sec=(int)(milisec/1000);
    milisec=milisec-(sec*1000);
    req.tv_sec=sec;
    req.tv_nsec=milisec*1000000L;
    __nsleep(&req,&rem);
    return 1;
}

int main()
{
    struct sigaction sa={0};
    sa.sa_handler=&sigfunc;
    sigaction(SIGINT, &sa,NULL);

    int a=0;
    scanf("%d",&a);

    for (;;)
    {
        printf("testing...\n");
        if (a==1)
            msleep(1000);
        else
            usleep(1000000);
    }
    return 1;
}

__nsleep is a wrapper for nanosleep, the reason I want to do that wrapper is because I want to make a recursive call to nanosleep. If nanosleep is intercept by signal, it will return -1 and the second param will store the remaining time. With that, I call __nsleep recursively passing the second param as first param now. The second param will be a temp timespac structure variable.

I create another wrapper msleep accepting millisecond, in timespec structure, you can either gives value in nanosecond or second. One thing to be aware is tv_nsec cannot go beyond 999999999, which is 1 second. If beyond that, you have to put it into tv_sec.

Updates:
I found __nsleep() is redundant, and I have a better idea without using recursive and __nsleep at all, instead, directly create a msleep.

int msleep(unsigned long milisec)
{
    struct timespec req={0};
    time_t sec=(int)(milisec/1000);
    milisec=milisec-(sec*1000);
    req.tv_sec=sec;
    req.tv_nsec=milisec*1000000L;
    while(nanosleep(&req,&req)==-1)
         continue;
    return 1;
}

Store back the remaining time to req, If getting return value -1, continue to sleep. Better and cleaner isn’t it? :D

Tap the interrupt signal

When you hit control+c, you are actually send a SIGINT ( Interrupt signal ) to your program. By default, your program will be terminated after receiving SIGINT. But you can change the way of handling Interrupt signal.

Some of the application tends to ignore SIGINT. You can easily do that with sigaction.

#include<stdio.h>
#include<signal.h>
void bypass_sigint(int sig_no)
{

}
int main()
{

    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = &bypass_sigint;
    sigaction(SIGINT, &sa,NULL);

    while(1)
    {
        sleep(1);
        printf("do nothing \n ");
    }
    return 0;
}

Create a void function that intentionally do nothing. Create a sigaction structure variable, set the sa_handle point to the void fucntion. At last calling sigaction function, telling the system, while receiving SIGINT, call the void function.

Observed that the sigaction have to take 3 parameters, and the third param is to store the default sigaction structure for SIGINT. specify NULL for ignoring that.

What if I wanna tap the interrupt signal, do some operations and then allows the default SIGINT operation carry on? This can be very useful, for example, I want my program to log whatever in my memory to a file before the program terminate.

#include<stdio.h>
#include<signal.h>
#include<string.h>

struct sigaction osa;

void bypass_sigint(int sig_no)
{
    printf("I tap SIGINT and returns back \n");
    sigaction(SIGINT,&osa,NULL);
    kill(0,SIGINT);
}

int main()
{

    struct sigaction sa,osa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = &bypass_sigint;
    sigaction(SIGINT, &sa,&osa);

    while(1)
    {
        sleep(1);
        printf("do nothing \n ");
    }
    return 0;
}

I save the default sigaction structure, and after finish running my handler operation, i reset my sigaction handler to default one and send myself SIGINT.