E-MailRelay
gfutureevent_unix.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2023 Graeme Walker <graeme_walker@users.sourceforge.net>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16// ===
17///
18/// \file gfutureevent_unix.cpp
19///
20
21#include "gdef.h"
22#include "gfutureevent.h"
23#include "gprocess.h"
24#include "gmsg.h"
25#include "geventloop.h"
26#include <array>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <fcntl.h>
30
31//| \class GNet::FutureEventImp
32/// A pimple-pattern implementation class used by GNet::FutureEvent.
33///
34class GNet::FutureEventImp : public EventHandler
35{
36public:
37 FutureEventImp( FutureEventHandler & , ExceptionSink ) ;
38 // Constructor.
39
40 ~FutureEventImp() override ;
41 // Destructor.
42
43 static bool send( HANDLE , bool ) noexcept ;
44 // Writes to the write socket.
45
46 void receive() ;
47 // Reads from the socket to clear the event.
48
49 HANDLE handle() noexcept ;
50 // Extracts the socket fd as a handle.
51
52public:
53 FutureEventImp( const FutureEventImp & ) = delete ;
54 FutureEventImp( FutureEventImp && ) = delete ;
55 FutureEventImp & operator=( const FutureEventImp & ) = delete ;
56 FutureEventImp & operator=( FutureEventImp && ) = delete ;
57
58private: // overrides
59 void readEvent() override ; // Override from GNet::EventHandler.
60
61private:
62 static int init( int ) ;
63
64private:
65 struct Fd
66 {
67 Fd() = default;
68 ~Fd() { if(fd!=-1) ::close(fd) ; }
69 Fd & operator=( int fd_ ) { fd = fd_ ; return *this ; }
70 int fd{-1} ;
71 Fd( const Fd & ) = delete ;
72 Fd( Fd && ) = delete ;
73 Fd & operator=( const Fd & ) = delete ;
74 Fd & operator=( Fd && ) = delete ;
75 } ;
76
77private:
78 FutureEventHandler & m_handler ;
79 Fd m_read ;
80 Fd m_write ;
81 bool m_triggered ;
82} ;
83
84GNet::FutureEventImp::FutureEventImp( FutureEventHandler & handler , ExceptionSink es ) :
85 m_handler(handler) ,
86 m_triggered(false)
87{
88 std::array<int,2U> fds {{ -1 , -1 }} ;
89 int rc = ::socketpair( AF_UNIX , SOCK_DGRAM , 0 , &fds[0] ) ;
90 if( rc != 0 )
91 {
92 int e = G::Process::errno_() ;
93 throw FutureEvent::Error( "socketpair" , G::Process::strerror(e) ) ;
94 }
95 m_read = init( fds[0] ) ;
96 m_write = init( fds[1] ) ;
97 EventLoop::instance().addRead( Descriptor(m_read.fd) , *this , es ) ;
98}
99
100int GNet::FutureEventImp::init( int fd )
101{
102 GDEF_IGNORE_RETURN ::fcntl( fd , F_SETFL , ::fcntl(fd,F_GETFL) | O_NONBLOCK ) ; // NOLINT
103 return fd ;
104}
105
106GNet::FutureEventImp::~FutureEventImp()
107{
108 if( m_read.fd >= 0 )
109 {
110 if( EventLoop::exists() )
111 EventLoop::instance().dropRead( Descriptor(m_read.fd) ) ;
112 }
113}
114
115HANDLE GNet::FutureEventImp::handle() noexcept
116{
117 int fd = -1 ;
118 std::swap( m_write.fd , fd ) ;
119 return static_cast<HANDLE>(fd) ;
120}
121
122void GNet::FutureEventImp::receive()
123{
124 char c = '\0' ;
125 GDEF_IGNORE_RETURN ::recv( m_read.fd , &c , 1 , 0 ) ;
126}
127
128bool GNet::FutureEventImp::send( HANDLE handle , bool close ) noexcept
129{
130 int fd = static_cast<int>(handle) ;
131 char c = '\0' ;
132 ssize_t rc = G::Msg::send( fd , &c , 1 , 0 ) ;
133 if( close )
134 ::close( fd ) ; // just after send() is okay
135 const bool ok = rc == 1 ;
136 return ok ;
137}
138
140{
141 receive() ;
142 if( !m_triggered )
143 {
144 m_triggered = true ;
145 m_handler.onFutureEvent() ;
146 }
147}
148
149// ==
150
152 m_imp(std::make_unique<FutureEventImp>(handler,es))
153{
154}
155
157= default ;
158
159bool GNet::FutureEvent::send( HANDLE handle , bool close ) noexcept
160{
161 return FutureEventImp::send( handle , close ) ;
162}
163
165{
166 return m_imp->handle() ;
167}
168
virtual void readEvent()
Called for a read event.
A tuple containing an ExceptionHandler interface pointer and a bound 'exception source' pointer.
A callback interface for GNet::FutureEvent.
Definition: gfutureevent.h:126
FutureEvent(FutureEventHandler &, ExceptionSink)
Constructor. Installs itself in the event loop.
static bool send(HANDLE handle, bool close=true) noexcept
Pokes an event into the main event loop so that the FutureEventHandler callback is called asynchronou...
HANDLE handle() noexcept
Extracts a handle that can be passed between threads and used in send().
~FutureEvent()
Destructor.
static ssize_t send(SOCKET, const void *, std::size_t, int flags) noexcept
A send() wrapper.
Definition: gmsg_mac.cpp:27
static std::string strerror(int errno_)
Translates an 'errno' value into a meaningful diagnostic string.
static int errno_(const SignalSafe &=G::SignalSafe()) noexcept
Returns the process's current 'errno' value.
STL namespace.