gregorySalvan
gregorySalvan

Reputation: 381

Interruption in a linux multithreaded app generate SIGSEGV

I have a x86_64 multithreaded application where I try to emulate avr interrupts: when interrupt occurs application and all threads are suspended while interrupt handler execute defined actions.

I thought signals were the solution to do this so I'm trying to catch SIGUSR1 signal, but when I raise SIGUSR1 program exit with a segmentation fault error before executing apply function. (I have tried mutex in isr and signals but removed as actually they run in the main thread)

The code is within 5 files.

isr.h

#ifndef __ISR_H__
#define __ISR_H__

typedef void (*routine_t)(void);

class InterruptServiceRoutine
{
    routine_t routine;
    bool locked = true;
public:
    InterruptServiceRoutine(routine_t isr);
    void apply();
    void unlock(){locked = false;};
};

typedef InterruptServiceRoutine ISR_t;

#endif // __ISR_H__

isr.cpp:

#include <ISR.h>

InterruptServiceRoutine::InterruptServiceRoutine(routine_t isr): routine(isr){}

void InterruptServiceRoutine::apply()
{
    if (!locked) routine();
}

Signals.h:

#ifndef __SIGNALS_H__
#define __SIGNALS_H__
#include <vector>
#include <ISR.h>
#include <signal.h>


class Logger;

class Signals
{
private:
    Logger& log;
    std::vector<ISR_t*> isr_table;

public:
    Signals(Logger&);
    ~Signals();
    unsigned int count(void);
    void clear(void);
    void connect(ISR_t &isr);
    void apply(int);
};

#endif // __SIGNALS_H__

Signals.cpp:

#include <signal.h>
#include <pthread.h>
#include <functional>

#include <ISR.h>
#include <Signals.h>
#include <Logger.h>

using namespace std;

void Signals::apply(int)
{

  sigset_t sigs_to_block;
  sigfillset(&sigs_to_block);
  pthread_sigmask(SIG_BLOCK, &sigs_to_block, NULL);

  unsigned int num_interrupts = count();
  for (unsigned int i=0; i < num_interrupts; ++i)
  {
    isr_table[i]->apply();
  }

  pthread_sigmask(SIG_SETMASK, NULL, NULL);
}

Signals::Signals(Logger& _log): log(_log)
{
  clear();
  auto _apply = bind1st(mem_fun(&Signals::apply), this);
  struct sigaction new_action;
  new_action.sa_handler = (__sighandler_t) &_apply;
  new_action.sa_flags = 0;
  sigfillset(&new_action.sa_mask);
  sigaction(SIGUSR1, &new_action, NULL);
  pthread_sigmask(SIG_SETMASK, NULL, NULL);
}

Signals::~Signals() {
  struct sigaction new_action;
  new_action.sa_handler = SIG_DFL;
  new_action.sa_flags = 0;
  sigemptyset(&new_action.sa_mask);
  sigaddset(&new_action.sa_mask, SIGUSR1);
  sigaction(SIGUSR1, &new_action, NULL);
  clear();
}

void Signals::clear(void)
{
  isr_table.clear();
  isr_table.reserve(20);
}

unsigned int Signals::count(void)
{
  return isr_table.size();
}

void Signals::connect(ISR_t &isr)
{
  isr_table.push_back(&isr);
}

SignalsTest.test:

#include <signal.h>
#include <pthread.h>

#include <cxxtest/TestSuite.h>
#include <ISR.h>
#include <Signals.h>
#include <Logger.h>

volatile sig_atomic_t isr_called_count;

void isr(void)
{
    ++isr_called_count;
}

class SignalsTestSuite: public CxxTest::TestSuite
{
  Logger log;
  Signals handler;

public:
  SignalsTestSuite(void): handler(log){}
  void setUp()
  {
    handler.clear();
    isr_called_count = 0;
  }
/* ... truncated for more visibility ... */
  void testWhenRaiseSIGUSRItCallsAvailableRoutine(void)
  {
    ISR_t routine(&isr);
    routine.unlock();
    handler.connect(routine);
    handler.connect(routine);
    raise(SIGUSR1);
    TS_ASSERT_EQUALS(isr_called_count, 2);
  }
};

Debug informations:

