Wednesday, 29 May 2019

Send an signal with an argument (integer value)

sigaction Definition

Name:

  •     sigaction, rt_sigaction - examine and change a signal action

Synopsis:

  • #include <signal.h>
  • int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

DESCRIPTION

  • The sigaction() system call is used to change the action taken by a process on receipt of a specific signal.
  • signum specifies the signal and can be any valid signal except SIGKILL and SIGSTOP.
  • If act is non-NULL, the new action for signal signum is installed from act.
  • If oldact is non-NULL, the previous action is saved in oldact.

  • The sigaction structure is defined as something like:
           struct sigaction {
               void     (*sa_handler)(int);
               void     (*sa_sigaction)(int, siginfo_t *, void *);
               sigset_t   sa_mask;
               int        sa_flags;
               void     (*sa_restorer)(void);
           };

Note: On some architectures a union is involved: do not assign to both sa_handler and sa_sigaction.

  • The sa_restorer field is not intended for application use.
  • If SA_SIGINFO is specified in sa_flags, then sa_sigaction (instead of sa_handler)
    sa_mask specifies a mask of signals which should be blocked
  • The siginfo_t data type is a structure with the following fields:
           siginfo_t {
               int      si_signo;     /* Signal number */
               int      si_errno;     /* An errno value */
               int      si_code;      /* Signal code */
               int      si_trapno;    /* Trap number that caused
                                         hardware-generated signal
                                         (unused on most architectures) */
               pid_t    si_pid;       /* Sending process ID */
               uid_t    si_uid;       /* Real user ID of sending process */
               int      si_status;    /* Exit value or signal */
               clock_t  si_utime;     /* User time consumed */
               clock_t  si_stime;     /* System time consumed */
               sigval_t si_value;     /* Signal value */
               int      si_int;       /* POSIX.1b signal */
               void    *si_ptr;       /* POSIX.1b signal */
               int      si_overrun;   /* Timer overrun count;
                                         POSIX.1b timers */
               int      si_timerid;   /* Timer ID; POSIX.1b timers */
               void    *si_addr;      /* Memory location which caused fault */
               long     si_band;      /* Band event (was int in
                                         glibc 2.3.2 and earlier) */
               int      si_fd;        /* File descriptor */
               short    si_addr_lsb;  /* Least significant bit of address
                                         (since Linux 2.6.32) */
               void    *si_lower;     /* Lower bound when address violation
                                         occurred (since Linux 3.19) */
               void    *si_upper;     /* Upper bound when address violation
                                         occurred (since Linux 3.19) */
               int      si_pkey;      /* Protection key on PTE that caused
                                         fault (since Linux 4.6) */
               void    *si_call_addr; /* Address of system call instruction
                                         (since Linux 3.5) */
               int      si_syscall;   /* Number of attempted system call
                                         (since Linux 3.5) */
               unsigned int si_arch;  /* Architecture of attempted system call
                                         (since Linux 3.5) */
           }

  • si_signo, si_errno and si_code are defined for all signals.
  • Signals sent with kill(2) and sigqueue(3) fill in si_pid and si_uid.
  • In addition, signals sent with sigqueue(3) fill in si_int and si_ptr with the values specified by the sender of the signal

The si_code field:

  •     The si_code field inside the siginfo_t argument that is passed to a SA_SIGINFO signal handler is a value (not a bit mask) indicating why this signal was sent.
  • The following values can be placed in si_code for a SIGILL signal:
           ILL_ILLOPC
                  Illegal opcode.

           ILL_ILLOPN
                  Illegal operand.

           ILL_ILLADR
                  Illegal addressing mode.

           ILL_ILLTRP
                  Illegal trap.

           ILL_PRVOPC
                  Privileged opcode.

           ILL_PRVREG
                  Privileged register.

           ILL_COPROC
                  Coprocessor error.

RETURN VALUE

  • sigaction() returns 0 on success; on error, -1 is returned, and set errno.

ERRORS        

  • EFAULT act or oldact points to memory which is not a valid part of the process address space.

sigqueue

