Remoto - VFS: VFS_thread.cpp Source File
Remoto - VFS
VFS_thread.cpp
Go to the documentation of this file.
1 
2 #include "VFS_thread.h"
3 
4 #include <QCoreApplication>
5 
6 #include "VFS.h"
7 #include "VFS_creator.h"
8 
28 
39 VFS_thread::VFS_thread(QDomElement nodeConfig, QVariantMap env, bool printConfig)
40 : VFS_node()
41 , _thread(this, nodeConfig, env, printConfig)
42 , _node(nullptr)
43 {
44  QMutexLocker l(&VFS_node::__allNodesMutex); //to make the threadcount reliable
45 
46  _threadcount++;
47  VFS_creator::_outstanding.acquire(); //acquire a resource for synchronization
48 
49  VFS::LOG( QString(" -Creating thread #%1 '%2:%3'").arg(_threadcount).arg(nodeConfig.tagName()).arg(nodeConfig.attribute("name")), 9 );
50 
51  //name the thread for gdb or ps or lldb
52  _thread.setObjectName( nodeConfig.tagName()+":"+nodeConfig.attribute("name") );
53 
54  connect( &_thread, SIGNAL(nodeCreated(VFS_node*)), this, SLOT(setNode(VFS_node*)) ); //listen for the node creation
55  connect( this, SIGNAL(mounted()), &_thread, SLOT(start()) ); //start the thread once we're mounted
56  connect( this, SIGNAL(unmounted(VFS_node *)), &_thread, SLOT(quit()) ); //kill the thread on unmount
57  connect( &_thread, SIGNAL(finished()), this, SLOT(defunct())) ; //unmount the thread once the thread is complete
58 }
59 
68 VFS_thread *VFS_thread::fromConfig(QString configString, QVariantMap env, bool printConfig)
69 {
70  QString error;
71  QDomDocument config;
72 
73  if (config.setContent( configString, &error ))
74  {
75  QDomElement child = config.firstChildElement();
76  return new VFS_thread(child,env,printConfig);
77  }
78  else
79  VFS::ERROR( QString("Could not create thread with config: %1\nerror: %2\n").arg(configString).arg(error));
80 
81  return nullptr;
82 }
83 
84 
92 {
93  /*
94  if (_node)
95  { delete _node;
96  //_node->deleteLater(); //because this object has no parent, we want to trigger deletion of this branch when the thread finishes
97  }
98  */
99 
100  VFS::LOG( QString(" -Destroying thread %1").arg(_thread.objectName()), 9 );
101 
102  _thread.quit();
103  _thread.wait();
104 
105  _threadcount--;
106 }
107 
108 
118 {
119  emit finished(true); //to include deletion
120 }
121 
122 
133 {
134  return _threadcount+1;
135 }
136 
137 
148 {
149  if (_node)
150  { VFS::ERROR("Node already set on thread. Aborting this command.");
151  return;
152  }
153 
154  _node = node;
155 
156  disconnect( &_thread, SIGNAL(nodeCreated(VFS_node*)), this, SLOT(setNode(VFS_node*)) ); //listen for the node creation
157  //connect( this, SIGNAL(unmounted(VFS_node *)), _node, SIGNAL(unmounted(VFS_node *)) ); //trigger unmount when this node is unmounted
158  connect( &_thread, SIGNAL(finished()), _node, SLOT(deleteLater()) );
159  connect( _node, SIGNAL(finished(bool)), this, SIGNAL(finished(bool)) );
160 
161  //printf("releasing...\n");
162  //VFS_creator::outstanding.release(); //release what was acquired in the constructor
163 }
164 
165 
178 VFS_node *VFS_thread::append(QString name, VFS_node *node, bool containerCheck, QString user)
179 {
180  Q_UNUSED(name);
181  Q_UNUSED(node);
182  Q_UNUSED(containerCheck);
183  Q_UNUSED(user);
184 
185  VFS::ERROR( "Adding children to a VFS_thread is unsupported... pass a config instead" );
186 
187  //return _node->append(name,node);
188 
189  return nullptr;
190 }
191 
192 
201 {
202  if (_node)
203  _node->mount(); //FIXME: is this thread-safe?
204 
205  return VFS_node::mount();
206 }
207 
208 
215 {
216  if (_node)
217  _node->unmount(); //FIXME: is this thread-safe?
218 
219  return VFS_node::unmount();
220 }
221 
222 
232 {
233  QMutexLocker l(&_lock);
234 
235  if (!_node) return false;
236 
237  return _node->isContainer(); //FIXME: it's bad to directly call anything from a dfferent thread... this will need to be deprecated at some point!
238 }
239 
240 
249 {
250  return (_node != nullptr);
251 }
252 
253 
254 /*
255 void VFS_thread::metadata(VFS_request *r)
256 {
257  //QMutexLocker l(&_lock);
258 
259  //FIXME: is it threadsafe to allow metadata to break the thread boundary?
260  //seems needed for VFS_applications
261  //_node->metadata(r);
262 
263  VFS_request *p = r->getCallback(this);
264  issueRequest(_node,p);
265 
266  //issueRequest(_node,r);
267 
268  //in this case, we actually don't want to call the base class because the default behavior would do stuff that may override the callback
269  //VFS_node::metadata(r);
270 }
271 */
272 
273 
284 {
285  Q_UNUSED(r);
286 
287  return this;
288 }
289 
290 
300 {
301  //Q_UNUSED(t);
302 
303  //if this happens, something is routing the wrong way?
304  //or is it?
305  //VFS::ERROR("THREAD SUBTREE REQUEST");
306 
307  executeRequest(t);
308  //issueRequest(_node,t);
309 }
310 
311 
320 {
321  if (_node)
322  issueRequest(_node,t);
323  else
324  VFS::ERROR( QString("No node set for this thread: %1\n%2\n").arg((quintptr)thread()).arg(QString(t->toJson(0,true))), 0, t->_user );
325 }
326 
327 
344 VFS_threadthread::VFS_threadthread(VFS_node *p, QDomElement nodeConfig, QVariantMap env, bool printConfig)
345 : QThread(p)
346 , _nodeConfig(nodeConfig)
347 , _env(env)
348 , _printConfig(printConfig)
349 , _node(nullptr)
350 {
351 }
352 
354 {
355  //covered as a connection above
356  /*
357  if (_node)
358  { //delete _node;
359  _node->deleteLater(); //because this object has no parent, we want to trigger deletion of this branch when the thread finishes
360  }
361  */
362 }
363 
364 
381 {
382  //VFS::LOG( QString("Creating node(s) for '%1' (%2)").arg(_nodeConfig.attribute("name")).arg(_nodeConfig.tagName()) );
383 
384  _nodeConfig.removeAttribute("thread"); //so we're not in a loop
385 
386  try
387  {
389  }
390  catch(...)
391  {
392  QString currentConfigFile = _env["file"].toString();
393  QString tag = _nodeConfig.tagName();
394  //printf("%s\n", qUtf8Printable( QString("Failed to load config '%1' on tag '%2'.").arg(currentConfigFile).arg(tag) ) );
395  VFS::ERROR( QString("Failed to load config '%1' on tag '%2'.").arg(currentConfigFile).arg(tag), 0, "VFS_threadthread" );
396  VFS_creator::_outstanding.release(); //release what was acquired in the constructor
397  emit creationFailed();
398  return;
399  }
400 
401  if(!_node)
402  { VFS::ERROR( QString("Thread %1 unable to create '%2'").arg(objectName()).arg(_nodeConfig.tagName()) );
403  VFS_creator::_outstanding.release(); //release what was acquired in the constructor
404  emit creationFailed();
405  return;
406  }
407 
408  _node->mount(); //call mount() on the thread node now that the thread is started
409 
410  emit nodeCreated(_node); //report the node back to the VFS_thread
411 
412  VFS_creator::_outstanding.release(); //release what was acquired in the constructor
413 
414  VFS_creator::_outstanding.acquire(VFS_CREATOR_MAX_OUTSTANDING); //wait to claim all available
415  VFS_creator::_outstanding.release(VFS_CREATOR_MAX_OUTSTANDING); //release them all (now we're in sync)
416 
417  //printf("THREAD EXEC\n");
418 
419  exec();
420 
421  //printf("THREAD COMPLETE\n");
422 }
#define VFS_CREATOR_MAX_OUTSTANDING
Definition: VFS_creator.h:15
static VFS_node * constructNode(QDomElement child, QVariantMap &env, bool printConfig=false)
VFS_creator::constructNode.
static QSemaphore _outstanding
A semaphore used to sync creation during startup.
Definition: VFS_creator.h:56
VFS_node is the base class from which all other VFS_node classes derive.
Definition: VFS_node.h:143
friend class VFS_thread
Definition: VFS_node.h:147
virtual VFS_node * unmount()
Unmount this node.
Definition: VFS_node.cpp:1742
virtual void issueRequest(VFS_request *t)
A convenience function.
Definition: VFS_node.cpp:1933
void mounted()
Emitted when a node is mount()ed.
void unmounted(VFS_node *self)
Emitted when a node is unmount()ed.
virtual bool isContainer()
A VFS_node may have children.
Definition: VFS_node.cpp:2025
QMutex _lock
A recursive mutex that is local to this node.
Definition: VFS_node.h:178
static QMutex __allNodesMutex
The global registry mutex, which will lock when node creation or deletion is being performed.
Definition: VFS_node.h:216
void finished(bool andDelete=false)
Emitted if a thread fails to create its node, or a node is rm()'d, or any other reason a node has com...
virtual VFS_node * mount()
Mount this node.
Definition: VFS_node.cpp:1718
The base class for all requests between nodes.
Definition: VFS_node.h:54
QString _user
who initiated this request, mostly for logging
Definition: VFS_node.h:106
virtual QByteArray toJson(postID id=0, bool ignoreSuccess=false, bool includeInitialPath=false)
Serialize this request.
Definition: VFS_node.cpp:415
A thread interface for creating multithreaded applications.
Definition: VFS_thread.h:32
virtual void subtreeRequest(VFS_request *t)
Subclass implementation of VFS_node::subtreeRequest()
Definition: VFS_thread.cpp:299
static int _threadcount
The internal thread count, useful for debug and logging messages.
Definition: VFS_thread.h:59
virtual void executeRequest(VFS_request *t)
Execute the VFS_request.
Definition: VFS_thread.cpp:319
void defunct()
When a thread is complete, it will emit finished(), which will trigger this slot.
Definition: VFS_thread.cpp:117
virtual bool isContainer()
The container-ness of the thread node.
Definition: VFS_thread.cpp:231
virtual VFS_node * mount()
Mount the node, and mount the thread node if it exists.
Definition: VFS_thread.cpp:200
VFS_node * _node
The root VFS_node running in the new thread.
Definition: VFS_thread.h:54
static VFS_thread * fromConfig(QString configString, QVariantMap env=QVariantMap(), bool printConfig=false)
A convenience method for creating threads.
Definition: VFS_thread.cpp:68
virtual VFS_node * unmount()
Unmount the node and the thread node if it exists.
Definition: VFS_thread.cpp:214
static int threadcount()
Return the current thread count, mostly only useful for logging output.
Definition: VFS_thread.cpp:132
VFS_threadthread _thread
The subclassed QThread, which will provide the event loop and actually run the thread.
Definition: VFS_thread.h:53
bool hasNode()
When a thread is created, it must construct its root node to become operational.
Definition: VFS_thread.cpp:248
virtual ~VFS_thread()
VFS_thread destructor.
Definition: VFS_thread.cpp:91
virtual VFS_node * append(QString name, VFS_node *node, bool containerCheck=true, QString user="unknown")
A dummy entry used to warn a developer of illegal use.
Definition: VFS_thread.cpp:178
void setNode(VFS_node *node)
Once the node is created in the new thread, this VFS_thread will keep a reference to it.
Definition: VFS_thread.cpp:147
virtual VFS_node * find(VFS_request *r)
Subclass implementation of VFS_node::find(), which is the path lookup mechanism.
Definition: VFS_thread.cpp:283
void run()
Run the QThread event loop.
Definition: VFS_thread.cpp:380
void nodeCreated(VFS_node *node)
Once the _node has been created, this signals back to the owning VFS_thread of its existence.
VFS_node * _node
The root VFS_node running in the new thread.
Definition: VFS_thread.h:24
QVariantMap _env
The environment.
Definition: VFS_thread.h:21
VFS_threadthread(VFS_node *p, QDomElement nodeConfig, QVariantMap env, bool printConfig)
Definition: VFS_thread.cpp:344
QDomElement _nodeConfig
XML config node.
Definition: VFS_thread.h:20
void creationFailed()
If _node creation was not possible, this signal is emitted.
bool _printConfig
A debug setting, used to make sure contexts are correct.
Definition: VFS_thread.h:22
static void LOG(QString message, int level=0, QString user="server")
Send a message to the VFS::_messages VFS_stream.
Definition: VFS.cpp:209
static void ERROR(QString message, int level=0, QString user="server")
Send a message to the VFS::_errors VFS_stream.
Definition: VFS.cpp:307
setter user
a setter DOCME
setter name
a setter DOCME
QStringList exec(QString command, bool *ok=nullptr)
execute a command in a shell, and return the resulting output as a QStringList
Definition: rutils.cpp:658