GNU gdb (Gentoo 7.7.1 p1) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://bugs.gentoo.org/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./out/signals...done.
(gdb) r
Starting program: test/out/signals 
warning: Could not load shared library symbols for linux-vdso.so.1.
Do you need "set solib-search-path" or "set sysroot"?
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Running 3 tests..
Program received signal SIGUSR1, User defined signal 1.
0x00007ffff7bd0beb in raise (sig=10) at ../sysdeps/unix/sysv/linux/pt-raise.c:36
36    return INLINE_SYSCALL (tgkill, 3, pid, THREAD_GETMEM (THREAD_SELF, tid),
(gdb) bt
#0  0x00007ffff7bd0beb in raise (sig=10) at ../sysdeps/unix/sysv/linux/pt-raise.c:36
#1  0x0000000000403f38 in SignalsTestSuite::testWhenRaiseSIGUSRItCallsAvailableRoutine (this=this@entry=0x631cc0 <suite_SignalsTestSuite>)
    at test/SignalsTest.test:62
#2  0x0000000000403f92 in TestDescription_suite_SignalsTestSuite_testWhenRaiseSIGUSRItCallsAvailableRoutine::runTest (this=<optimized out>) at out/signals.cpp:38
#3  0x000000000040424e in CxxTest::RealTestDescription::run (this=<optimized out>) at /opt/cxxtest/cxxtest/RealDescriptions.cpp:109
#4  0x0000000000409afb in CxxTest::TestRunner::runTest (this=this@entry=0x7fffffffd29f, td=...) at /opt/cxxtest/cxxtest/TestRunner.h:85
#5  0x0000000000409c76 in CxxTest::TestRunner::runSuite (this=this@entry=0x7fffffffd29f, sd=...) at /opt/cxxtest/cxxtest/TestRunner.h:72
#6  0x0000000000409e15 in CxxTest::TestRunner::runWorld (this=this@entry=0x7fffffffd29f) at /opt/cxxtest/cxxtest/TestRunner.h:57
#7  0x0000000000409f52 in CxxTest::TestRunner::runAllTests (listener=...) at /opt/cxxtest/cxxtest/TestRunner.h:34
#8  0x0000000000409f93 in CxxTest::ErrorFormatter::run (this=this@entry=0x7fffffffd320) at /opt/cxxtest/cxxtest/ErrorFormatter.h:59
#9  0x000000000040aa89 in CxxTest::Main<CxxTest::ErrorPrinter> (tmp=..., argc=argc@entry=1, argv=argv@entry=0x7fffffffd448) at /opt/cxxtest/cxxtest/TestMain.h:109
#10 0x0000000000407f62 in main (argc=1, argv=0x7fffffffd448) at out/runner.cpp:18
(gdb) l
31       that.  */
32    pid_t pid = THREAD_GETMEM (THREAD_SELF, pid);
33    if (__glibc_unlikely (pid < 0))
34      pid = -pid;
35  
36    return INLINE_SYSCALL (tgkill, 3, pid, THREAD_GETMEM (THREAD_SELF, tid),
37               sig);
38  }
(gdb) s

Program received signal SIGSEGV, Segmentation fault.
0x00007fffffffd210 in ?? ()
(gdb) bt
#0  0x00007fffffffd210 in ?? ()
#1  <signal handler called>
#2  0x00007ffff7bd0beb in raise (sig=10) at ../sysdeps/unix/sysv/linux/pt-raise.c:36
#3  0x0000000000403f38 in SignalsTestSuite::testWhenRaiseSIGUSRItCallsAvailableRoutine (this=this@entry=0x631cc0 <suite_SignalsTestSuite>)
    at test/SignalsTest.test:62
#4  0x0000000000403f92 in TestDescription_suite_SignalsTestSuite_testWhenRaiseSIGUSRItCallsAvailableRoutine::runTest (this=<optimized out>) at out/signals.cpp:38
#5  0x000000000040424e in CxxTest::RealTestDescription::run (this=<optimized out>) at /opt/cxxtest/cxxtest/RealDescriptions.cpp:109
#6  0x0000000000409afb in CxxTest::TestRunner::runTest (this=this@entry=0x7fffffffd29f, td=...) at /opt/cxxtest/cxxtest/TestRunner.h:85
#7  0x0000000000409c76 in CxxTest::TestRunner::runSuite (this=this@entry=0x7fffffffd29f, sd=...) at /opt/cxxtest/cxxtest/TestRunner.h:72
#8  0x0000000000409e15 in CxxTest::TestRunner::runWorld (this=this@entry=0x7fffffffd29f) at /opt/cxxtest/cxxtest/TestRunner.h:57
#9  0x0000000000409f52 in CxxTest::TestRunner::runAllTests (listener=...) at /opt/cxxtest/cxxtest/TestRunner.h:34
#10 0x0000000000409f93 in CxxTest::ErrorFormatter::run (this=this@entry=0x7fffffffd320) at /opt/cxxtest/cxxtest/ErrorFormatter.h:59
#11 0x000000000040aa89 in CxxTest::Main<CxxTest::ErrorPrinter> (tmp=..., argc=argc@entry=1, argv=argv@entry=0x7fffffffd448) at /opt/cxxtest/cxxtest/TestMain.h:109
#12 0x0000000000407f62 in main (argc=1, argv=0x7fffffffd448) at out/runner.cpp:18
(gdb) l
Line number 39 out of range; ../sysdeps/unix/sysv/linux/pt-raise.c has 38 lines.
(gdb) s
Cannot find bounds of current function
(gdb) c
Continuing.

Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.

