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 126 of file eda_dde.cpp.

Constructor & Destructor Documentation

◆ ASYNC_SOCKET_HOLDER()

ASYNC_SOCKET_HOLDER::ASYNC_SOCKET_HOLDER ( )
inline

Definition at line 129 of file eda_dde.cpp.

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

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

◆ ~ASYNC_SOCKET_HOLDER()

ASYNC_SOCKET_HOLDER::~ASYNC_SOCKET_HOLDER ( )
inline

Definition at line 149 of file eda_dde.cpp.

150 {
151 {
152 std::lock_guard<std::mutex> lock( m_mutex );
153 m_shutdown = true;
154 }
155
156 m_cv.notify_one();
157
158 try
159 {
160 if( m_thread.joinable() )
161 m_thread.join();
162 }
163 catch( ... )
164 {
165 }
166 }
std::condition_variable m_cv
Definition: eda_dde.cpp:293
std::mutex m_mutex
Definition: eda_dde.cpp:292

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 175 of file eda_dde.cpp.

176 {
177 if( m_messageReady )
178 return false;
179
180 std::lock_guard<std::mutex> lock( m_mutex );
181
182 m_message = std::make_pair( aService, aMessage );
183 m_messageReady = true;
184 m_cv.notify_one();
185
186 return true;
187 }
std::pair< int, std::string > m_message
Definition: eda_dde.cpp:290

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 193 of file eda_dde.cpp.

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

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 293 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 290 of file eda_dde.cpp.

Referenced by Send(), and worker().

◆ m_messageReady

bool ASYNC_SOCKET_HOLDER::m_messageReady
private

Definition at line 291 of file eda_dde.cpp.

Referenced by Send(), and worker().

◆ m_mutex

std::mutex ASYNC_SOCKET_HOLDER::m_mutex
mutableprivate

Definition at line 292 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 294 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 289 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: