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