1 // Copyright (C) 2007-2008 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.
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
22 // KERNEL SALOME_Event : Define event posting mechanism
23 // File : SALOME_Event.cxx
24 // Author : Sergey ANIKIN
26 #include "SALOME_Event.h"
29 #include <QApplication>
31 // asv 21.02.05 : introducing multi-platform approach of thread comparison
32 // - on Unix using pthread_t type for storing ThreadId
33 // - on Win32 using integer type for storing ThreadId
34 // NOT using integer ThreadId on both Unix and Win32 because (from documentation):
35 // "...Do not allow your program to rely on the internal structure or size of the pthread_t..."
39 static DWORD myThread;
42 static pthread_t myThread;
47 \brief Helper event class responsible for initializing SALOME_Event
48 mechanism by the main thread ID
50 class InitEvent : public SALOME_Event
55 virtual void Execute();
59 \brief Constructor, initializes the event mechanism by the current thread ID.
60 It is asssumed to be the main thread ID, so be careful!
62 InitEvent::InitEvent()
68 \brief Destructor, does nothing.
70 InitEvent::~InitEvent()
75 \brief Nothing to be executed for this kind of event.
77 void InitEvent::Execute()
81 // NOTE: Here the SALOME event mechanism is initalized by the
82 // current thread ID that is always assumed to be the main thread ID.
83 // This should be revised as soon as the application library is no longer
84 // linked against the Event library (i.e. this static object is not created or created
85 // outside the main thread).
86 static InitEvent myInitEvent;
89 \class SALOME_CustomEvent
90 \brief Generic event class for user-defined events
92 This class contains a generic void* data member that may be used
93 for transferring event-specific data to the receiver.
95 \warning The internal data is not destroyed by the class destructor.
100 \param type event type
102 SALOME_CustomEvent::SALOME_CustomEvent( int type )
103 : QEvent( (QEvent::Type)type ), d( 0 )
109 \param type event type
110 \param data custom data
112 SALOME_CustomEvent::SALOME_CustomEvent( QEvent::Type type, void* data )
113 : QEvent( type ), d( data )
118 \brief Get custom data.
119 \return pointer to the internal data
121 void* SALOME_CustomEvent::data() const
127 \brief Set custom data.
128 \param data pointer to the internal data
130 void SALOME_CustomEvent::setData( void* data )
137 \brief The class which encapsulates data and functionality required for
138 posting component-specific events to perform arbitrary operations
139 in the main GUI thread.
141 SALOME_Event objects can be posted by any thread belonging to the GUI process.
143 It is necessary to derive a custom event class from SALOME_Event and
144 re-implement virtual Execute() method. This method should actually perform
145 the desirable operation. To pass all the required data to Execute() and
146 store a return value, arbitrary data fields can be added to the custom
147 event class. There is no need to protect such fields with a mutex, for only
148 one thread working with a SALOME_Event object is active at any moment.
151 - Create SALOME_Event. Components can derive their own event class from
152 SALOME_Event in order to pass custom data to the event handler.
153 - Call process() method to post the event. After process() execution
154 it is possible to examine fields of your custom event object.
155 - Perform delete operator on the event to wake up the desktop (you can also
156 set <autoRelease> parameter to \c true to automatically wake up desktop after
159 The method processed() is used by the desktop to signal that event processing
162 To make all this work, it is necessary to call static method GetSessionThread()
163 during the application initialization, i.e. from main() function.
164 It is important to call this method from the primary application thread.
170 //! Total number of semaphore resources
171 const int NumberOfResources = 2;
174 \brief Initialize event mechanism.
176 This function sets up the main application thread. It should be called
177 during the application initialization, i.e. main() function.
179 void SALOME_Event::GetSessionThread(){
181 myThread = ::GetCurrentThreadId();
183 myThread = pthread_self();
188 \brief Check if the processing is in the main application thread.
189 \return \c true if this method is called from the main application thread
191 bool SALOME_Event::IsSessionThread(){
192 bool aResult = false;
194 aResult = myThread == ::GetCurrentThreadId();
196 aResult = myThread == pthread_self();
204 SALOME_Event::SALOME_Event(){
205 // Prepare the semaphore
206 mySemaphore = new QSemaphore( NumberOfResources );
207 mySemaphore->acquire( NumberOfResources );
213 SALOME_Event::~SALOME_Event(){
214 if ( mySemaphore->available() < NumberOfResources )
215 mySemaphore->release( NumberOfResources - mySemaphore->available() );
220 \brief This method should be called by the main GUI thread
221 in order to execute the code specific for this event and finally
222 to inform the calling thread that the event
223 has been processed waking it up with help of the semaphore .
225 void SALOME_Event::ExecutePostedEvent()
227 // Diagnose incorrect usage of SALOME_Event API
228 if ( !IsSessionThread() ){
229 qWarning( "SALOME_Event::ExecutePostedEvent() is called from a secondary thread that might mean an error in application logic!" );
231 // Actual execution specific for particular kind of event
233 // Signal the calling thread that the event has been processed
238 \brief Post the event and wait for its completion.
239 process() should be called from a secondary thread only.
242 void SALOME_Event::process()
244 // Diagnose incorrect usage of SALOME_Event API
245 if ( IsSessionThread() ){
246 qWarning( "SALOME_Event::process() is called from the main GUI thread that might mean an error in application logic!" );
249 QApplication::postEvent( qApp, new SALOME_CustomEvent( SALOME_EVENT, (void*)this ) );
250 mySemaphore->acquire( 1 );
254 \brief Use this method to signal that this event has been processed.
256 void SALOME_Event::processed()
258 mySemaphore->release( 1 );
262 \fn virtual void SALOME_Event::Execute();
263 \brief This method should be redefined in the successor classes
269 \brief Template class for event which calls the function
270 without arguments and returning result.
274 \class TVoidMemFunEvent
275 \brief Template class for event which calls the function
276 without arguments and without return value.
280 \class TMemFun1ArgEvent
281 \brief Template class for event which calls the function
282 with one argument and returning result.
286 \class TVoidMemFun1ArgEvent
287 \brief Template class for event which calls the function
288 with one argument and without return value.
292 \class TMemFun2ArgEvent
293 \brief Template class for event which calls the function
294 with two arguments and returning result.
298 \class TVoidMemFun2ArgEvent
299 \brief Template class for event which calls the function
300 with two arguments and without return value.
305 \brief Template function for processing events with return value.
310 \brief Template function for processing events without return value.