Thursday, April 27, 2017

Signal - signal handlers

There are two types of interrupts 1. Hardware interrupts
2. Software interrupts. Software interrupts are called signals.


How to Generate signals:
Signals are generated by 3 ways.
1. Automatically generated by process
   eg. when you access memory which is not allocated to process.
2. Process generates it willingly eg. abort(), raise()
3. Generates the signal by kill command and send it to
   specific process id. eg. kill -3 1234

What happens when signal is generated.
1. When signal generated by internally or by  kill command,
   kernel will first check that the signaling process has
   enough permission to send singal to specific process, if
   not - it will give error.
2. It sends signal to process.
3. Now process has following way to handle the signal.
    3.1 If process has not registered signal handler, the default signal handler will be called. (Most of default handler terminates the process)
    3.2 If process has registered to ignore the signal, the signal will be ignored.
    3.3 If process has registered the signal handler, that signal handler will be called.
    3.4 If process has masked the received signal, signal will be queued and when the signal is unmasked by the process - it will call the signal handler.
    3.5 If process is busy in any syscall, if that syscall is light weight eg socket(), it will be completed otherwise system call will be interrupted eg. read(), write(), pipe(), and then signal handler will be called.
4. After call of signal handler, the process is resumed from where it was.

To see list of signals, use command kill -l. The signals SIGKILL and SIGSTOP can not be caught, blocked, or ignored. Even in signal handler , all system calls are not
supported. If process uses abort() function, abort() generates SIGABRT twice.So if the signal handler of SIGABRT is registered, on first SIGABRT the registered
handler will be called.  It restores default state and on second SIGABRT - default signal handler will be called that will terminate the process.


List of few signals:

SIGSEGV: generated when invalid read or write operation is done in memory.
SIGBUS: generated when process accesses mmaped memory that does not corresponds to file.  eg. mmaped file is truncated and still process tries to access address of truncated area.
SIGCHLD: when child process exits/dies, this signal is sent to its parent process.
SIGFPE: few system generates this signal when integer is divided by 0.
SIGINTR: Ctrl+c
SIGSTOP: Ctrl+z
SIGQUIT: Ctrl+\
SIGHUP: generated on death of controlling process.
SIGILL: generated when process executes illegal instruction.
SIGABRT: generated when process executes abort().

SIGPIPE: generated when process tries to write on descriptor and there is no one available to read that data.

Signal and fork:
When process is forked, for the child process the signal queue will be empty even if parent has the pending queue.Signal handler and blocked signal state will be inherited by child. Signal mask is preserved in exec.

Signal and thread:
1. If no thread has blocked the signal, signal is delivered to any thread  and signal handler(default/registered) will be called.
2. If thread has blocked the signal, signal is delivered to any thread who has not blocked the signal.If all threads have blocked the signal, signal will be queued. Thread can block the signal by pthread_sigmask().
3. A thread can send signal to other thread by thread_kill.


Example of signal(). However, signal() is deprecated so use sigaction() instead:
#include<stdio.h>
#include<signal.h>
#include<unistd.h>

int enable_sigquit = 0;
int flip = 0;

void sig_handler(int signo)
{
    if (signo == SIGINT) {
        if (flip == 0) {
            enable_sigquit = 1;
        }
        printf("SIGINT received.\n");
    } else {
        printf("received singnal - %d\n", signo);
    }
}

int main(void)
{
    sigset_t maskset;

    if (sigemptyset(&maskset) == -1) {
        printf("sigemptyset failed for '%m'\n");
        return 0;
    }
    /*
     * add SIGQUIT to maskset.
     */
    if (sigaddset(&maskset, SIGQUIT) == -1) {
        printf("sigaddset failed for '%m'\n");
        return 0;
    }
    /*
     * block SIGQUIT
     */
    if (sigprocmask(SIG_BLOCK, &maskset, NULL) == -1) {
        printf("sigprocmask block failed for '%m'\n");
        return 0;
    }

    /*
     * try to register signal handler for SIGKILL
     */
    if (signal(SIGKILL, sig_handler) == SIG_ERR) {
        printf("can not handle SIGKILL\n");
    }

    /*
     * register signal handler for SIGINT
     */
    if (signal(SIGINT, sig_handler) == SIG_ERR) {
        printf("signal failed for '%m'\n");
        return 0;
    }

    /*
     * ignore signal SIGUSR1
     */
    if (signal(SIGUSR1, SIG_IGN) == SIG_ERR) {
        printf("signal SIG_IGN failed for '%m'\n");
        return 0;
    }
    printf("SIGQUIT is blocked, to unblocked it, give SIGINT to this process.\n");
    while(1) {
        sleep(1);
        if (enable_sigquit) {
            if (sigprocmask(SIG_UNBLOCK, &maskset, NULL) == -1) {
                printf("sigprocmask block failed for '%m'\n");
                return 0;
            }
            printf("SIGQUIT is unblocked.\n");
            enable_sigquit = 0;
            flip = 1;
        }
    }
  return 0;
}

