0

I am trying to write simple program that uses real-time signals in Linux. But I encountered strange behaviour, first the code:

#include<signal.h>
#include<sys/types.h>
#include<stdlib.h>
#include<stdio.h>
#include"errhandling.h"
#include<string.h>
#include<errno.h>
#include<unistd.h>

void baz(int sig,siginfo_t* info,void *context)
{
  if (sig==SIGUSR1)
      printf("SIGUSR1 %d\n",info->si_value.sival_int);
  else if(sig==SIGRTMIN)
      printf("SIGRTMIN %d\n",info->si_value.sival_int);
  else 
      printf("SIGRTMIN+1 %d\n",info->si_value.sival_int);
  return ;
}

void sig_output()
{
  sigset_t set;
  sigprocmask(0,NULL,&set);
  printf("blokowane sa: ");
  if (sigismember(&set,SIGUSR1))
      printf("SIGUSR1 ");
  if(sigismember(&set,SIGUSR2))
      printf(" SIGUSR2");
  printf("\n");
  return ;
}


int received=0;
int usr2=0;

void foo(int sig)
{
  return ;
}

void usr1_handler(int sig)
{
  printf("usr1_handler\n");
  //++received;
}



void usr2_handler(int sig)
{
  usr2=1;
}

int main(int argc,char **argv)
{
  int i=0;
  pid_t pid=getppid();
  struct sigaction a;
  struct sigaction a2;
  a.sa_flags=SA_SIGINFO;
  sigset_t set;
  sigemptyset(&set);
  //sigaddset(&set,SIGRTMAX);
  sigemptyset(&(a.sa_mask));
  sigemptyset(&(a2.sa_mask));
  a.sa_sigaction=baz;
  sigaction(SIGRTMIN,&a,NULL);
  a2.sa_handler=usr1_handler;
  sigaction(SIGRTMIN+1,&a2,NULL);
  //sigprocmask(SIG_SET,&(a.sa_mask),NULL);
  while(!usr2)
  {
      printf("while\n"); 
      sigsuspend(&set);

  }
      //pause()
  printf("after while\n");
  return EXIT_SUCCESS;
}

when I run this program and it enters this loop with sigsuspend and I send to this program SIGRTMIN everything goes ok - handler executes and it waits for another signal, but when I send it SIGRTMIN+1 I get segmentation fault.

It seems that for real-time signals I need to use this extended handler with 3 arguments, but why? Is it specified somewhere? I run this program on my friend OpenSUSE 12.1 and I don't get segmentation fault for SIGRTMIN+1, but on my Xubuntu 11.10, when I send SIGRTMIN+1 I am getting segmentation fault. Is it problem with my system? Or is it implementation dependent?

Andna
  • 6,539
  • 13
  • 71
  • 120

2 Answers2

2

It seems you are missing to assign a handler to a2.sa_sigaction.


In general it is not good idea to refer to signals by a raw integer values, as the definition for the various signals might be platform specific.


Update: Make sure the struct sigaction structures are initialised properly by for example memset()ing them to 0.

alk
  • 69,737
  • 10
  • 105
  • 255
  • You are right - it went missing during copying code, I changed first post, still I get segmentation fault for SIGRTMIN+1 – Andna Apr 18 '12 at 12:25
1

Don't use printf() and friends from inside a signal handler. Don't be stubborn... Here's a substitute.

#include <stdarg.h>

int myprintf(const char *fmt, ...);
int myprintf(const char *fmt, ...)
{
    va_list args;
    char buff[512];
    int rc;

    va_start( args, fmt );

    rc = vsnprintf ( buff, sizeof buff, fmt, args );
    va_end (args);

    if (rc >0 && rc < sizeof buff) write(1, buff, rc);

    return rc;
}

UPDATE: this appears to work:

#include <signal.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#pragma #include"errhandling.h"
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdarg.h>

int myprintf(const char *fmt, ...);
int myprintf(const char *fmt, ...)
{
  va_list args;
  char buff[512];
  int rc;

  va_start( args, fmt );
  rc = vsnprintf ( buff, sizeof buff, fmt, args );
  va_end (args);

  if (rc > 0 && rc < sizeof buff) write(1, buff, rc);

  return rc;
}

void baz(int sig, siginfo_t *info, void *context)
{
#define INFO_VAL(p) p?p->si_value.sival_int:0
  if (sig==SIGUSR1)
      myprintf("SIGUSR1 %d\n", INFO_VAL(info) );
  else if(sig==SIGRTMIN)
      myprintf("SIGRTMIN %d\n", INFO_VAL(info) );
  else
      myprintf("SIGRTMIN%+d %p\n", sig-SIGRTMIN, INFO_VAL(info) );
  return ;
#undef INFO_VAL
}

void sig_output()
{
  sigset_t set;
  sigprocmask(0,NULL,&set);
  myprintf("blokowane sa: ");
  if (sigismember(&set,SIGUSR1))
      myprintf("SIGUSR1 ");
  if(sigismember(&set,SIGUSR2))
      myprintf(" SIGUSR2");
  myprintf("\n");
  return ;
}
volatile int received=0;
volatile int usr2=0;

void foo(int sig)
{
  return ;
}

void usr1_handler(int sig)
{
  myprintf("usr1_handler\n");
  //++received;
}



void usr2_handler(int sig)
{
  usr2=1;
}

int main(int argc,char **argv)
{
  int i=0;
  pid_t pid=getppid();
  struct sigaction a, a2;
  sigset_t set;

  sigemptyset(&set);
  //sigaddset(&set,SIGRTMAX);
  sigemptyset(&a.sa_mask);
  sigemptyset(&a2.sa_mask);
  a.sa_flags = 0;
  a2.sa_flags = SA_SIGINFO;
  a2.sa_sigaction = baz;
  a.sa_handler = usr1_handler;
  sigaction(SIGUSR1,&a,NULL);

  a.sa_handler = usr2_handler;
  sigaction(SIGUSR2,&a,NULL);

  sigaction(SIGRTMIN+1,&a2,NULL);
  sigaction(SIGRTMIN+2,&a2,NULL);
  sigaction(SIGRTMIN+3,&a2,NULL);
  //sigprocmask(SIG_SET,&(a.sa_mask),NULL);
  while(!usr2)
  {
      myprintf("while(!usr2)\n");
      sigsuspend(&set);

  }
      //pause()
  myprintf("after while\n");
  return EXIT_SUCCESS;
}
wildplasser
  • 43,142
  • 8
  • 66
  • 109
  • I bet this `a.sa_flags = 0;` did the job. – alk Apr 18 '12 at 14:31
  • Yes, metoo. I saw in in your answer while I already had put it into my local copy of the offending program. (the handling of a and a2 differed in a few too many places) – wildplasser Apr 18 '12 at 14:39
  • This does not help. `snprintf` is not specified to be async-signal-safe either, and in the real world (e.g. glibc) it's very async-signal-unsafe (it even calls `malloc`). Ideally `snprintf` *should be* specified as async-signal-safe, but getting everyone to fix their bad implementations is no easy task... – R.. GitHub STOP HELPING ICE Apr 18 '12 at 14:40
  • The OP is always free to supply his own replacement for vsnprintf(), IIRC, the Apache team was forced to do this in the days when snprintf() and friends were not yet present on every platform. – wildplasser Apr 18 '12 at 18:00