/* * 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 "Singleton.h" #include "FuncHelper.h" #include "PollHelper.h" #include #include #include #include #include #include class CPipeEvent { public: enum { EVT_1 = 0x01, EVT_WAKEUP = EVT_1, EVT_EXIT = 0x7F, EVT_SIG_0 = 0x80, EVT_SIG_MAX = EVT_SIG_0 + _NSIG, }; public: int Wait(long lTimeout = INFINITE, const sigset_t* pSigSet = nullptr) { pollfd pfd = {m_fd[0], POLLIN}; while(TRUE) { int rs = (int)::PollForSingleObject(pfd, lTimeout, pSigSet); if(rs <= TIMEOUT) return rs; if(pfd.revents & POLLIN) { BYTE v; if(!Get(v)) return HAS_ERROR; if(v == 0) continue; return (int)v; } if(pfd.revents & _POLL_ALL_ERROR_EVENTS) { ::SetLastError(ERROR_BROKEN_PIPE); return HAS_ERROR; } ASSERT(FALSE); } } BOOL Set(BYTE bVal = EVT_WAKEUP) { ASSERT_CHECK_EINVAL(bVal != 0); return VERIFY(write(m_fd[1], &bVal, 1) > 0); } BOOL Get(BYTE& v) { ASSERT(IsValid()); int rs = (int)read(m_fd[0], &v, 1); if(IS_HAS_ERROR(rs)) { if(IS_WOULDBLOCK_ERROR()) v = 0; else return FALSE; } else if(rs == 0) { ::SetLastError(ERROR_BROKEN_PIPE); return FALSE; } return TRUE; } BOOL Reset() { BYTE v; while(TRUE) { if(!Get(v)) return FALSE; if(v == 0) break; } return TRUE; } BOOL SetSignal(BYTE bSigVal) { ASSERT_CHECK_EINVAL(bSigVal > 0 && bSigVal < _NSIG); return Set((BYTE)(EVT_SIG_0 + bSigVal)); } static inline BYTE ToSignalValue(int iWaitResult) { if(iWaitResult <= EVT_SIG_0 || iWaitResult >= EVT_SIG_MAX) return 0; return (BYTE)(iWaitResult - EVT_SIG_0); } BOOL IsValid() {return IS_VALID_FD(m_fd[0]) && IS_VALID_FD(m_fd[1]);} operator FD () {return m_fd[0];} FD GetFD () {return m_fd[0];} public: CPipeEvent() { VERIFY_IS_NO_ERROR(pipe2(m_fd, O_NONBLOCK | O_CLOEXEC)); VERIFY(::fcntl_SETFL(m_fd[0], O_NOATIME)); VERIFY(::fcntl_SETFL(m_fd[1], O_NOATIME)); } ~CPipeEvent() { close(m_fd[1]); close(m_fd[0]); } DECLARE_NO_COPY_CLASS(CPipeEvent) private: FD m_fd[2] = {INVALID_FD, INVALID_FD}; }; template class CCounterEvent { public: eventfd_t Wait(long lTimeout = INFINITE, const sigset_t* pSigSet = nullptr) { pollfd pfd = {m_evt, POLLIN}; while(TRUE) { long rs = ::PollForSingleObject(pfd, lTimeout, pSigSet); if(rs <= TIMEOUT) return (eventfd_t)rs; if(pfd.revents & POLLIN) { eventfd_t v; if(!Get(v)) return HAS_ERROR; if(v == 0) continue; return v; } if(pfd.revents & _POLL_ALL_ERROR_EVENTS) { ::SetLastError(ERROR_HANDLES_CLOSED); return HAS_ERROR; } ASSERT(FALSE); } } BOOL Set(eventfd_t val = 1) { ASSERT_CHECK_EINVAL(val > 0); int rs = eventfd_write(m_evt, val); return VERIFY_IS_NO_ERROR(rs); } BOOL Get(eventfd_t& v) { ASSERT(IsValid()); if(IS_HAS_ERROR(eventfd_read(m_evt, &v))) { if(IS_WOULDBLOCK_ERROR()) v = 0; else return FALSE; } return TRUE; } BOOL Reset() { eventfd_t v; while(TRUE) { if(!Get(v)) return FALSE; if(v == 0) break; } return TRUE; } BOOL IsValid() {return IS_VALID_FD(m_evt);} operator FD () {return m_evt;} FD GetFD () {return m_evt;} public: CCounterEvent(int iInitCount = 0) { int iFlag = EFD_NONBLOCK | EFD_CLOEXEC | (is_sem_mode ? EFD_SEMAPHORE : 0); m_evt = eventfd(iInitCount, iFlag); VERIFY(IsValid()); } ~CCounterEvent() { if(IsValid()) close(m_evt); } DECLARE_NO_COPY_CLASS(CCounterEvent) private: FD m_evt = INVALID_FD; }; using CSimpleEvent = CCounterEvent; using CSemaphoreEvent = CCounterEvent; using CEvt = CSimpleEvent; class CTimerEvent { public: ULLONG Wait(long lTimeout = INFINITE, const sigset_t* pSigSet = nullptr) { pollfd pfd = {m_tmr, POLLIN}; while(TRUE) { SSIZE_T rs = ::PollForSingleObject(pfd, lTimeout, pSigSet); if(rs <= TIMEOUT) return (ULLONG)rs; if(pfd.revents & POLLIN) { BOOL ok; ULLONG v; if(!Get(v, ok)) return HAS_ERROR; if(!ok) continue; return v; } if(pfd.revents & _POLL_ALL_ERROR_EVENTS) { ::SetLastError(ERROR_HANDLES_CLOSED); return HAS_ERROR; } ASSERT(FALSE); } } BOOL Set(LLONG llInterval, LLONG llStart = -1) { ASSERT_CHECK_EINVAL(llInterval >= 0L); if(llStart < 0) llStart = llInterval; itimerspec its; ::MillisecondToTimespec(llStart, its.it_value); ::MillisecondToTimespec(llInterval, its.it_interval); int rs = timerfd_settime(m_tmr, 0, &its, nullptr); return VERIFY_IS_NO_ERROR(rs); } BOOL Get(ULLONG &v, BOOL& ok) { ASSERT(IsValid()); return ::ReadTimer(m_tmr, &v, &ok); } BOOL Reset() { BOOL ok; ULLONG v; while(TRUE) { if(!Get(v, ok)) return FALSE; if(!ok) break; } return TRUE; } BOOL GetTime(LLONG& lStart, LLONG& lInterval) { itimerspec its; if(IS_HAS_ERROR(timerfd_gettime(m_tmr, &its))) return FALSE; lStart = ::TimespecToMillisecond(its.it_value); lInterval = ::TimespecToMillisecond(its.it_interval); return TRUE; } BOOL IsValid() {return IS_VALID_FD(m_tmr);} operator FD () {return m_tmr;} FD GetFD () {return m_tmr;} public: CTimerEvent(bool bRealTimeClock = FALSE) { int iCID = (bRealTimeClock ? CLOCK_REALTIME : CLOCK_MONOTONIC); m_tmr = timerfd_create(iCID, TFD_NONBLOCK | TFD_CLOEXEC); VERIFY(IsValid()); } ~CTimerEvent() { if(IsValid()) close(m_tmr); } DECLARE_NO_COPY_CLASS(CTimerEvent) private: FD m_tmr = INVALID_FD; }; class CSignalEvent { public: int Wait(signalfd_siginfo& sgInfo, long lTimeout = INFINITE, const sigset_t* pSigSet = nullptr) { m_dwTID = SELF_THREAD_ID; pollfd pfd = {m_sig, POLLIN}; while(TRUE) { long rs = ::PollForSingleObject(pfd, lTimeout, pSigSet); if(rs <= TIMEOUT) return (int)rs; if(pfd.revents & POLLIN) { BOOL ok; if(!Get(sgInfo, ok)) return HAS_ERROR; if(!ok) continue; return sgInfo.ssi_signo; } if(pfd.revents & _POLL_ALL_ERROR_EVENTS) { ::SetLastError(ERROR_HANDLES_CLOSED); return HAS_ERROR; } ASSERT(FALSE); } m_dwTID = 0; } BOOL Set(int iSig, const sigval sgVal, THR_ID dwTID = 0) { if(dwTID == 0) { dwTID = m_dwTID; if(dwTID == 0) { ::SetLastError(ERROR_INVALID_STATE); return FALSE; } } #if !defined(__ANDROID__) int rs = pthread_sigqueue(dwTID, iSig, sgVal); #else int rs = pthread_kill(dwTID, iSig); #endif return IS_NO_ERROR(rs); } BOOL Get(signalfd_siginfo& v, BOOL& ok) { ASSERT(IsValid()); static const SSIZE_T SIZE = sizeof(signalfd_siginfo); if(read(m_sig, &v, SIZE) == SIZE) ok = TRUE; { if(IS_WOULDBLOCK_ERROR()) ok = FALSE; else return FALSE; } return ok; } BOOL Reset() { BOOL ok; signalfd_siginfo v; while(TRUE) { if(!Get(v, ok)) return FALSE; if(!ok) break; } return TRUE; } BOOL Mask(const sigset_t* pSigMask) { if(!pSigMask) { if(!IsValid()) return TRUE; return IS_NO_ERROR(close(m_sig)); } FD sig = signalfd(m_sig, pSigMask, SFD_NONBLOCK | SFD_CLOEXEC); if(IS_VALID_FD(sig)) { m_sig = sig; return TRUE; } return FALSE; } BOOL IsValid() {return IS_VALID_FD(m_sig);} operator FD () {return m_sig;} FD GetFD () {return m_sig;} public: CSignalEvent(const sigset_t* pSigMask = nullptr) { if(pSigMask) VERIFY(Mask(pSigMask)); } ~CSignalEvent() { if(IsValid()) close(m_sig); } DECLARE_NO_COPY_CLASS(CSignalEvent) private: FD m_sig = INVALID_FD; THR_ID m_dwTID = 0; };