Friday, September 26, 2014

Performance increment by minimizing page fault - C program

Generally normal programmers don't care about page faults, those will be occurred at run time of program and that degrades the performance.

This is very crucial thing that every best programmer should take care.

If you don't know what is page faults , Please visit http://en.wikipedia.org/wiki/Page_fault .

When your program is taking or requiring high memory, there are chances of high page faults.

So to minimize page faults:

1.  Suppose there are different structures or objects in your program and you are checking some conditions into them or editing some values inside them.  In this situation, you should group these structures and objects in one structure or object such a way that all different structures come serially in memory in one structure. So your one structure have continues memory in the system and that structure will be used more in program so the page in OS having this structure will be accessed frequently and so the page will be found in the memory most of times so the page faults will be less.

2.  Same as said in point 1, if you are knowing how much memory will be required by your program at run time (or you can calculate first),  you should do malloc or calloc of that memory in single call and utilize it. To utilize that memory you require small memory management unit(program- very easy program) for allocating or freeing the memory. This solution is most useful when you are creating any data structure that is not being edited at run time -just being read at run time.



Any how its up to programmers, what they want, because this thing is hidden and only clever and smarter C programmers take care.


<Sumit Kakadiya>


Thursday, July 24, 2014

difference between select, poll and epoll

Which one would you like to use select, poll or epoll? and why??

Any how I have to use only that is supported by my system.

But if all are supported than rank will be epoll, poll and last select in ascending order.

Because there are lots of pros and cons for all three.

fds stands for file descriptors here.

1.
       In select and poll before going to call of select and poll, you have to copy fds and their events from user space to kernel space every time. And to copy or register this events, you have to loop the fds every time also. So its a big overhead.

      But in epoll, you just have to copy fds and events  from user space to kernel space only ones before going into epoll_wait call. So it saves two things looping and coping to user space to kernel space in every next epool_wait call. So its a big advantage.

2.
      In select and poll , after coming from select and poll, you again have to loop all fds and have to check their events. So even if fd's events is not set, you also have to check it. So again its a big over head.

     But in epoll, after coming from epoll call, it gives you list of fds which have events. So you have to loop only those fds who have events but not all fds. So it saves much time.

3.
      epoll works with signalfd, timerfd, eventfd.

4.  
      select is not scalable because the fd_set size (probably your system may have limit to 1024) is limited in our system.

      But in case of poll and epoll, they are scalable.

5.
     In select you have to give read , write and error descriptors to separate fd_set. So You have to loop all  three to check for events.

     But in case of poll  it is in revents of pollfd sturcture and in epoll it is in events of epoll_event structure. So you do not have to loop separately.

6.
     Biggest disadvantage of epoll is that it is not supported by all system and it is not that much portable like select and poll. But if my system supports epoll, I will go for it.


<Sumit kakadiya>

Wednesday, July 23, 2014

Find out your machine is little endian or big endian by c program - linux

There are lots of ways available on net to find out machine is little endian or big endian.

But the way I am showing is to find out endianess by program that takes optimum memory.

The program will find it just by 2 bytes, as follow

#include <stdio.h>
#include <inttypes.h>

struct abc {
    union {
        int16_t a;
        char c[sizeof(int16_t)];
    };
};

int
main() {
    struct abc abc;
    abc.a = 1;

    if(abc.c[0] == 1) {
        printf("Machine is little endian.\n");
    } else {
        printf("Machine is big endian\n.");
    }

    return 0;
}


<Sumit Kakadiya>                                                                                                                                                                   

C programming-- throughput increment -decrement by little take care

"Optimum space maximum throughput"

Suppose you are creating on structure having fixed sized for example:

1.
struct abc {
     int a;
     char c[50];
};

2.
you can also write the same as
struct abc {
    int a;
    char *c;
};   and you will malloc like c= malloc(50);

and you want to do something like
struct abc *a=malloc(sizeof(struct abc));

So which way is better?

Yes it depends on application but if your structure size is fixed means any how your structure have int a + 50 bytes for variable in that case , you should go for 1.(first) implementation.

Why????
Because when you go for first implementation, whole memory will be continues, so OS(operating system) will load all memory in same page.  So there will be very less page-fault.

While in second implementation, it may possible that when you do c=malloc(50), memory of c will be allocated  in other page, so to access c OS may have page-faults.   Even you will also have to do extra system call malloc for allocating memory to variable c. So it would minimize your throughput.


Another thing is that you are saving space of sizeof(char*)  in implementation 1.Because in first implementation you are using char c[50]; that requires exactly 50*sizeof(char) bytes.

But in second implementation, you have bytes of sizeof(char *) + (50*sizeof(char));



<Sumit Kakadiya>