1 // Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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, or (at your option) any later version.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // KERNEL SALOME_Event : Define event posting mechanism
24 // File : SALOME_Event.cxx
25 // Author : Sergey ANIKIN
27 #include "SALOME_Event.h"
30 #include <QApplication>
32 // asv 21.02.05 : introducing multi-platform approach of thread comparison
33 // - on Unix using pthread_t type for storing ThreadId
34 // - on Win32 using integer type for storing ThreadId
35 // NOT using integer ThreadId on both Unix and Win32 because (from documentation):
36 // "...Do not allow your program to rely on the internal structure or size of the pthread_t..."
40 static DWORD myThread;
43 static pthread_t myThread;
48 \brief Helper event class responsible for initializing SALOME_Event
49 mechanism by the main thread ID
51 class InitEvent : public SALOME_Event
56 virtual void Execute();
60 \brief Constructor, initializes the event mechanism by the current thread ID.
61 It is asssumed to be the main thread ID, so be careful!
63 InitEvent::InitEvent()
69 \brief Destructor, does nothing.
71 InitEvent::~InitEvent()
76 \brief Nothing to be executed for this kind of event.
78 void InitEvent::Execute()
82 // NOTE: Here the SALOME event mechanism is initalized by the
83 // current thread ID that is always assumed to be the main thread ID.
84 // This should be revised as soon as the application library is no longer
85 // linked against the Event library (i.e. this static object is not created or created
86 // outside the main thread).
87 static InitEvent myInitEvent;
90 \class SALOME_CustomEvent
91 \brief Generic event class for user-defined events
93 This class contains a generic void* data member that may be used
94 for transferring event-specific data to the receiver.
96 \warning The internal data is not destroyed by the class destructor.
101 \param type event type
103 SALOME_CustomEvent::SALOME_CustomEvent( int type )
104 : QEvent( (QEvent::Type)type ), d( 0 )
110 \param type event type
111 \param data custom data
113 SALOME_CustomEvent::SALOME_CustomEvent( QEvent::Type type, void* data )
114 : QEvent( type ), d( data )
119 \brief Get custom data.
120 \return pointer to the internal data
122 void* SALOME_CustomEvent::data() const
128 \brief Set custom data.
129 \param data pointer to the internal data
131 void SALOME_CustomEvent::setData( void* data )
138 \brief The class which encapsulates data and functionality required for
139 posting component-specific events to perform arbitrary operations
140 in the main GUI thread.
142 SALOME_Event objects can be posted by any thread belonging to the GUI process.
144 It is necessary to derive a custom event class from SALOME_Event and
145 re-implement virtual Execute() method. This method should actually perform
146 the desirable operation. To pass all the required data to Execute() and
147 store a return value, arbitrary data fields can be added to the custom
148 event class. There is no need to protect such fields with a mutex, for only
149 one thread working with a SALOME_Event object is active at any moment.
152 - Create SALOME_Event. Components can derive their own event class from
153 SALOME_Event in order to pass custom data to the event handler.
154 - Call process() method to post the event. After process() execution
155 it is possible to examine fields of your custom event object.
156 - Perform delete operator on the event to wake up the desktop (you can also
157 set <autoRelease> parameter to \c true to automatically wake up desktop after
160 The method processed() is used by the desktop to signal that event processing
163 To make all this work, it is necessary to call static method GetSessionThread()
164 during the application initialization, i.e. from main() function.
165 It is important to call this method from the primary application thread.
171 //! Total number of semaphore resources
172 const int NumberOfResources = 2;
175 \brief Initialize event mechanism.
177 This function sets up the main application thread. It should be called
178 during the application initialization, i.e. main() function.
180 void SALOME_Event::GetSessionThread(){
182 myThread = ::GetCurrentThreadId();
184 myThread = pthread_self();
189 \brief Check if the processing is in the main application thread.
190 \return \c true if this method is called from the main application thread
192 bool SALOME_Event::IsSessionThread(){
193 bool aResult = false;
195 aResult = myThread == ::GetCurrentThreadId();
197 aResult = myThread == pthread_self();
205 SALOME_Event::SALOME_Event(){
206 // Prepare the semaphore
207 mySemaphore = new QSemaphore( NumberOfResources );
208 mySemaphore->acquire( NumberOfResources );
214 SALOME_Event::~SALOME_Event(){
215 if ( mySemaphore->available() < NumberOfResources )
216 mySemaphore->release( NumberOfResources - mySemaphore->available() );
221 \brief This method should be called by the main GUI thread
222 in order to execute the code specific for this event and finally
223 to inform the calling thread that the event
224 has been processed waking it up with help of the semaphore .
226 void SALOME_Event::ExecutePostedEvent()
228 // Diagnose incorrect usage of SALOME_Event API
229 if ( !IsSessionThread() ){
230 qWarning( "SALOME_Event::ExecutePostedEvent() is called from a secondary thread that might mean an error in application logic!" );
232 // Actual execution specific for particular kind of event
234 // Signal the calling thread that the event has been processed
239 \brief Post the event and wait for its completion.
240 process() should be called from a secondary thread only.
243 void SALOME_Event::process()
245 // Diagnose incorrect usage of SALOME_Event API
246 if ( IsSessionThread() ){
247 qWarning( "SALOME_Event::process() is called from the main GUI thread that might mean an error in application logic!" );
250 QApplication::postEvent( qApp, new SALOME_CustomEvent( SALOME_EVENT, (void*)this ) );
251 mySemaphore->acquire( 1 );
255 \brief Use this method to signal that this event has been processed.
257 void SALOME_Event::processed()
259 mySemaphore->release( 1 );
263 \fn virtual void SALOME_Event::Execute();
264 \brief This method should be redefined in the successor classes
270 \brief Template class for event which calls the function
271 without arguments and returning result.
275 \class TVoidMemFunEvent
276 \brief Template class for event which calls the function
277 without arguments and without return value.
281 \class TMemFun1ArgEvent
282 \brief Template class for event which calls the function
283 with one argument and returning result.
287 \class TVoidMemFun1ArgEvent
288 \brief Template class for event which calls the function
289 with one argument and without return value.
293 \class TMemFun2ArgEvent
294 \brief Template class for event which calls the function
295 with two arguments and returning result.
299 \class TVoidMemFun2ArgEvent
300 \brief Template class for event which calls the function
301 with two arguments and without return value.
306 \brief Template function for processing events with return value.
311 \brief Template function for processing events without return value.