Thread: queued signals problem, C programming related

  1. #1
    Unregistered
    Guest

    queued signals problem, C programming related

    Hi. I have been trying to make a program work, that is using realtime queued signals, but I had problems with it. What I am trying to do here is to check if all signals generated by the first source (program) are delivered to the second source (program). If you compile it and execute it you will see that only 2 of them are normally delivered, everything else is lost. I just can't find out what is wrong.
    The programs are pretty straight forward. Thanks for your help in advance.

    I am using:
    Linux Slackware 8.0
    kernel 2.4.17
    gcc 2.95.3 20010315



    /* ================================ SOURCE 1 ======================================*/

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <signal.h>
    #include <iostream.h>

    void main(int argc, char *argv[])
    {
    int pid;
    int signo = SIGUSR1;

    union sigval qval1;
    union sigval qval2;
    union sigval qval3;
    union sigval qval4;
    union sigval qval5;

    qval1.sival_int = 1;
    qval2.sival_int = 2;
    qval3.sival_int = 3;
    qval4.sival_int = 4;
    qval5.sival_int = 5;

    if (argc != 2) {
    fprintf(stderr, "Usage: %s pid signal value\n", argv[0]);
    exit(1);
    }

    pid = atoi(argv[1]);

    fprintf(stderr, "Sending signal to process %d\n", pid);

    sigqueue(pid, signo, qval1);
    sigqueue(pid, signo, qval2);
    sigqueue(pid, signo, qval3);
    sigqueue(pid, signo, qval4);
    sigqueue(pid, signo, qval5);

    pause();
    }




    /* ================================ SOURCE 2 ======================================*/

    #include <iostream.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <signal.h>

    void my_handler(int signo, siginfo_t* info, void *context)
    {
    sleep(2);
    cout<<"SIGNAL HANDLER\n";
    }

    void main(void)
    {
    int pid = getpid();
    struct sigaction act;
    sigset_t sigset;

    fprintf(stderr, "Process ID is %ld\n", (long)getpid());

    sigemptyset(&sigset);
    sigaddset(&sigset, SIGALRM);
    sigprocmask(SIG_BLOCK, &sigset, NULL);

    sigemptyset(&act.sa_mask);
    act.sa_flags = SA_SIGINFO;
    act.sa_sigaction = my_handler;
    if (sigaction(SIGUSR1, &act, NULL) < 0) {
    perror("Sigaction failed");
    exit(1);
    }

    fprintf(stderr, "Signal SIGUSR1 = %d ready\n", SIGUSR1);

    for( ; ; )
    pause();
    }

  2. #2
    Registered User Engineer's Avatar
    Join Date
    Oct 2001
    Posts
    125
    I don't really have the time to debug your code, but after looking at it I can say the following:

    1) You are blocking all the signals except SIGALRM:

    sigemptyset(&sigset);
    sigaddset(&sigset, SIGALRM);
    sigprocmask(SIG_BLOCK, &sigset, NULL);

    2) You are setting up a signal handler for only one signal:

    if (sigaction(SIGUSR1, &act, NULL) < 0) {

    3) In your signal handler you might be sleeping() for too long. Signals in UNIX are asynchronous, and they arrive pretty fast (much faster than 1 signal in 2 seconds) and even if the program is sleeping they will interrupt it.

    Those are just quick tips. Hope this helped...
    1 rule of the Samurai Code: if you have nothing to say, don't say anything at all!

  3. #3
    Unregistered
    Guest

    Exclamation

    that's exackly the porpuse of the sleep(). I must wait, so that the signal arrives in the mean-while. When a handler is executing the signal for this handler is blocked, until the handler returns. This means that by using queued signals the signal should be queued and arrive just after the termination of the previous signal handler. But this doesn't happen....

  4. #4
    Registered User
    Join Date
    Jan 2002
    Posts
    3

    Behavior of sigqueue in linux

    Ok, here is my theory on why linux is only coming up with 2 of you signals from sigqueue.
    (First of all, I don't think sleeping is a good idea in a signal handler,
    you probably don't want to do much. [On a side note all signals were delivered
    on a Solaris 8-Intel box, I tested your code on.])

    Before I actually state my theory, here is my tracking through glibc and kernel source
    code to where sigqueue actually starts doing work.

    - sigqueue can be found in the glibc source code under sysdeps/unix/sysv/linux/sigqueue.c.
    - this calls rt_sigqueueinfo (found in linux source kernel/signal.c
    - which calls kill_proc_info
    - which calls send_sig_info (here we are doing some real work, at least
    interesting work)

    I know here that this function is returning a 0 in your program, because I modified your source
    code to check the return value of sigqueue, (and it is returning 0); send_sig_info is using the
    variable "ret" for the return value, and you can see it doesn't get set to 0 until after a couple of
    checks. The next possible return is if the signal is 0 or NULL, which in our case it isn't. The next
    possible return with 0 is if the ignored_signal function returns non-zero. I tracked this through signal_type,
    which shows that global sigals (kill and other special stuff), is not ignored "I could be wrong, you can
    check the source it's also in signal.c"). Then we hit this section of code.

    Code:
            /* Support queueing exactly one non-rt signal, so that we
               can get more detailed information about the cause of
               the signal. */
            if (sig < SIGRTMIN && sigismember(&t->pending.signal, sig))
                    goto out;
    You can check to see that normal signals like SIGUSR1, SIGINT, etc.. are less than SIGRTMIN.
    Check /usr/include/asm/signal.h (shown below). So if sigismember(&t->pending.signal, sig) returns non-zero,
    you have a call to sigqueue that returns 0, which is never delivered at:

    Code:
            ret = deliver_signal(sig, info, t);
    Now check the man page for sigismember:
    sigismember tests whether signum is a member of set.
    sigismember returns 1 if signum is a member of set, 0 if signum is
    not a member, and -1 on error.

    So you send one signal USR1 (and you are sleeping now in the handler), so the second signal gets queued
    in &t->pending.signal (t is the task struct obtained from the pid), and finally the
    rest of the signals of the same type get ignored, skipping the call to deliver_signal.



    **** IN OTHER WORDS DON"T SLEEP IN SIGNALS AND DON'T EXPECT SIGNALS TO ALWAYS BE
    DELIVERED. SIGNALS ARE LIKE UDP NOT TCP. ****

    I could have this completly wrong, I'm not a kernel programmer for linux, so if there are any out
    there, is this correct?




    (you have got to love an os you can track this kind of stuff down in. I have had problems
    determining the nature of signals, and posix queues in solaris for quite awhile, I wish I
    had the source.)


    [THE REST IS THE LINUX/GLIBC SOURCE CODE (under gnu license) I looked at]



    Code:
    ./sysdeps/unix/sysv/linux/sigqueue.c [glibc source code]
    ---------------------------------------------------------------
    
    extern int __syscall_rt_sigqueueinfo (int, int, siginfo_t *__unbounded);
    
    #ifdef __NR_rt_sigqueueinfo
    /* Return any pending signal or wait for one for the given time.  */
    int
    __sigqueue (pid, sig, val)
         pid_t pid;
         int sig;
         const union sigval val;
    {
      siginfo_t info;
    
      /* First, clear the siginfo_t structure, so that we don't pass our
         stack content to other tasks.  */
      memset (&info, 0, sizeof (siginfo_t));
      /* We must pass the information about the data in a siginfo_t value.  */
      info.si_signo = sig;
      info.si_code = SI_QUEUE;
      info.si_pid = __getpid ();
      info.si_uid = __getuid ();
      info.si_value = val;
    
      return INLINE_SYSCALL (rt_sigqueueinfo, 3, pid, sig, __ptrvalue (&info));
    }
    weak_alias (__sigqueue, sigqueue)
    
    
    
    kernel/signal.c [linux source code]
    -------------------------------------------------
    asmlinkage long
    sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo)
    {
            siginfo_t info;
    
            if (copy_from_user(&info, uinfo, sizeof(siginfo_t)))
                    return -EFAULT;
    
            /* Not even root can pretend to send signals from the kernel.
               Nor can they impersonate a kill(), which adds source info.  */
            if (info.si_code >= 0)
                    return -EPERM;
            info.si_signo = sig;
    
            /* POSIX.1b doesn't mention process groups.  */
            return kill_proc_info(sig, &info, pid);
    }
    
    
    kernel/signal.c [linux source code]
    -------------------------------------------------
    inline int
    kill_proc_info(int sig, struct siginfo *info, pid_t pid)
    {
            int error;
            struct task_struct *p;
    
            read_lock(&tasklist_lock);
            p = find_task_by_pid(pid);
            error = -ESRCH;
            if (p)
                    error = send_sig_info(sig, info, p);
            read_unlock(&tasklist_lock);
            return error;
    }
    
    
    int
    send_sig_info(int sig, struct siginfo *info, struct task_struct *t)
    {
            unsigned long flags;
            int ret;
    
    
    #if DEBUG_SIG
    printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
    #endif
    
            ret = -EINVAL;
            if (sig < 0 || sig > _NSIG)
                    goto out_nolock;
            /* The somewhat baroque permissions check... */
            ret = -EPERM;
            if (bad_signal(sig, info, t))
                    goto out_nolock;
    
            /* The null signal is a permissions and process existance probe.
               No signal is actually delivered.  Same goes for zombies. */
            ret = 0;
            if (!sig || !t->sig)
                    goto out_nolock;
    
            spin_lock_irqsave(&t->sigmask_lock, flags);
            handle_stop_signal(sig, t);
    
            /* Optimize away the signal, if it's a signal that can be
               handled immediately (ie non-blocked and untraced) and
               that is ignored (either explicitly or by default).  */
    
            if (ignored_signal(sig, t))
                    goto out;
    
            /* Support queueing exactly one non-rt signal, so that we
               can get more detailed information about the cause of
               the signal. */
            if (sig < SIGRTMIN && sigismember(&t->pending.signal, sig))
                    goto out;
    
            ret = deliver_signal(sig, info, t);
    out:
            spin_unlock_irqrestore(&t->sigmask_lock, flags);
            if ((t->state & TASK_INTERRUPTIBLE) && signal_pending(t))
                    wake_up_process(t);
    out_nolock:
    #if DEBUG_SIG
    printk(" %d -> %d\n", signal_pending(t), ret);
    #endif
    
            return ret;
    }
    
    
    from /usr/include/asm/signal.h
    ------------------------------------------------------------------
    #define SIGHUP           1
    #define SIGINT           2
    #define SIGQUIT          3
    #define SIGILL           4
    #define SIGTRAP          5
    #define SIGABRT          6
    #define SIGIOT           6
    #define SIGBUS           7
    #define SIGFPE           8
    #define SIGKILL          9
    #define SIGUSR1         10
    #define SIGSEGV         11
    #define SIGUSR2         12
    #define SIGPIPE         13
    #define SIGALRM         14
    #define SIGTERM         15
    #define SIGSTKFLT       16
    #define SIGCHLD         17
    #define SIGCONT         18
    #define SIGSTOP         19
    #define SIGTSTP         20
    #define SIGTTIN         21
    #define SIGTTOU         22
    #define SIGURG          23
    #define SIGXCPU         24
    #define SIGXFSZ         25
    #define SIGVTALRM       26
    #define SIGPROF         27
    #define SIGWINCH        28
    #define SIGIO           29
    #define SIGPOLL         SIGIO
    /*
    #define SIGLOST         29
    */
    #define SIGPWR          30
    #define SIGSYS          31
    #define SIGUNUSED       31
    
    /* These should not be considered constants from userland.  */
    #define SIGRTMIN        32
    #define SIGRTMAX        (_NSIG-1)

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Problem with signals
    By kahad in forum C Programming
    Replies: 9
    Last Post: 12-07-2006, 10:42 AM
  2. problem in calling DLL
    By bhagwat_maimt in forum C++ Programming
    Replies: 2
    Last Post: 11-19-2006, 10:43 PM
  3. Replies: 2
    Last Post: 06-21-2006, 04:23 AM
  4. Laptop Problem
    By Boomba in forum Tech Board
    Replies: 1
    Last Post: 03-07-2006, 06:24 PM
  5. date-time related problem
    By Ruchikar in forum C Programming
    Replies: 1
    Last Post: 11-18-2002, 11:17 PM