KiCad PCB EDA Suite
ASYNC_SOCKET_HOLDER Class Reference

Spin up a thread to send messages via a socket. More...

Public Member Functions

 ASYNC_SOCKET_HOLDER ()
 
 ~ASYNC_SOCKET_HOLDER ()
 
bool Send (int aService, const std::string &aMessage)
 Attempt to send a message if the thread is available. More...
 

Private Member Functions

void worker ()
 Actual task that sends data to the socket server. More...
 

Private Attributes

std::thread m_thread
 
std::pair< int, std::string > m_message
 
bool m_messageReady
 
std::mutex m_mutex
 
std::condition_variable m_cv
 
bool m_shutdown
 

Detailed Description

Spin up a thread to send messages via a socket.

No message queuing, if a message is in flight when another is posted with Send(), the second is just dropped. This is a workaround for "non-blocking" sockets not always being non-blocking, especially on Windows. It is kept fairly simple and not exposed to the outside world because it should be replaced in a future KiCad version with a real message queue of some sort, and unified with the Kiway messaging system.

Definition at line 120 of file eda_dde.cpp.

Constructor & Destructor Documentation

◆ ASYNC_SOCKET_HOLDER()

ASYNC_SOCKET_HOLDER::ASYNC_SOCKET_HOLDER ( )
inline

Definition at line 123 of file eda_dde.cpp.

123  :
124  m_messageReady( false ),
125  m_shutdown( false )
126  {
127  // Do a dummy Connect so that wx will set up the socket stuff on the main thread, which is
128  // required even if you later make socket connections on another thread.
129  wxSocketClient* client = new wxSocketClient;
130  wxIPV4address addr;
131 
132  addr.Hostname( HOSTNAME );
133  addr.Service( KICAD_PCB_PORT_SERVICE_NUMBER );
134 
135  client->Connect( addr, false );
136 
137  client->Close();
138  client->Destroy();
139 
140  m_thread = std::thread( &ASYNC_SOCKET_HOLDER::worker, this );
141  }
#define KICAD_PCB_PORT_SERVICE_NUMBER
< Pcbnew listens on this port for commands from Eeschema
Definition: eda_dde.h:40
std::thread m_thread
Definition: eda_dde.cpp:283
static const wxString HOSTNAME(wxT("localhost"))
void worker()
Actual task that sends data to the socket server.
Definition: eda_dde.cpp:187

References HOSTNAME(), KICAD_PCB_PORT_SERVICE_NUMBER, m_thread, and worker().

◆ ~ASYNC_SOCKET_HOLDER()

ASYNC_SOCKET_HOLDER::~ASYNC_SOCKET_HOLDER ( )
inline

Definition at line 143 of file eda_dde.cpp.

144  {
145  {
146  std::lock_guard<std::mutex> lock( m_mutex );
147  m_shutdown = true;
148  }
149 
150  m_cv.notify_one();
151 
152  try
153  {
154  if( m_thread.joinable() )
155  m_thread.join();
156  }
157  catch( ... )
158  {
159  }
160  }
std::mutex m_mutex
Definition: eda_dde.cpp:286
std::thread m_thread
Definition: eda_dde.cpp:283
std::condition_variable m_cv
Definition: eda_dde.cpp:287

References m_cv, m_mutex, m_shutdown, and m_thread.

Member Function Documentation

◆ Send()

bool ASYNC_SOCKET_HOLDER::Send ( int  aService,
const std::string &  aMessage 
)
inline

Attempt to send a message if the thread is available.

Parameters
aServiceis the port number (i.e. service) to send to.
aMessageis the message to send.
Returns
true if the message was queued.

Definition at line 169 of file eda_dde.cpp.

170  {
171  if( m_messageReady )
172  return false;
173 
174  std::lock_guard<std::mutex> lock( m_mutex );
175 
176  m_message = std::make_pair( aService, aMessage );
177  m_messageReady = true;
178  m_cv.notify_one();
179 
180  return true;
181  }
std::mutex m_mutex
Definition: eda_dde.cpp:286
std::condition_variable m_cv
Definition: eda_dde.cpp:287
std::pair< int, std::string > m_message
Definition: eda_dde.cpp:284

References m_cv, m_message, m_messageReady, and m_mutex.

◆ worker()

void ASYNC_SOCKET_HOLDER::worker ( )
inlineprivate

Actual task that sends data to the socket server.

Definition at line 187 of file eda_dde.cpp.

