VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gfatpipe.h
Go to the documentation of this file.
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 /// \file gfatpipe.h
19 ///
20 
21 #ifndef G_FAT_PIPE__H
22 #define G_FAT_PIPE__H
23 
24 #include "gdef.h"
25 #include "gsharedmemory.h"
26 #include "gsemaphore.h"
27 #include "gdatetime.h"
28 #include "gsignalsafe.h"
29 #include "gexception.h"
30 #include <string>
31 #include <vector>
32 #include <utility>
33 
34 namespace G
35 {
36  class FatPipe ;
37  class FatPipeReceiver ;
38 }
39 
40 /// \class G::FatPipe
41 /// A one-way, unreliable-datagram communication channel from a parent process
42 /// to a child process, using shared memory. Update events are sent from the
43 /// parent process via an inherited non-blocking file descriptor. The
44 /// shared memory file descriptor and the event file descriptor are typically
45 /// passed to the child process via its command-line.
46 /// \code
47 ///
48 /// // writer...
49 /// FatPipe fat_pipe ;
50 /// if( fork() == 0 )
51 /// {
52 /// fat_pipe.doChild() ;
53 /// execl( "/bin/child" , "/bin/child" ,
54 /// fat_pipe.shmemfd() , fat_pipe.pipefd() , nullptr ) ;
55 /// _exit( 1 ) ;
56 /// }
57 /// fat_pipe.doParent()
58 /// fat_pipe.send( p , n ) ;
59 ///
60 /// // reader...
61 /// FatPipe::Receiver rx( shmem_fd , pipe_fd ) ;
62 /// vector<char> buffer ;
63 /// while( FatPipe::wait(rx.fd()) )
64 /// rx.receive( buffer ) ;
65 /// \endcode
66 ///
67 /// The implementation actuall uses two shared memory segments; a fixed size
68 /// control segment containing a mutex, and a data segment that is resized as
69 /// necessary. They are unlinked from the file system as soon as they are
70 /// created, so they are almost never visible.
71 ///
72 /// A socketpair() pipe is used for the data-available event signalling.
73 ///
74 /// The child process typically obtains the control segment's file descriptor
75 /// from its command-line, whereas the data segment's file descriptor is
76 /// passed over the event pipe.
77 ///
79 {
80 public:
81  G_EXCEPTION( Error , "fat pipe error" ) ;
82  typedef FatPipeReceiver Receiver ;
83 
84  FatPipe() ;
85  ///< Constructor.
86 
87  ~FatPipe() ;
88  ///< Destructor.
89 
90  void doParent( bool auto_cleanup = true ) ;
91  ///< To be called from the parent process after fork().
92 
93  void doChild() ;
94  ///< To be called from the child process after fork().
95 
96  void send( const char * data , size_t size , const char * type = nullptr ) ;
97  ///< Sends a chunk of data to the child process. This will block in sendmsg() on
98  ///< first use or if the shared memory is grown in order to transfer the data fd.
99 
100  void send( const std::vector<char> & data , const char * type = nullptr ) ;
101  ///< Sends a chunk of data to the child process. This will block in sendmsg() on
102  ///< first use or if the shared memory is grown in order to transfer the data fd.
103 
104  void send( const std::vector<std::pair<const char *,size_t> > & data , const char * type = nullptr ) ;
105  ///< Sends a segmented data to the child process. This will block in sendmsg() on
106  ///< first use or if the shared memory is grown in order to transfer the data fd.
107 
108  void send( const std::vector<std::vector<char> > & data , const char * type = nullptr ) ;
109  ///< Sends chunked data to the child process. This will block in sendmsg() on
110  ///< first use or if the shared memory is grown in order to transfer the data fd.
111 
112  bool ping() ;
113  ///< Returns true if the receiver seems to be there.
114 
115  const char * shmemfd() const ;
116  ///< Returns the shared memory file descriptor as a string pointer (suitable
117  ///< for exec()).
118 
119  const char * pipefd() const ;
120  ///< Returns the pipe file descriptor as a string pointer (suitable for exec()).
121 
122 public:
123  struct DataMemory /// Shared memory structure for G::FatPipe.
124  {
125  enum { MAGIC = 0xbeef } ;
126  int magic ;
127  char type[60] ;
128  time_t time_s ;
129  g_uint32_t time_us ;
130  size_t data_size ;
131  char data[1] ;
132  } ;
133  struct ControlMemory /// Shared memory structure for G::FatPipe.
134  {
135  enum { MAGIC = 0xdead } ;
136  int magic ;
138  } ;
139  struct Lock /// RAII class to lock the G::FatPipe control segment.
140  {
141  explicit Lock( G::Semaphore * s ) ;
142  ~Lock() ;
143  G::Semaphore * m_s ;
144  } ;
145 
146 private:
147  FatPipe( const FatPipe & ) ;
148  void operator=( const FatPipe & ) ;
149  static size_t sensible( size_t ) ;
150  static std::string name() ;
151  static std::string name( size_t ) ;
152  static std::string tostring( int ) ;
153  static void close_( int ) ;
154  static void cleanup( G::SignalSafe , const char * ) ;
155  void send( size_t , size_t , const char ** , size_t * , const char * type ) ;
156 
157 private:
158  bool m_child ;
159  bool m_parent ;
160  G::SharedMemory m_shmem ;
161  unique_ptr<G::SharedMemory> m_shmem_data ;
162  int m_pipe_fds[2] ;
163  int m_pipe_fd ;
164  std::string m_arg_shmemfd ;
165  std::string m_arg_pipefd ;
166  int m_new_data_fd ;
167  std::vector<const char*> m_data_p ;
168  std::vector<size_t> m_data_n ;
169 } ;
170 
171 /// \class G::FatPipeReceiver
172 /// A class to read a fat pipe in the child process.
173 ///
175 {
176 public:
177  FatPipeReceiver( int shmem_fd , int pipe_fd ) ;
178  ///< Constructor.
179 
180  bool receive( std::vector<char> & buffer , std::string * type_p = nullptr , G::EpochTime * = nullptr ) ;
181  ///< Reads a message from the fat pipe's shared memory into the
182  ///< supplied buffer.
183  ///<
184  ///< This is used in the child process, with the file descriptors
185  ///< inherited from the parent. The pipe fd must be non-blocking
186  ///< and it must have a pending read event (see wait()).
187  ///<
188  ///< If the read event should be ignored then an empty buffer is
189  ///< returned. Throws on error, but returns false if the pipe breaks.
190 
191  int pipefd() const ;
192  ///< Returns the pipe fd.
193 
194  static void wait( int pipe_fd ) ;
195  ///< A convenience function that sets the pipe fd to be non-blocking
196  ///< and does a non-multiplexed wait for a read event.
197 
198 private:
199  typedef FatPipe::Error Error ;
202  typedef FatPipe::Lock Lock ;
203  FatPipeReceiver( const FatPipeReceiver & ) ;
204  void operator=( const FatPipeReceiver & ) ;
205  static void copy( SharedMemory & , SharedMemory & , std::vector<char> & , std::string * , G::EpochTime * ) ;
206  struct Info { bool got_data ; bool got_eof ; int data_fd ; } ;
207  static Info flush( int pipe_fd ) ;
208 
209 private:
210  int m_pipe_fd ;
211  SharedMemory m_shmem ;
212  unique_ptr<SharedMemory> m_shmem_data ;
213 } ;
214 
215 #endif
A subsecond-resolution timestamp based on a time_t.
Definition: gdatetime.h:39
int pipefd() const
Returns the pipe fd.
Definition: gfatpipe.cpp:281
An empty structure that is used to indicate a signal-safe, reentrant implementation.
Definition: gsignalsafe.h:36
void send(const char *data, size_t size, const char *type=nullptr)
Sends a chunk of data to the child process.
Definition: gfatpipe.cpp:155
Shared memory structure for G::FatPipe.
Definition: gfatpipe.h:123
void doChild()
To be called from the child process after fork().
Definition: gfatpipe.cpp:103
const char * pipefd() const
Returns the pipe file descriptor as a string pointer (suitable for exec()).
Definition: gfatpipe.cpp:130
RAII class to lock the G::FatPipe control segment.
Definition: gfatpipe.h:139
FatPipe()
Constructor.
Definition: gfatpipe.cpp:57
~FatPipe()
Destructor.
Definition: gfatpipe.cpp:75
A semaphore class with a posix or sysv implementation chosen at build-time.
Definition: gsemaphore.h:47
const char * shmemfd() const
Returns the shared memory file descriptor as a string pointer (suitable for exec()).
Definition: gfatpipe.cpp:135
void doParent(bool auto_cleanup=true)
To be called from the parent process after fork().
Definition: gfatpipe.cpp:140
A POSIX shared memory class.
Definition: gsharedmemory.h:41
Shared memory structure for G::FatPipe.
Definition: gfatpipe.h:133
static void wait(int pipe_fd)
A convenience function that sets the pipe fd to be non-blocking and does a non-multiplexed wait for a...
Definition: gfatpipe.cpp:377
A class to read a fat pipe in the child process.
Definition: gfatpipe.h:174
FatPipeReceiver(int shmem_fd, int pipe_fd)
Constructor.
Definition: gfatpipe.cpp:275
bool receive(std::vector< char > &buffer, std::string *type_p=nullptr, G::EpochTime *=nullptr)
Reads a message from the fat pipe's shared memory into the supplied buffer.
Definition: gfatpipe.cpp:315
bool ping()
Returns true if the receiver seems to be there.
Definition: gfatpipe.cpp:266
semaphore storage
Definition: gsemaphore.h:51
A one-way, unreliable-datagram communication channel from a parent process to a child process...
Definition: gfatpipe.h:78