Memory informations:

$ valgrind --leak-check=full --show-leak-kinds=all ./out/signals
==31715== Memcheck, a memory error detector
==31715== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==31715== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==31715== Command: ./out/signals
==31715== 
Running 3 tests..==31715== 
==31715== Process terminating with default action of signal 11 (SIGSEGV)
==31715==  Bad permissions for mapped region at address 0xFFEFFF1F0
==31715==    at 0xFFEFFF1F0: ???
==31715==    by 0x409F92FF: ???
==31715==    by 0xFFF: ???
==31715==    by 0x40AA88FF: ???
==31715== 
==31715== HEAP SUMMARY:
==31715==     in use at exit: 176 bytes in 2 blocks
==31715==   total heap usage: 2 allocs, 0 frees, 176 bytes allocated
==31715== 
==31715== 16 bytes in 1 blocks are still reachable in loss record 1 of 2
==31715==    at 0x4C294C0: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==31715==    by 0x408AB1: CxxTest::ErrorPrinter::ErrorPrinter(std::ostream&, char const*, char const*) (ErrorPrinter.h:43)
==31715==    by 0x407F4C: main (runner.cpp:17)
==31715== 
==31715== 160 bytes in 1 blocks are still reachable in loss record 2 of 2
==31715==    at 0x4C294C0: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==31715==    by 0x40B2E3: __gnu_cxx::new_allocator<InterruptServiceRoutine*>::allocate(unsigned long, void const*) (new_allocator.h:104)
==31715==    by 0x40B315: std::_Vector_base<InterruptServiceRoutine*, std::allocator<InterruptServiceRoutine*> >::_M_allocate(unsigned long) (in test/out/signals)
==31715==    by 0x40B941: InterruptServiceRoutine** std::vector<InterruptServiceRoutine*, std::allocator<InterruptServiceRoutine*> >::_M_allocate_and_copy<std::move_iterator<InterruptServiceRoutine**> >(unsigned long, std::move_iterator<InterruptServiceRoutine**>, std::move_iterator<InterruptServiceRoutine**>) (stl_vector.h:1138)
==31715==    by 0x40BA28: std::vector<InterruptServiceRoutine*, std::allocator<InterruptServiceRoutine*> >::reserve(unsigned long) (vector.tcc:75)
==31715==    by 0x40AE7D: Signals::clear() (Signals.cpp:57)
==31715==    by 0x40AF50: Signals::Signals(Logger&) (Signals.cpp:32)
==31715==    by 0x403531: SignalsTestSuite::SignalsTestSuite() (in test/out/signals)
==31715==    by 0x40302D: __static_initialization_and_destruction_0(int, int) (signals.cpp:18)
==31715==    by 0x403144: _GLOBAL__sub_I_suite_SignalsTestSuite_init (signals.cpp:39)
==31715==    by 0x4147EC: __libc_csu_init (elf-init.c:88)
==31715==    by 0x5A8DA34: (below main) (libc-start.c:245)
==31715== 
==31715== LEAK SUMMARY:
==31715==    definitely lost: 0 bytes in 0 blocks
==31715==    indirectly lost: 0 bytes in 0 blocks
==31715==      possibly lost: 0 bytes in 0 blocks
==31715==    still reachable: 176 bytes in 2 blocks
==31715==         suppressed: 0 bytes in 0 blocks
==31715== 
==31715== For counts of detected and suppressed errors, rerun with: -v
==31715== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Erreur de segmentation

I've tried to figure out why there are missing symbols (0x00007fffffffd210 in ?? () and at 0xFFEFFF1F0: ??? ...):

