VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gfutureevent_unix.cpp
1 //
2 // Copyright (C) 2017 Graeme Walker
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 "gnet.h"
23 #include "gfutureevent.h"
24 #include "gmsg.h"
25 #include "geventloop.h"
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 ///
34 {
35 public:
36  typedef FutureEvent::Error Error ;
37  typedef FutureEvent::handle_type handle_type ;
38 
39  explicit FutureEventImp( FutureEventHandler & handler ) ;
40  // Constructor.
41 
42  virtual ~FutureEventImp() ;
43  // Destructor.
44 
45  unsigned int receive() ;
46  // Reads from the read socket.
47 
48  static bool send( handle_type , unsigned int ) g__noexcept ;
49  // Writes to the write socket.
50 
51  handle_type handle() const ;
52  // Returns the socket fd as a handle.
53 
54 private:
55  FutureEventImp( const FutureEventImp & ) ;
56  void operator=( const FutureEventImp & ) ;
57  static int init( int ) ;
58  virtual void readEvent() ; // Override from GNet::EventHandler.
59  virtual void onException( std::exception & ) ; // Override from GNet::EventExceptionHandler.
60 
61 private:
62  FutureEventHandler & m_handler ;
63  int m_fd_read ;
64  int m_fd_write ;
65 } ;
66 
67 GNet::FutureEventImp::FutureEventImp( FutureEventHandler & handler ) :
68  m_handler(handler) ,
69  m_fd_read(-1) ,
70  m_fd_write(-1)
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 ) ;
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() ) // (in case we're in the process's last gasp)
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() const
102 {
103  return static_cast<handle_type>(m_fd_write) ;
104 }
105 
106 unsigned int GNet::FutureEventImp::receive()
107 {
108  char c = 0 ;
109  ssize_t rc = ::recv( m_fd_read , &c , 1 , 0 ) ;
110  if( rc != 1 )
111  throw Error("recv") ;
112  return static_cast<unsigned int>(c) ;
113 }
114 
115 bool GNet::FutureEventImp::send( handle_type handle , unsigned int payload ) g__noexcept
116 {
117  int fd = static_cast<int>(handle) ;
118  char c = static_cast<char>(payload) ;
119  ssize_t rc = G::Msg::send( fd , &c , 1 , 0 ) ;
120  const bool ok = rc == 1 ;
121  return ok ;
122 }
123 
124 void GNet::FutureEventImp::readEvent()
125 {
126  m_handler.onFutureEvent( receive() ) ;
127 }
128 
129 void GNet::FutureEventImp::onException( std::exception & e )
130 {
131  m_handler.onException( e ) ;
132 }
133 
134 // ==
135 
137  m_imp(new FutureEventImp(handler))
138 {
139 }
140 
142 {
143 }
144 
145 bool GNet::FutureEvent::send( handle_type handle , unsigned int payload ) g__noexcept
146 {
147  return FutureEventImp::send( handle , payload ) ;
148 }
149 
150 GNet::FutureEvent::handle_type GNet::FutureEvent::handle() const
151 {
152  return m_imp->handle() ;
153 }
154 
155 // ==
156 
158 {
159 }
160 
A callback interface for GNet::FutureEvent.
Definition: gfutureevent.h:95
handle_type handle() const
Returns a handle that can be passed between threads and used in send().
static ssize_t send(int, const void *, size_t, int, int fd_to_send=-1)
A send() replacement using sendmsg().
Definition: gmsg.cpp:32
virtual void dropRead(Descriptor fd)=0
Removes the given event source descriptor from the list of read sources.
~FutureEvent()
Destructor.
A class that encapsulates a network file descriptor and hides knowledge of its o/s-spefific error val...
Definition: gdescriptor.h:37
virtual void addRead(Descriptor fd, EventHandler &handler)=0
Adds the given event source descriptor and associated handler to the read list.
FutureEvent(FutureEventHandler &)
Constructor.
A base class for classes that handle asynchronous events from the event loop.
Definition: geventhandler.h:78
virtual ~FutureEventHandler()
Destructor.
A pimple-pattern implementation class used by GNet::FutureEvent.
static bool exists()
Returns true if an instance exists.
Definition: geventloop.cpp:51
static bool send(handle_type handle, unsigned int payload) g__noexcept
Pokes the event payload into the main event loop so that the callback is called once the stack is unw...
static EventLoop & instance()
Returns a reference to an instance of the class, if any.
Definition: geventloop.cpp:43