Salome HOME
Connect feature with group, document and index in the group
[modules/shaper.git] / src / PyInterp / PyInterp_Dispatcher.cxx
1
2 #include "PyInterp_Dispatcher.h"   // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
3 #include "PyInterp_Interp.h"
4 #include "PyInterp_Watcher.h"
5 #include "PyInterp_Request.h"
6
7 #include <QObject>
8 #include <QCoreApplication>
9
10 PyInterp_Dispatcher* PyInterp_Dispatcher::myInstance = 0;
11
12 void PyInterp_Request::process()
13 {
14   safeExecute();
15
16   bool isSync = IsSync();
17
18   if ( !isSync )
19     myMutex.lock();
20
21   if ( listener() )
22     processEvent( listener() );
23
24   if ( !isSync )
25     myMutex.unlock();
26 }
27
28 void PyInterp_Request::safeExecute()
29 {
30   //ProcessVoidEvent( new PyInterp_ExecuteEvent( this ) );
31   execute();
32 }
33
34 void PyInterp_Request::Destroy( PyInterp_Request* request )
35 {
36   // Lock and unlock the mutex to avoid errors on its deletion
37   request->myMutex.lock();
38   request->myMutex.unlock();
39   delete request;
40 }
41
42 QEvent* PyInterp_Request::createEvent()
43 {
44   return new PyInterp_Event( PyInterp_Event::ES_NOTIFY, this );
45 }
46
47 void PyInterp_Request::processEvent( QObject* o )
48 {
49   if ( !o )
50     return;
51
52   QEvent* e = createEvent();
53   if ( !e )
54     return;
55
56   if ( !IsSync() )
57     QCoreApplication::postEvent( o, e );
58   else
59   {
60     QCoreApplication::sendEvent( o, e );
61     delete e;
62   }
63 }
64
65 void PyInterp_Request::setListener( QObject* o )
66 {
67   myMutex.lock();
68   myListener = o;
69   myMutex.unlock();
70 }
71
72 void PyInterp_LockRequest::safeExecute()
73 {
74   if ( getInterp() ){
75     PyLockWrapper aLock = getInterp()->GetLockWrapper();
76     //ProcessVoidEvent( new PyInterp_ExecuteEvent( this ) );
77     execute();
78   }
79 }
80
81 PyInterp_Event::~PyInterp_Event()
82 {
83   PyInterp_Request::Destroy( myRequest );
84   myRequest = 0;
85 }
86
87 PyInterp_Dispatcher* PyInterp_Dispatcher::Get()
88 {
89   if ( !myInstance )
90     myInstance = new PyInterp_Dispatcher();
91   return myInstance;
92 }
93
94 PyInterp_Dispatcher::PyInterp_Dispatcher() 
95 : QThread()
96 {
97   myWatcher = new PyInterp_Watcher();
98 }
99
100 PyInterp_Dispatcher::~PyInterp_Dispatcher()
101 {
102   // Clear the request queue
103   myQueueMutex.lock();
104
105   QListIterator<RequestPtr> it( myQueue );
106   while ( it.hasNext() )
107     PyInterp_Request::Destroy( it.next() );
108   myQueue.clear();
109
110   myQueueMutex.unlock();
111
112   // Wait for run() to finish
113   wait();
114
115   delete myWatcher;
116   myWatcher = 0;
117 }
118
119 bool PyInterp_Dispatcher::IsBusy() const
120 {
121   return isRunning();
122 }
123
124 void PyInterp_Dispatcher::Exec( PyInterp_Request* theRequest )
125 {
126   if ( !theRequest )
127     return;
128
129   //if ( theRequest->IsSync() && !IsBusy() ) // synchronous processing - nothing is done if dispatcher is busy!
130   if ( theRequest->IsSync() ) // synchronous processing
131     processRequest( theRequest );
132   else // asynchronous processing
133   {
134     myQueueMutex.lock();
135     myQueue.enqueue( theRequest );
136     if ( theRequest->listener() )
137       QObject::connect( theRequest->listener(), SIGNAL( destroyed( QObject* ) ), myWatcher, SLOT( onDestroyed( QObject* ) ) );
138     myQueueMutex.unlock();  
139
140     if ( !IsBusy() )
141       start();
142   }
143 }
144
145 void PyInterp_Dispatcher::run()
146 {
147 //  MESSAGE("*** PyInterp_Dispatcher::run(): STARTED")
148   PyInterp_Request* aRequest;
149
150   // prepare for queue size check
151   myQueueMutex.lock();
152
153   while( myQueue.size() ) {
154 //    MESSAGE("*** PyInterp_Dispatcher::run(): next request taken from the queue")
155     aRequest = myQueue.head();
156
157     // let other threads append their requests to the end of the queue
158     myQueueMutex.unlock();
159
160     // processRequest() may delete a request, so this pointer must not be used
161     // after request is processed!
162     processRequest( aRequest );
163
164     // prepare for removal of the first request in the queue
165     myQueueMutex.lock();
166     // IMPORTANT: the first item could have been removed by objectDestroyed() --> we have to check it
167     if ( myQueue.head() == aRequest ) // It's still here --> remove it
168       myQueue.dequeue();
169
170 //    MESSAGE("*** PyInterp_Dispatcher::run(): request processed")
171   }
172
173   myQueueMutex.unlock();
174 //  MESSAGE("*** PyInterp_Dispatcher::run(): FINISHED")
175 }
176
177 void PyInterp_Dispatcher::processRequest( PyInterp_Request* theRequest )
178 {
179   theRequest->process();
180 }
181
182 void PyInterp_Dispatcher::objectDestroyed( const QObject* o )
183 {
184   // prepare for modification of the queue
185   myQueueMutex.lock();
186
187   QMutableListIterator<RequestPtr> it( myQueue );
188   while ( it.hasNext() )
189   {
190     RequestPtr r = it.next();
191     if ( o == r->listener() )
192     {
193       r->setListener( 0 ); // to prevent event posting
194       it.remove();
195     }
196   }
197
198   myQueueMutex.unlock();
199 }