(gdb) info share
From                To                  Syms Read   Shared Object Library
0x00007ffff7ddca80  0x00007ffff7df5960  Yes         /lib64/ld-linux-x86-64.so.2
                                        No          linux-vdso.so.1
0x00007ffff7bc6a40  0x00007ffff7bd2781  Yes         /lib64/libpthread.so.0
0x00007ffff79bb360  0x00007ffff79be0dc  Yes         /lib64/librt.so.1
0x00007ffff770f5f0  0x00007ffff77733c3  Yes         /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/libstdc++.so.6
0x00007ffff73c04f0  0x00007ffff7425266  Yes         /lib64/libm.so.6
0x00007ffff71a7ac0  0x00007ffff71b6e45  Yes         /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/libgcc_s.so.1
0x00007ffff6e2c430  0x00007ffff6f53b44  Yes         /lib64/libc.so.6

But can't find a way to get "linux-vdso.so.1" on gentoo.

I'm a beginner in C++ what I'm doing wrong with memory ? Have you a tip to fix this ?

Edit1:

routine_t and __sighandler_t types are aliases for: void (*)(void)

Upvotes: 0

Views: 541

Answers (2)

gregorySalvan
gregorySalvan

Reputation: 381

Problem solved thanks to Igor Tandetnik.

Finally the following code function.

signals.h:

#ifndef __SIGNALS_H__
#define __SIGNALS_H__
#include <vector>
#include <ISR.h>
#include <signal.h>

using namespace std;

class Logger;

class Signals
{
private:
    Logger& log;
    static bool action_handled;
    void reserve();

public:
    static void start();
    static void stop();
    static std::vector<ISR_t*> isr_table;
    Signals(Logger& _log);
    ~Signals();
    unsigned int count(void);
    void clear(void);
    void connect(ISR_t&);
    static void apply(int);
    static void unmask_pthread_signals();
    static void mask_pthread_signals();
};


#endif // __SIGNALS_H__

signals.cpp:

#include <functional>
#include <signal.h>
#include <pthread.h>

#include <ISR.h>
#include <Signals.h>
#include <Logger.h>


using namespace std;

vector<ISR_t*> Signals::isr_table={};
bool Signals::action_handled=false;


void Signals::apply(int)
{
  mask_pthread_signals();
  for (unsigned int i=0; i < isr_table.size(); ++i)
  {
    isr_table[i]->apply();
  }
  unmask_pthread_signals();
}

Signals::Signals(Logger& _log): log(_log){
  clear();
  start();
}


Signals::~Signals() {
  clear();
  stop();
}



void Signals::clear(void)
{
  isr_table.clear();
  isr_table.reserve(0);
}

unsigned int Signals::count(void)
{
  return isr_table.size();
}

void Signals::start()
{
  if (action_handled) return;
  struct sigaction new_action;
  new_action.sa_handler = (__sighandler_t) &Signals::apply;
  new_action.sa_flags = 0;
  sigemptyset(&new_action.sa_mask);
  sigaction(SIGUSR1, &new_action, NULL);
  unmask_pthread_signals();
  action_handled = true;
}

void Signals::stop()
{
  if (!action_handled) return;
  struct sigaction new_action;
  new_action.sa_handler = SIG_DFL;
  sigemptyset(&new_action.sa_mask);
  sigaction(SIGUSR1, &new_action, NULL);
  mask_pthread_signals();
  action_handled = false;
}

void Signals::unmask_pthread_signals()
{
  sigset_t signals_mask;
  sigemptyset(&signals_mask);
  pthread_sigmask(SIG_SETMASK, &signals_mask, NULL);
}

void Signals::mask_pthread_signals()
{
  sigset_t signals_mask;
  sigfillset(&signals_mask);
  pthread_sigmask(SIG_SETMASK, &signals_mask, NULL);
}

void Signals::reserve()
{
  if (isr_table.capacity() <= isr_table.size()) {
    isr_table.reserve(isr_table.capacity() + 20);
  }
}

void Signals::connect(ISR_t &isr)
{
  start();
  reserve();
  isr_table.push_back(&isr);
}

Upvotes: 0

Propulsion
Propulsion

Reputation: 513

I believe that you can safely ignore the error. A StackOverflow member with a reputation in the top 0.25% of members (!) says that this warning "Could not load shared library symbols for linux-vdso.so.1." is something you can safely ignore. To see the post, go here:

Could not load shared library symbols for linux-vdso.so.1. while debugging

Upvotes: 1

Related Questions