]> SALOME platform Git repositories - modules/gui.git/blob - src/PyInterp/PyInterp_Dispatcher.cxx
Salome HOME
Merge from V6_main_20120808 08Aug12
[modules/gui.git] / src / PyInterp / PyInterp_Dispatcher.cxx
1 // Copyright (C) 2007-2012  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
23 //  File   : PyInterp_Dispatcher.cxx
24 //  Author : Sergey ANIKIN, OCC
25 //  Module : GUI
26 //
27 #include "PyInterp_Dispatcher.h"   // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
28 #include "PyInterp_Interp.h"
29 #include "PyInterp_Watcher.h"
30 #include <SALOME_Event.h>
31
32 #include <QObject>
33 #include <QCoreApplication>
34
35 class PyInterp_ExecuteEvent: public SALOME_Event
36 {
37 public:
38   PyInterp_Request* myRequest;
39   PyInterp_ExecuteEvent( PyInterp_Request* r )
40     : myRequest( r ) {}
41   virtual void Execute()
42   {
43     myRequest->execute();
44   }
45 };
46
47 PyInterp_Dispatcher* PyInterp_Dispatcher::myInstance = 0;
48
49 void PyInterp_Request::process()
50 {
51   safeExecute();
52
53   bool isSync = IsSync();
54
55   if ( !isSync )
56     myMutex.lock();
57
58   if ( listener() )
59     processEvent( listener() );
60
61   if ( !isSync )
62     myMutex.unlock();
63 }
64
65 void PyInterp_Request::safeExecute()
66 {
67   //ProcessVoidEvent( new PyInterp_ExecuteEvent( this ) );
68   execute();
69 }
70
71 void PyInterp_Request::Destroy( PyInterp_Request* request )
72 {
73   // Lock and unlock the mutex to avoid errors on its deletion
74   request->myMutex.lock();
75   request->myMutex.unlock();
76   delete request;
77 }
78
79 QEvent* PyInterp_Request::createEvent() const
80 {
81   return new PyInterp_Event( PyInterp_Event::ES_NOTIFY, (PyInterp_Request*)this );
82 }
83
84 void PyInterp_Request::processEvent( QObject* o )
85 {
86   if ( !o )
87     return;
88
89   QEvent* e = createEvent();
90   if ( !e )
91     return;
92
93   if ( !IsSync() )
94     QCoreApplication::postEvent( o, e );
95   else
96   {
97     QCoreApplication::sendEvent( o, e );
98     delete e;
99   }
100 }
101
102 void PyInterp_Request::setListener( QObject* o )
103 {
104   myMutex.lock();
105   myListener = o;
106   myMutex.unlock();
107 }
108
109 void PyInterp_LockRequest::safeExecute()
110 {
111   if ( getInterp() ){
112     PyLockWrapper aLock = getInterp()->GetLockWrapper();
113     //ProcessVoidEvent( new PyInterp_ExecuteEvent( this ) );
114     execute();
115   }
116 }
117
118 PyInterp_Event::~PyInterp_Event()
119 {
120   PyInterp_Request::Destroy( myRequest );
121   myRequest = 0;
122 }
123
124 PyInterp_Dispatcher* PyInterp_Dispatcher::Get()
125 {
126   if ( !myInstance )
127     myInstance = new PyInterp_Dispatcher();
128   return myInstance;
129 }
130
131 PyInterp_Dispatcher::PyInterp_Dispatcher() 
132 : QThread()
133 {
134   myWatcher = new PyInterp_Watcher();
135 }
136
137 PyInterp_Dispatcher::~PyInterp_Dispatcher()
138 {
139   // Clear the request queue
140   myQueueMutex.lock();
141
142   QListIterator<RequestPtr> it( myQueue );
143   while ( it.hasNext() )
144     PyInterp_Request::Destroy( it.next() );
145   myQueue.clear();
146
147   myQueueMutex.unlock();
148
149   // Wait for run() to finish
150   wait();
151
152   delete myWatcher;
153   myWatcher = 0;
154 }
155
156 bool PyInterp_Dispatcher::IsBusy() const
157 {
158   return isRunning();
159 }
160
161 void PyInterp_Dispatcher::Exec( PyInterp_Request* theRequest )
162 {
163   if ( !theRequest )
164     return;
165
166   //if ( theRequest->IsSync() && !IsBusy() ) // synchronous processing - nothing is done if dispatcher is busy!
167   if ( theRequest->IsSync() ) // synchronous processing - nothing is done if dispatcher is busy!
168     processRequest( theRequest );
169   else // asynchronous processing
170   {
171     myQueueMutex.lock();
172     myQueue.enqueue( theRequest );
173     if ( theRequest->listener() )
174       QObject::connect( theRequest->listener(), SIGNAL( destroyed( QObject* ) ), myWatcher, SLOT( onDestroyed( QObject* ) ) );
175     myQueueMutex.unlock();  
176
177     if ( !IsBusy() )
178       start();
179   }
180 }
181
182 void PyInterp_Dispatcher::run()
183 {
184 //  MESSAGE("*** PyInterp_Dispatcher::run(): STARTED")
185   PyInterp_Request* aRequest;
186
187   // prepare for queue size check
188   myQueueMutex.lock();
189
190   while( myQueue.size() ) {
191 //    MESSAGE("*** PyInterp_Dispatcher::run(): next request taken from the queue")
192     aRequest = myQueue.head();
193
194     // let other threads append their requests to the end of the queue
195     myQueueMutex.unlock();
196
197     // processRequest() may delete a request, so this pointer must not be used
198     // after request is processed!
199     processRequest( aRequest );
200
201     // prepare for removal of the first request in the queue
202     myQueueMutex.lock();
203     // IMPORTANT: the first item could have been removed by objectDestroyed() --> we have to check it
204     if ( myQueue.head() == aRequest ) // It's still here --> remove it
205       myQueue.dequeue();
206
207 //    MESSAGE("*** PyInterp_Dispatcher::run(): request processed")
208   }
209
210   myQueueMutex.unlock();
211 //  MESSAGE("*** PyInterp_Dispatcher::run(): FINISHED")
212 }
213
214 void PyInterp_Dispatcher::processRequest( PyInterp_Request* theRequest )
215 {
216   theRequest->process();
217 }
218
219 void PyInterp_Dispatcher::objectDestroyed( const QObject* o )
220 {
221   // prepare for modification of the queue
222   myQueueMutex.lock();
223
224   QMutableListIterator<RequestPtr> it( myQueue );
225   while ( it.hasNext() )
226   {
227     RequestPtr r = it.next();
228     if ( o == r->listener() )
229     {
230       r->setListener( 0 ); // to prevent event posting
231       it.remove();
232     }
233   }
234
235   myQueueMutex.unlock();
236 }