184 lines
3.8 KiB
C++
184 lines
3.8 KiB
C++
/*
|
|
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
|
*
|
|
* Author : Bruce Liang
|
|
* Website : https://github.com/ldcsaa
|
|
* Project : https://github.com/ldcsaa/HP-Socket
|
|
* Blog : http://www.cnblogs.com/ldcsaa
|
|
* Wiki : http://www.oschina.net/p/hp-socket
|
|
* QQ Group : 44636872, 75375912
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "hpsocket/GlobalDef.h"
|
|
#include "Thread.h"
|
|
|
|
#include <signal.h>
|
|
|
|
#include <memory>
|
|
|
|
using namespace std;
|
|
|
|
template<class T> class CSignalHandler
|
|
{
|
|
public:
|
|
using MT = CSignalHandler<T>;
|
|
using SI = siginfo_t;
|
|
using SS = sigset_t;
|
|
using CHandlerThread = CThread<MT, const SS, VOID>;
|
|
using F = VOID (T::*)(const SI*);
|
|
using SF = VOID (*)(const SI*);
|
|
using SSPTR = unique_ptr<SS>;
|
|
friend CHandlerThread;
|
|
|
|
public:
|
|
|
|
BOOL Setup(SF pFunc, const SS* pSigSet, BOOL bRestorOnCancel = TRUE)
|
|
{
|
|
return Setup((__CFakeRunnerClass_*)nullptr, *(F*)&pFunc, pSigSet, bRestorOnCancel);
|
|
}
|
|
|
|
BOOL Setup(T* pRunner, F pFunc, const SS* pSigSet, BOOL bRestorOnCancel = TRUE)
|
|
{
|
|
ASSERT_CHECK_EINVAL(pSigSet != nullptr);
|
|
|
|
m_pssPre = make_unique<SS>();
|
|
int rs = pthread_sigmask(SIG_BLOCK, pSigSet, m_pssPre.get());
|
|
|
|
if(rs != NO_ERROR)
|
|
{
|
|
m_pssPre = nullptr;
|
|
::SetLastError(rs);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
m_pRunner = pRunner;
|
|
m_pFunc = pFunc;
|
|
m_pssCur = make_unique<SS>();
|
|
|
|
::CopyPlainObject(m_pssCur.get(), pSigSet);
|
|
|
|
BOOL isOK = m_thHandler.Start(this, &MT::ThreadFunc, m_pssCur.get());
|
|
|
|
if(isOK && !bRestorOnCancel)
|
|
m_pssPre = nullptr;
|
|
else if(!isOK)
|
|
EXECUTE_RESTORE_ERROR(Reset());
|
|
|
|
return isOK;
|
|
}
|
|
|
|
BOOL Cancel()
|
|
{
|
|
BOOL isOK = m_thHandler.IsRunning();
|
|
|
|
if(isOK)
|
|
{
|
|
isOK = m_thHandler.Interrupt();
|
|
isOK &= m_thHandler.Join();
|
|
}
|
|
|
|
isOK &= Reset();
|
|
|
|
return isOK;
|
|
}
|
|
|
|
BOOL IsRunning () {return m_thHandler.IsRunning();}
|
|
T* GetRunner () {return m_pRunner;}
|
|
F GetFunc () {return m_pFunc;}
|
|
SF GetSFunc () {return *(SF*)&m_pFunc;}
|
|
THR_ID GetThreadID () {return m_thHandler.GetThreadID();}
|
|
NTHR_ID GetNativeID () {return m_thHandler.GetNativeID();}
|
|
|
|
|
|
private:
|
|
VOID ThreadFunc(const SS* pSigSet)
|
|
{
|
|
ASSERT(pSigSet == m_pssCur.get());
|
|
|
|
SI si;
|
|
|
|
ZeroObject(si);
|
|
|
|
while(!::IsThreadInterrupted())
|
|
{
|
|
#if !defined(__ANDROID__)
|
|
int rs = NO_EINTR_EXCEPT_THR_INTR_INT(sigwaitinfo(pSigSet, &si));
|
|
#else
|
|
int rs = NO_EINTR_EXCEPT_THR_INTR_INT(sigwait(pSigSet, &si.si_signo));
|
|
#endif
|
|
|
|
if(IS_HAS_ERROR(rs))
|
|
{
|
|
if(IS_ERROR(EINTR))
|
|
{
|
|
ASSERT(::IsThreadInterrupted());
|
|
break;
|
|
}
|
|
|
|
ERROR_ABORT();
|
|
}
|
|
|
|
Run((T*)nullptr, &si);
|
|
}
|
|
}
|
|
|
|
template<typename T_, typename = enable_if_t<!is_same<T_, __CFakeRunnerClass_>::value>>
|
|
VOID Run(T_*, const SI* pSigSet) {(m_pRunner->*m_pFunc)(pSigSet);}
|
|
|
|
VOID Run(__CFakeRunnerClass_*, const SI* pSigSet) {(*(SF*)&m_pFunc)(pSigSet);}
|
|
|
|
|
|
BOOL Reset()
|
|
{
|
|
BOOL isOK = TRUE;
|
|
|
|
if(m_pssPre)
|
|
{
|
|
isOK = (pthread_sigmask(SIG_SETMASK, m_pssPre.get(), nullptr) == NO_ERROR);
|
|
m_pssPre = nullptr;
|
|
}
|
|
|
|
m_pssCur = nullptr;
|
|
m_pRunner = nullptr;
|
|
m_pFunc = nullptr;
|
|
|
|
return isOK;
|
|
}
|
|
|
|
public:
|
|
CSignalHandler()
|
|
{
|
|
}
|
|
|
|
virtual ~CSignalHandler()
|
|
{
|
|
Cancel();
|
|
}
|
|
|
|
DECLARE_NO_COPY_CLASS(CSignalHandler)
|
|
|
|
private:
|
|
T* m_pRunner;
|
|
F m_pFunc;
|
|
SSPTR m_pssCur;
|
|
SSPTR m_pssPre;
|
|
CHandlerThread m_thHandler;
|
|
};
|
|
|
|
using CStaticSignalHandler = CSignalHandler<__CFakeRunnerClass_>;
|