E-MailRelay

gfutureevent_unix.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2021 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 "gmsg.h"
24#include "geventloop.h"
25#include <array>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <fcntl.h>
29
30//| \class GNet::FutureEventImp
31/// A pimple-pattern implementation class used by GNet::FutureEvent.
32///
33 class GNet::FutureEventImp : public EventHandler
34{
35 public:
36 using handle_type = FutureEvent::handle_type ;
37
38 FutureEventImp( FutureEventHandler & , ExceptionSink ) ;
39 // Constructor.
40
41 ~FutureEventImp() override ;
42 // Destructor.
43
44 static bool send( handle_type , bool ) noexcept ;
45 // Writes to the write socket.
46
47 void receive() ;
48 // Reads from the socket to clear the event.
49
50 handle_type handle() noexcept ;
51 // Extracts the socket fd as a handle.
52
53 public:
54 FutureEventImp( const FutureEventImp & ) = delete ;
55 FutureEventImp( FutureEventImp && ) = delete ;
56 void operator=( const FutureEventImp & ) = delete ;
57 void operator=( FutureEventImp && ) = delete ;
58
59 private: // overrides
60 void readEvent() override ; // Override from GNet::EventHandler.
61
62 private:
63 static int init( int ) ;
64
65 private:
66 struct Fd
67 {
68 Fd() = default;
69 ~Fd() { if(fd!=-1) ::close(fd) ; }
70 Fd & operator=( int fd_ ) { fd = fd_ ; return *this ; }
71 int fd{-1} ;
72 Fd( const Fd & ) = delete ;
73 Fd( Fd && ) = delete ;
74 void operator=( const Fd & ) = delete ;
75 void operator=( Fd && ) = delete ;
76 } ;
77
78 private:
79 FutureEventHandler & m_handler ;
80 Fd m_read ;
81 Fd m_write ;
82 bool m_triggered ;
83} ;
84
85GNet::FutureEventImp::FutureEventImp( FutureEventHandler & handler , ExceptionSink es ) :
86 m_handler(handler) ,
87 m_triggered(false)
88{
89 std::array<int,2U> fds {{ -1 , -1 }} ;
90 int rc = ::socketpair( AF_UNIX , SOCK_DGRAM , 0 , &fds[0] ) ;
91 if( rc != 0 )
92 throw FutureEvent::Error( "socketpair" ) ;
93 m_read = init( fds[0] ) ;
94 m_write = init( fds[1] ) ;
95 EventLoop::instance().addRead( Descriptor(m_read.fd) , *this , es ) ;
96}
97
98 int GNet::FutureEventImp::init( int fd )
99{
100 GDEF_IGNORE_RETURN ::fcntl( fd , F_SETFL , ::fcntl(fd,F_GETFL) | O_NONBLOCK ) ;
101 return fd ;
102}
103
104GNet::FutureEventImp::~FutureEventImp()
105{
106 if( m_read.fd >= 0 )
107 {
108 if( EventLoop::exists() )
109 EventLoop::instance().dropRead( Descriptor(m_read.fd) ) ;
110 }
111}
112
113GNet::FutureEventImp::handle_type GNet::FutureEventImp::handle() noexcept
114{
115 int fd = -1 ;
116 std::swap( m_write.fd , fd ) ;
117 return static_cast<handle_type>(fd) ;
118}
119
120 void GNet::FutureEventImp::receive()
121{
122 char c = '\0' ;
123 GDEF_IGNORE_RETURN ::recv( m_read.fd , &c , 1 , 0 ) ;
124}
125
126 bool GNet::FutureEventImp::send( handle_type handle , bool close ) noexcept
127{
128 int fd = static_cast<int>(handle) ;
129 char c = '\0' ;
130 ssize_t rc = G::Msg::send( fd , &c , 1 , 0 ) ;
131 if( close )
132 ::close( fd ) ; // just after send() is okay
133 const bool ok = rc == 1 ;
134 return ok ;
135}
136
137 void GNet::FutureEventImp::readEvent()
138{
139 receive() ;
140 if( !m_triggered )
141 {
142 m_triggered = true ;
143 m_handler.onFutureEvent() ;
144 }
145}
146
147// ==
148
149 GNet::FutureEvent::FutureEvent( FutureEventHandler & handler , ExceptionSink es ) :
150 m_imp(std::make_unique<FutureEventImp>(handler,es))
151{
152}
153
154 GNet::FutureEvent::~FutureEvent()
155= default ;
156
157 bool GNet::FutureEvent::send( handle_type handle , bool close ) noexcept
158{
159 return FutureEventImp::send( handle , close ) ;
160}
161
162GNet::FutureEvent::handle_type GNet::FutureEvent::handle() noexcept
163{
164 return m_imp->handle() ;
165}
166
GNet::EventHandler
A base class for classes that handle asynchronous events from the event loop.
Definition: geventhandler.h:48
GNet::EventLoop::dropRead
virtual void dropRead(Descriptor fd) noexcept=0
Removes the given event source descriptor from the list of read sources.
GNet::EventLoop::exists
static bool exists()
Returns true if an instance exists.
Definition: geventloop.cpp:54
GNet::EventLoop::instance
static EventLoop & instance()
Returns a reference to an instance of the class, if any.
Definition: geventloop.cpp:47
GNet::EventLoop::addRead
virtual void addRead(Descriptor fd, EventHandler &, ExceptionSink)=0
Adds the given event source descriptor and associated handler to the read list.
GNet::ExceptionSink
A tuple containing an ExceptionHandler interface pointer and a bound 'exception source' pointer.
Definition: gexceptionsink.h:100
GNet::FutureEventHandler
A callback interface for GNet::FutureEvent.
Definition: gfutureevent.h:113
GNet::FutureEventImp
A pimple-pattern implementation class used by GNet::FutureEvent.
Definition: gfutureevent_unix.cpp:34
GNet::FutureEvent::FutureEvent
FutureEvent(FutureEventHandler &, ExceptionSink)
Constructor. Installs itself in the event loop.
Definition: gfutureevent_unix.cpp:149
GNet::FutureEvent::handle
handle_type handle() noexcept
Extracts a handle that can be passed between threads and used in send().
Definition: gfutureevent_unix.cpp:162
GNet::FutureEvent::send
static bool send(handle_type handle, bool close=true) noexcept
Pokes an event into the main event loop so that the FutureEventHandler callback is called asynchronou...
Definition: gfutureevent_unix.cpp:157
GNet::FutureEvent::~FutureEvent
~FutureEvent()
Destructor.
G::Msg::send
static ssize_t send(SOCKET, const void *, std::size_t, int flags) noexcept
A send() replacement using sendmsg().
Definition: gmsg_unix.cpp:34
geventloop.h
gfutureevent.h
gmsg.h