ACE 的ACE_Sig_Action/ACE_Sig_Handler/ACE_Sig_Guard 和 SIGSEGV屏蔽

1、 ACE_Sig_Action

ACE_Sig_Action是对POSIX sigaction()调用进行封装的封装类。使用ACE_Sig_Action类,只能为一个信号设置一个回调函数。由于回调函数是在信号中断处理上下文中,绝不要在回调函数中做耗时工作。如果有耗时工作要做,我们可以使用ACE_Reactor的通知机制,让耗时工作转会普通的执行上下文去做。

ACE_Sig_Action用法:

  • 定义如下类型的回调函数:typedef void (*ACE_SignalHandler) (int );返回void,接受一个int类型的参数(信号类型值);
  • 实例化ACE_Sig_Action对象,使用ACE_Sig_Action::handler (ACE_SignalHandler)函数设置回调函数,使用ACE_Sig_Action::register_action(int signum)函数,为信号signum设置回调函数。

示例代码:

  1. void my_handler (int signo) {  
  2.     // Do something  
  3. }  
  4.   
  5. ACE_Sig_Action sig_action;  
  6. sig_action.handler (my_handler);  
  7. sig_action.register_action (SIGUSR1);  

在信号中断回调函数执行过程中,依然能够被 其它 信号中断,但不能被正在处理的信号所中断。对于在某信号的回调处理执行中,收到多次该信号,操作系统将pend此信号,并在上一处理函数执行完后,回调 一次 。如果我们不希望信号回调函数被中断,我们可以为ACE_Sig_Action实例指定信号掩码。如在上面的实例代码中,如果我们不希望SIGUSR1信号的中断处理函数被信号SIGUSR2中断,可在register_action()方法调用前加上如下代码:

  1. ACE_Sig_Set sig_set;  
  2. sig_set.add (SIGUSR2);  
  3. sig_action.mask (sig_set);  

注意,我们的许多阻塞的系统调用能够被信号中断,在使用信号时,要为阻塞函数做信号中断处理。对于为sigaction()系统调用提供SA_RESTART标志支持的系统,我们可以对ACE_Sig_Action对象设置SA_RESTART标志,可让被信号中断的系统调用继续执行。不过设置这个标识是不是能够起作用,要参考操作系统的文档,我在自己的linux虚拟机上设置此标识时,并未自动重新调用被信号中断的系统调用。

2、 ACE_Sig_Handler

ACE_Sig_Handler提供了一种面向对象的、基于事件处理器的信号登记和分派方案。使用ACE_Sig_Handler提供的这一方案,我们需要从ACE_Event_Handler的派生信号处理类。

2.1 ACE_Sig_Handler用法:

  • 从ACE_Event_Handler派生信号处理类,实现虚方法handle_signal()。
  • 创建信号处理类实例,创建ACE_Sig_Handler实例。调用ACE_Sig_Handler::register_handler (int signo, ACE_Event_Handler *h)方法为信号设置信号处理器。

2.2 示例代码

  1. #include <ace/Sig_Handler.h>  
  2. #include <ace/Event_Handler.h>  
  3. #include <ace/Log_Msg.h>  
  4. #include <ace/Process.h>  
  5.   
  6. class MySignalHandler: public ACE_Event_Handler  
  7. {  
  8.     public:  
  9.         MySignalHandler (int signo): signum_(signo) {}  
  10.   
  11.         virtual ~MySignalHandler () {}  
  12.   
  13.         virtual int handle_signal (int signum,  
  14.                 siginfo_t * = 0,  
  15.                 ucontext_t * = 0)  
  16.         {  
  17.             ACE_TRACE (ACE_TEXT ("MySignalHandler::handle_signal"));  
  18.   
  19.             // Make sure the right handler was called back.  
  20.             ACE_ASSERT (signum == this->signum_);  
  21.   
  22.             ACE_DEBUG ((LM_DEBUG,  
  23.                         ACE_TEXT ("%S occured\n"),  
  24.                         signum));  
  25.             return 0;  
  26.         }  
  27.     private:  
  28.         int signum_;  
  29. };  
  30.   
  31. int ACE_TMAIN (int argc, ACE_TCHAR *argv[])  
  32. {  
  33.     MySignalHandler h1 (SIGUSR1), h2 (SIGUSR2);  
  34.     ACE_Sig_Handler handler;  
  35.     handler.register_handler (SIGUSR1, &h1);  
  36.     handler.register_handler (SIGUSR2, &h2);  
  37.   
  38.     //ACE_OS::kill (ACE_OS::getpid (), SIGUSR1);  
  39.     //ACE_OS::kill (ACE_OS::getpid (), SIGUSR2);  
  40.     ACE_Process kill_signal;  
  41.     ACE_Process_Options options;  
  42.     options.command_line ("./kill_signal %d %d",  
  43.             ACE_OS::getpid (),  
  44.             SIGUSR1);  
  45.     kill_signal.spawn (options);  
  46.   
  47.     options.command_line ("./kill_signal %d %d",  
  48.             ACE_OS::getpid (),  
  49.             SIGUSR2);  
  50.     kill_signal.spawn (options);  
  51.       
  52.     int time = 10;  
  53.     while (ACE_OS::sleep (time) == -1)  
  54.     {  
  55.         ACE_DEBUG ((LM_DEBUG,  
  56.                     ACE_TEXT ("Sleep() returns -1\n")));  
  57.         if (errno == EINTR)  
  58.             continue;  
  59.         else  
  60.         {  
  61.             ACE_ERROR_RETURN ((LM_ERROR,  
  62.                         ACE_TEXT ("%p\n"),  
  63.                         ACE_TEXT ("sleep")), -1);  
  64.         }  
  65.     }  
  66.   
  67.     return 0;  
  68. }  