Name

  • sigqueue - queue a signal and data to a process

SYNOPSIS   

  •      #include <signal.h>
  •     int sigqueue(pid_t pid, int sig, const union sigval value);

DESCRIPTION       

  • sigqueue() sends the signal specified in sig to the process whose PID is given in pid.
  • The value argument is used to specify an accompanying item of data (either an integer or a pointer value) to be sent with the signal, and has the following type:
           union sigval {
               int   sival_int;
               void *sival_ptr;
           };
  • If the receiving process has installed a handler for this signal using the SA_SIGINFO flag to sigaction(2), then it can obtain this data via the si_value field of the siginfo_t structure

RETURN VALUE

  • On success, sigqueue() returns 0, Otherwise, -1 is returned and set errno .

Program


/* Send an signal with an argument (integer value) by Velraj.K
 * Check : http://velrajcoding.blogspot.in
 */

#include <stdio.h>
#include <stdlib.h>        // For exit()
#include <string.h>       // For memset()
#include <unistd.h>      // For fork() & sleep()
#include <sys/wait.h>      // For sig_atomic_t, siginfo_t, sigaction, SA_SIGINFO, SIGUSR1, SIGUSR2, sigqueue(), wait()
#include <assert.h>        // For assert()

static volatile sig_atomic_t got_value = 0;

void sig_handler(int sig, siginfo_t *info, void *x)
{
    pid_t pid = 0;

    pid = getpid();
    /* info->si_value.sival_int contains the integer value receive from sender */
    switch (info->si_value.sival_int) {
        case 1:
            printf("Vel Child:%d, received Signal with arg value as 1 sig num = %d SIG_USR1:%d SIG_USR2:%d \n", pid, sig, SIGUSR1, SIGUSR2);
            break;
        case 2:
            printf("Vel Child:%d, received Signal with arg value as 2 sig num = %d \n", pid, sig);
            break;
        default:
            printf("Invalid value \n");
            break;
    }
    ++got_value;

    return;
}


int main()
{
    struct sigaction act = {0};
    int ret;
    int status = 0;
    pid_t pid = -1;
    union sigval send_arg = {0};

    act.sa_flags = SA_SIGINFO;
    act.sa_sigaction = sig_handler;

    /* Install hangler for singal */
    ret = sigaction(SIGUSR1, &act, NULL);
    assert(ret == 0);

    ret = sigaction(SIGUSR2, &act, NULL);
    assert(ret == 0);

    /* Create child process & send the signal from parent to Child */
    pid = fork();
    /*
     * On success, parent process get child PID,
     * Child process get pid as 0
     */
    if (-1 == pid) {
        exit(1);
    } else if (0 == pid) {
        /* Child process */
        while (2 != got_value) {
            sleep(1);
        }
        exit(0);
    } else {
        /* Parent process */
        /* Send signal along with value 1 */
        send_arg.sival_int = 1;
        printf("Vel Parent:%d send SIGUSR2 with arg value as 1 to the Child:%d \n", getpid(), pid);
        sigqueue(pid, SIGUSR2, send_arg);

        /* Send signal along with value 2 */
        send_arg.sival_int = 2;
        printf("Vel Parent:%d send SIGUSR1 with arg value as 2 to the Child:%d \n", getpid(), pid);
        sigqueue(pid, SIGUSR1, send_arg);
        wait(&status);
        printf("Vel Parent:%d  -->  Status return by Child:%d \n", getpid(), status);
    }

    return 0;
}

 

Output:

 Vel Parent:10474 send SIGUSR2 with arg value as 1 to the Child:10475
Vel Parent:10474 send SIGUSR1 with arg value as 2 to the Child:10475
Vel Child:10475, received Signal with arg value as 1 sig num = 12 SIG_USR1:10 SIG_USR2:12
Vel Child:10475, received Signal with arg value as 2 sig num = 10
Vel Parent:10474  -->  Status return by Child:0



Reference:

  • http://man7.org/linux/man-pages/man2/sigaction.2.html
  • http://man7.org/linux/man-pages/man3/sigqueue.3.html