Salome HOME
Update from BR_V5_DEV 13Feb2009
[modules/gui.git] / src / PyInterp / PyInterp_Dispatcher.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  File   : PyInterp_Dispatcher.cxx
23 //  Author : Sergey ANIKIN, OCC
24 //  Module : GUI
25 //
26 #include "PyInterp_Dispatcher.h"   // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
27 #include "PyInterp_Interp.h"
28 #include "PyInterp_Watcher.h"
29 #include <SALOME_Event.h>
30
31 #include <QObject>
32 #include <QCoreApplication>
33
34 class PyInterp_ExecuteEvent: public SALOME_Event
35 {
36 public:
37   PyInterp_Request* myRequest;
38   PyInterp_ExecuteEvent( PyInterp_Request* r )
39     : myRequest( r ) {}
40   virtual void Execute()
41   {
42     myRequest->execute();
43   }
44 };
45
46 using namespace std;
47
48 PyInterp_Dispatcher* PyInterp_Dispatcher::myInstance = 0;
49
50 void PyInterp_Request::process()
51 {
52   safeExecute();
53
54   bool isSync = IsSync();
55
56   if ( !isSync )
57     myMutex.lock();
58
59   if ( listener() )
60     processEvent( listener() );
61
62   if ( !isSync )
63     myMutex.unlock();
64 }
65
66 void PyInterp_Request::safeExecute()
67 {
68   //ProcessVoidEvent( new PyInterp_ExecuteEvent( this ) );
69   execute();
70 }
71
72 void PyInterp_Request::Destroy( PyInterp_Request* request )
73 {
74   // Lock and unlock the mutex to avoid errors on its deletion
75   request->myMutex.lock();
76   request->myMutex.unlock();
77   delete request;
78 }
79
80 QEvent* PyInterp_Request::createEvent() const
81 {
82   return new PyInterp_Event( PyInterp_Event::ES_NOTIFY, (PyInterp_Request*)this );
83 }
84
85 void PyInterp_Request::processEvent( QObject* o )
86 {
87   if ( !o )
88     return;
89
90   QEvent* e = createEvent();
91   if ( !e )
92     return;
93
94   if ( !IsSync() )
95     QCoreApplication::postEvent( o, e );
96   else
97   {
98     QCoreApplication::sendEvent( o, e );
99     delete e;
100   }
101 }
102
103 void PyInterp_Request::setListener( QObject* o )
104 {
105   myMutex.lock();
106   myListener = o;
107   myMutex.unlock();
108 }
109
110 void PyInterp_LockRequest::safeExecute()
111 {
112   if ( getInterp() ){
113     PyLockWrapper aLock = getInterp()->GetLockWrapper();
114     //ProcessVoidEvent( new PyInterp_ExecuteEvent( this ) );
115     execute();
116   }
117 }
118
119 PyInterp_Event::~PyInterp_Event()
120 {
121   PyInterp_Request::Destroy( myRequest );
122   myRequest = 0;
123 }
124
125 PyInterp_Dispatcher* PyInterp_Dispatcher::Get()
126 {
127   if ( !myInstance )
128     myInstance = new PyInterp_Dispatcher();
129   return myInstance;
130 }
131
132 PyInterp_Dispatcher::PyInterp_Dispatcher() 
133 : QThread()
134 {
135   myWatcher = new PyInterp_Watcher();
136 }
137
138 PyInterp_Dispatcher::~PyInterp_Dispatcher()
139 {
140   // Clear the request queue
141   myQueueMutex.lock();
142
143   QListIterator<RequestPtr> it( myQueue );
144   while ( it.hasNext() )
145     PyInterp_Request::Destroy( it.next() );
146   myQueue.clear();
147
148   myQueueMutex.unlock();
149
150   // Wait for run() to finish
151   wait();
152
153   delete myWatcher;
154   myWatcher = 0;
155 }
156
157 bool PyInterp_Dispatcher::IsBusy() const
158 {
159   return isRunning();
160 }
161
162 void PyInterp_Dispatcher::Exec( PyInterp_Request* theRequest )
163 {
164   if ( !theRequest )
165     return;
166
167   //if ( theRequest->IsSync() && !IsBusy() ) // synchronous processing - nothing is done if dispatcher is busy!
168   if ( theRequest->IsSync() ) // synchronous processing - nothing is done if dispatcher is busy!
169     processRequest( theRequest );
170   else // asynchronous processing
171   {
172     myQueueMutex.lock();
173     myQueue.enqueue( theRequest );
174     if ( theRequest->listener() )
175       QObject::connect( theRequest->listener(), SIGNAL( destroyed( QObject* ) ), myWatcher, SLOT( onDestroyed( QObject* ) ) );
176     myQueueMutex.unlock();  
177
178     if ( !IsBusy() )
179       start();
180   }
181 }
182
183 void PyInterp_Dispatcher::run()
184 {
185 //  MESSAGE("*** PyInterp_Dispatcher::run(): STARTED")
186   PyInterp_Request* aRequest;
187
188   // prepare for queue size check
189   myQueueMutex.lock();
190
191   while( myQueue.size() ) {
192 //    MESSAGE("*** PyInterp_Dispatcher::run(): next request taken from the queue")
193     aRequest = myQueue.head();
194
195     // let other threads append their requests to the end of the queue
196     myQueueMutex.unlock();
197
198     // processRequest() may delete a request, so this pointer must not be used
199     // after request is processed!
200     processRequest( aRequest );
201
202     // prepare for removal of the first request in the queue
203     myQueueMutex.lock();
204     // IMPORTANT: the first item could have been removed by objectDestroyed() --> we have to check it
205     if ( myQueue.head() == aRequest ) // It's still here --> remove it
206       myQueue.dequeue();
207
208 //    MESSAGE("*** PyInterp_Dispatcher::run(): request processed")
209   }
210
211   myQueueMutex.unlock();
212 //  MESSAGE("*** PyInterp_Dispatcher::run(): FINISHED")
213 }
214
215 void PyInterp_Dispatcher::processRequest( PyInterp_Request* theRequest )
216 {
217   theRequest->process();
218 }
219
220 void PyInterp_Dispatcher::objectDestroyed( const QObject* o )
221 {
222   // prepare for modification of the queue
223   myQueueMutex.lock();
224
225   QMutableListIterator<RequestPtr> it( myQueue );
226   while ( it.hasNext() )
227   {
228     RequestPtr r = it.next();
229     if ( o == r->listener() )
230     {
231       r->setListener( 0 ); // to prevent event posting
232       it.remove();
233     }
234   }
235
236   myQueueMutex.unlock();
237 }