2015-06-06 36 views
0

我有一个x86_64多线程应用程序,我尝试模拟avr中断:当中断发生时,中断处理程序执行定义的操作时,应用程序和所有线程都挂起。在linux多线程应用程序中的中断生成SIGSEGV

我以为信号是这样做的解决方案,所以我试图捕获SIGUSR1信号,但是当我在执行应用函数之前提出SIGUSR1程序退出时出现分段错误错误。 (我已经在isr和信号中尝试了互斥锁,但实际上它们已经在主线程中运行)

代码在5个文件中。

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); 
    } 
}; 

调试信息:

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 ([email protected]=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 ([email protected]=0x7fffffffd29f, td=...) at /opt/cxxtest/cxxtest/TestRunner.h:85 
#5 0x0000000000409c76 in CxxTest::TestRunner::runSuite ([email protected]=0x7fffffffd29f, sd=...) at /opt/cxxtest/cxxtest/TestRunner.h:72 
#6 0x0000000000409e15 in CxxTest::TestRunner::runWorld ([email protected]=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 ([email protected]=0x7fffffffd320) at /opt/cxxtest/cxxtest/ErrorFormatter.h:59 
#9 0x000000000040aa89 in CxxTest::Main<CxxTest::ErrorPrinter> (tmp=..., [email protected]=1, [email protected]=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 ([email protected]=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 ([email protected]=0x7fffffffd29f, td=...) at /opt/cxxtest/cxxtest/TestRunner.h:85 
#7 0x0000000000409c76 in CxxTest::TestRunner::runSuite ([email protected]=0x7fffffffd29f, sd=...) at /opt/cxxtest/cxxtest/TestRunner.h:72 
#8 0x0000000000409e15 in CxxTest::TestRunner::runWorld ([email protected]=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 ([email protected]=0x7fffffffd320) at /opt/cxxtest/cxxtest/ErrorFormatter.h:59 
#11 0x000000000040aa89 in CxxTest::Main<CxxTest::ErrorPrinter> (tmp=..., [email protected]=1, [email protected]=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. 

记忆的信息:

$ 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 

我试图找出为什么有缺少符号(0x00007fffffffd210? ()和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 

,但无法找到一个办法让 “Linux的vdso.so.1” 在Gentoo。

我是C++初学者,我在做什么内存错误? 你有一个小费来解决这个问题吗?

EDIT1:

routine_t和__sighandler_t类型是别名:无效(*)(无效)

+1

'(__sighandler_t)_apply;''_apply'是一个对象,而不是一个函数。它的地址不是函数指针。您的程序展示未定义的行为。信号处理程序必须是一个纯粹的独立函数,匹配'__sighandler_t'签名。此外,[信号处理程序非常有限](http://en.cppreference.com/w/cpp/utility/program/signal#Signal_handler),它可以做什么以及它可以安全地访问哪些对象。 –

+0

我不确定,但它似乎有可能使用方法作为信号处理程序:http://stackoverflow.com/questions/343219/is-it-possible-to-use-signal-inside-ac-class这里http://stackoverflow.com/questions/12857101/catching-signals-use-a-member-function-as-signal-handler。我应该使用静态方法吗? (我已经尝试过但不去挖掘它) – gregorySalvan

+1

是的,你可以使用静态方法。本质上,静态方法只是一个花哨名称的常规函数​​。 –

回答

1

我相信你可以安全地忽略错误。成员顶部0.25%(!)声望的StackOverflow成员表示此警告“无法为linux-vdso.so.1加载共享库符号”。是你可以放心忽略的东西。要查看后,去这里:

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

+0

谢谢,对于linux-vdso.so.1。但为什么他们缺少符号,而它是唯一没有符号的共享库? (信号用-g选项编译) – gregorySalvan

+1

@gregorySalvan:'linux-vdso.so.1'不是一个普通的共享库,它是内核直接放入进程地址空间的共享对象。其中的代码实际上是内核的一部分。 – caf

+0

我检查过推进的答案,即使它是部分回应,整个答案(咖啡和伊戈尔Tandetnik)解决了我的问题,并帮助我了解发生了什么。谢谢。完成测试所有解决方案后,我会将固定代码放入。 – gregorySalvan

0

问题解决了感谢伊戈尔Tandetnik。

最后是下面的代码函数。

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); 
} 
相关问题