E-MailRelay

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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