其中kill_signal是一个向指定进程ID发送指定信号的小程序。程序派生子进程向自己发送信号。
handle_signal的第一个参数引发中断的信号值。我们不详细介绍handle_signal回调函数的另外两个参数,可参考操作系统文档。其中siginfo_t提供了正在递送信号的起因和属性等信息。

3、 ACE_Sig_Guard

信号中断处理是异步的。如果我们在某段代码的执行过程中不希望被信号中断,可以使用ACE_Sig_Guard进行保护。

示例代码如下:

  1. ACE_Sig_Set sig_set;  
  2. sig_set.add (SIGUSR1);  
  3. sig_set.add (SIGUSR2);  
  4.   
  5. {  
  6.     ACE_Sig_Guard sig_guard (&sig_set); // Start of protection  
  7.     // Protected Code.  
  8.     // Can't interrupt by signals in sig_set  
  9. //End of protection  
在保护代码执行的过程中,如果sig_set中的信号被递送,则只有保护代码执行完,才回调信号中断处理函数。



ACE SIGPIPE 问题


######################


屏蔽SIGPIPE

方法1

// Ensure an error, not a signal, on broken pipe.
  ACE_Sig_Action no_sigpipe ((ACE_SignalHandler) SIG_IGN);
  ACE_Sig_Action original_action;
  no_sigpipe.register_action (SIGPIPE, &original_action);

.................
.................

no_sigpipe.restore_action (SIGPIPE, original_action); 


方法2



// Ignore SIGPIPE so that each <SVC_HANDLER> can handle this on its own.
  ACE_Sig_Action sig ((ACE_SignalHandler) SIG_IGN, SIGPIPE);
  ACE_UNUSED_ARG (sig);



捕捉SIGSEGV信号

代码如下:
#include "ace/Stack_Trace.h"

//注册信号
        ACE_Sig_Set sig_set;
   sig_set.sig_add(SIGINT);
   sig_set.sig_add(SIGQUIT);
   sig_set.sig_add(SIGSEGV);
   ACE_Sig_Action sig ((ACE_SignalHandler) SIG_IGN, SIGPIPE); //这个是socket break信号,忽略处理
   ACE_UNUSED_ARG (sig);
   if (ACE_Reactor::instance()->register_handler(sig_set, this) == -1)
     ACE_ERROR_RETURN((LM_ERROR,
                       ACE_TEXT("%p\n"),
                       ACE_TEXT("register_handler")),
                       -1);

      ...

对应信号处理:
  int
 XXX::handle_signal(int signum, siginfo_t *,ucontext_t *)
 {
   if( SIGSEGV == signum ){
     ACE_Stack_Trace st;
     ACE_DEBUG((LM_DEBUG,ACE_TEXT("(%P|%D) stack : \n%s\n"), st.c_str()));
     ACE_Sig_Set sig_set;
     sig_set.sig_add(SIGSEGV);
     ACE_Reactor::instance()->remove_handler(sig_set);
   } 
   ACE_Reactor::end_event_loop();
   
   ACE_DEBUG((LM_DEBUG,ACE_TEXT("(%P|%D) end event loop\n")));
   return 0;
 } 



使用handle_signal 信号捕捉函数

signalhand.h

#include "ace/Basic_Types.h"
#include "ace/Signal.h"


/*************************************************
Class: CSignalHandlerImpl
Description: 信号量处理类实现
*************************************************/
class CSignalHandler : public ACE_Event_Handler
{
public:
    CSignalHandler();
    virtual ~CSignalHandler();


public:
    ACE_INT32 Init();//初始化
    ACE_INT32 Exit();


public:
    virtual ACE_INT32 handle_signal (ACE_INT32 signum, siginfo_t * = 0, ucontext_t * = 0); //实现这个回调函数


private:
    ACE_Sig_Action no_sigpipe;
};


signalhand.cpp




/*************************************************
Function:         initial
Description:     初始化函数,进行信号量注册
*************************************************/
ACE_INT32 CSignalHandler::Init()
{
    CAppManager::Instance()->GetReactor().register_handler(SIGHUP, this);
    CAppManager::Instance()->GetReactor().register_handler(SIGINT, this);
    CAppManager::Instance()->GetReactor().register_handler(SIGABRT, this);
    CAppManager::Instance()->GetReactor().register_handler(SIGALRM, this);
    CAppManager::Instance()->GetReactor().register_handler(SIGUSR1, this);
    CAppManager::Instance()->GetReactor().register_handler(SIGUSR2, this);
#ifndef ACE_CONFIG_WIN32_H
    CAppManager::Instance()->GetReactor().register_handler(SIGPOLL, this);
    CAppManager::Instance()->GetReactor().register_handler(SIGVTALRM, this);
    CAppManager::Instance()->GetReactor().register_handler(SIGPROF, this);
#endif
    CAppManager::Instance()->GetReactor().register_handler(SIGCLD, this);
    CAppManager::Instance()->GetReactor().register_handler(SIGTERM, this);
    CAppManager::Instance()->GetReactor().register_handler(SIGCHLD, this);
    CAppManager::Instance()->GetReactor().register_handler(SIGIO, this);


    no_sigpipe.register_action (SIGPIPE, NULL);


    return 0;
}




/*************************************************
Function:         handle_signal
Description:     系统回调函数,这里不对信号量
                进行处理,只是进行标志位置位
                然后唤醒信号量处理线程进行处理
*************************************************/
ACE_INT32 CSignalHandler::handle_signal (ACE_INT32 signum, siginfo_t * , ucontext_t *)
{
    ACE_Sig_Set sigs;


    sigs.sig_add (SIGHUP);
    sigs.sig_add (SIGINT);
    sigs.sig_add (SIGABRT);
    sigs.sig_add (SIGALRM);
    sigs.sig_add (SIGUSR1);
    sigs.sig_add (SIGUSR2);
    sigs.sig_add (SIGCLD);
    sigs.sig_add (SIGTERM);
    sigs.sig_add (SIGCHLD);
    sigs.sig_add (SIGIO);


#ifndef ACE_CONFIG_WIN32_H
    sigs.sig_add (SIGPOLL);
    sigs.sig_add (SIGVTALRM);
    sigs.sig_add (SIGPROF);
#endif


    ACE_Sig_Guard guard (&sigs);


    if (SIGINT == signum || SIGTERM == signum)
    {
    //会检测并退出系统的
    }
    else if (SIGUSR1 == signum)
    {
        // 自定义处理线程处理
    }


    return 0;
}


参考:

http://www.riverace.com/newsletters/February2008.htm

http://blog.csdn.net/htf15/article/details/7594963

http://www.dre.vanderbilt.edu/~schmidt/DOC_ROOT/ACE/examples/C++NPv2/Client_Logging_Daemon.cpp

http://blog.csdn.net/projecinfo/article/details/393124

http://www.acejoy.com/ace/thread-4361-1-1.html

ftp://ftp.radiomaryja.pl.eu.org/vol/rzm1/ace/dummy_dir/ACE_wrappers/examples/C++NPv2/AIO_Client_Logging_Daemon.cpp

http://binders.cgm.ucdavis.edu/Rays%20documents%20need%20to%20file/Centrifuge/Robot/ACE_wrappers/examples/OS/Process/imore.cpp

http://www.44342.com/ace-f1160-t16199-p1.htm

http://fehead.tistory.com/146

猜你喜欢

转载自blog.csdn.net/yangyangye/article/details/42583337
ACE
今日推荐