188  {
189  int port;
190  std::string message;
191 
192  std::unique_lock<std::mutex> lock( m_mutex );
193 
194  while( !m_shutdown )
195  {
196  m_cv.wait( lock, [&]() { return m_messageReady || m_shutdown; } );
197 
198  if( m_shutdown )
199  break;
200 
201  port = m_message.first;
202  message = m_message.second;
203 
204  lock.unlock();
205 
206  wxSocketClient* sock_client;
207  wxIPV4address addr;
208 
209  // Create a connection
210  addr.Hostname( HOSTNAME );
211  addr.Service( port );
212 
213  // Mini-tutorial for Connect() :-)
214  // (JP CHARRAS Note: see wxWidgets: sockets/client.cpp sample)
215  // ---------------------------
216  //
217  // There are two ways to use Connect(): blocking and non-blocking,
218  // depending on the value passed as the 'wait' (2nd) parameter.
219  //
220  // Connect(addr, true) will wait until the connection completes,
221  // returning true on success and false on failure. This call blocks
222  // the GUI (this might be changed in future releases to honor the
223  // wxSOCKET_BLOCK flag).
224  //
225  // Connect(addr, false) will issue a nonblocking connection request
226  // and return immediately. If the return value is true, then the
227  // connection has been already successfully established. If it is
228  // false, you must wait for the request to complete, either with
229  // WaitOnConnect() or by watching wxSOCKET_CONNECTION / LOST
230  // events (please read the documentation).
231  //
232  // WaitOnConnect() itself never blocks the GUI (this might change
233  // in the future to honor the wxSOCKET_BLOCK flag). This call will
234  // return false on timeout, or true if the connection request
235  // completes, which in turn might mean:
236  //
237  // a) That the connection was successfully established
238  // b) That the connection request failed (for example, because
239  // it was refused by the peer.
240  //
241  // Use IsConnected() to distinguish between these two.
242  //
243  // So, in a brief, you should do one of the following things:
244  //
245  // For blocking Connect:
246  //
247  // bool success = client->Connect(addr, true);
248  //
249  // For nonblocking Connect:
250  //
251  // client->Connect(addr, false);
252  //
253  // bool waitmore = true;
254  // while (! client->WaitOnConnect(seconds, millis) && waitmore )
255  // {
256  // // possibly give some feedback to the user,
257  // // update waitmore if needed.
258  // }
259  // bool success = client->IsConnected();
260  //
261  // And that's all :-)
262 
263  sock_client = new wxSocketClient( wxSOCKET_BLOCK );
264  sock_client->SetTimeout( 1 ); // Time out in Seconds
265  sock_client->Connect( addr, false );
266  sock_client->WaitOnConnect( 0, 250 );
267 
268  if( sock_client->Ok() && sock_client->IsConnected() )
269  {
270  sock_client->SetFlags( wxSOCKET_NOWAIT /*wxSOCKET_WAITALL*/ );
271  sock_client->Write( message.c_str(), message.length() );
272  }
273 
274  sock_client->Close();
275  sock_client->Destroy();
276 
277  m_messageReady = false;
278 
279  lock.lock();
280  }
281  }
std::mutex m_mutex
Definition: eda_dde.cpp:286
static const wxString HOSTNAME(wxT("localhost"))
std::condition_variable m_cv
Definition: eda_dde.cpp:287
std::pair< int, std::string > m_message
Definition: eda_dde.cpp:284

References HOSTNAME(), m_cv, m_message, m_messageReady, m_mutex, and m_shutdown.

Referenced by ASYNC_SOCKET_HOLDER().

Member Data Documentation

◆ m_cv

std::condition_variable ASYNC_SOCKET_HOLDER::m_cv
private

Definition at line 287 of file eda_dde.cpp.

Referenced by Send(), worker(), and ~ASYNC_SOCKET_HOLDER().

◆ m_message

std::pair<int, std::string> ASYNC_SOCKET_HOLDER::m_message
private

Definition at line 284 of file eda_dde.cpp.

Referenced by Send(), and worker().

◆ m_messageReady

bool ASYNC_SOCKET_HOLDER::m_messageReady
private

Definition at line 285 of file eda_dde.cpp.

Referenced by Send(), and worker().

◆ m_mutex

std::mutex ASYNC_SOCKET_HOLDER::m_mutex
mutableprivate

Definition at line 286 of file eda_dde.cpp.

Referenced by Send(), worker(), and ~ASYNC_SOCKET_HOLDER().

◆ m_shutdown

bool ASYNC_SOCKET_HOLDER::m_shutdown
private

Definition at line 288 of file eda_dde.cpp.

Referenced by worker(), and ~ASYNC_SOCKET_HOLDER().

◆ m_thread

std::thread ASYNC_SOCKET_HOLDER::m_thread
private

Definition at line 283 of file eda_dde.cpp.

Referenced by ASYNC_SOCKET_HOLDER(), and ~ASYNC_SOCKET_HOLDER().


The documentation for this class was generated from the following file: