Logo ROOT   6.12/07
Reference Guide
TGWin32ProxyBase.cxx
Go to the documentation of this file.
1 // @(#)root/win32gdk:$Id$
2 // Author: Valeriy Onuchin 08/08/2003
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TGWin32ProxyBase
13 \ingroup win32
14 
15 Proxy classes provide thread-safe interface to global objects.
16 
17 For example: TGWin32VirtualXProxy (to gVirtualX),
18  TGWin32InterpreterProxy (to gInterpreter).
19 
20 Proxy object creates callback object and posts a windows message to
21 "processing thread". When windows message is received callback
22 ("real method") is executed.
23 
24 For example:
25  gVirtualX->ClearWindow()
26 
27  - callback object created containing pointer to function
28  corresponding TGWin32::ClearWindow() method
29  - message to "processing thread" (main thread) is posted
30  - TGWin32::ClearWindow() method is executed inside main thread
31  - thread containing gVirtualX proxy object waits for reply
32  from main thread that TGWin32::ClearWindow() is completed.
33 
34 Howto create proxy class:
35 
36  1. Naming.
37  name of proxy = TGWin32 + the name of "virtual base class" + Proxy
38 
39  e.g. TGWin32VirtualXProxy = TGWin32 + VirtualX + Proxy
40 
41  2. Definition of global object
42  As example check definition and implementation of
43  gVirtualX, gInterpreter global objects
44 
45  3. Class definition.
46  proxy class must be inherited from "virtual base class" and
47  TGWin32ProxyBase class. For example:
48 
49  class TGWin32VirtualX : public TVirtualX , public TGWin32ProxyBase
50 
51  4. Constructors, destructor, extra methods.
52  - constructors and destructor of proxy class do nothing
53  - proxy class must contain two extra static methods
54  RealObject(), ProxyObject(). Each of them return pointer to object
55  of virtual base class.
56 
57  For example:
58  static TInterpreter *RealObject();
59  static TInterpreter *ProxyObject();
60 
61  5. Implementation
62  TGWin32ProxyDefs.h file contains a set of macros which very
63  simplify implementation.
64  - RETURN_PROXY_OBJECT macro implements ProxyObject() method, e.g.
65  RETURN_PROXY_OBJECT(Interpreter)
66  - the names of other macros say about itself.
67 
68  For example:
69  VOID_METHOD_ARG0(Interpreter,ClearFileBusy,1)
70  void TGWin32InterpreterProxy::ClearFileBusy()
71 
72  RETURN_METHOD_ARG0_CONST(VirtualX,Visual_t,GetVisual)
73  Visual_t TGWin32VirtualXProxy::GetVisual() const
74 
75  RETURN_METHOD_ARG2(VirtualX,Int_t,OpenPixmap,UInt_t,w,UInt_t,h)
76  Int_t TGWin32VirtualXProxy::OpenPixmap,UInt_t w,UInt_t h)
77 
78  - few methods has _LOCK part in the name
79  VOID_METHOD_ARG1_LOCK(Interpreter,CreateListOfMethods,TClass*,cl)
80 
81 */
82 
83 
84 #include "Windows4Root.h"
85 #include <windows.h>
86 
87 #include "TGWin32ProxyBase.h"
88 #include "TRefCnt.h"
89 #include "TList.h"
90 #include "TGWin32.h"
91 #include "TROOT.h"
92 
93 ////////////////////////////////////////////////////////////////////////////////
94 class TGWin32CallBackObject : public TObject {
95 public:
96  TGWin32CallBack fCallBack; // callback function (called by GUI thread)
97  void *fParam; // arguments passed to/from callback function
98 
99  TGWin32CallBackObject(TGWin32CallBack cb,void *p):fCallBack(cb),fParam(p) {}
100  ~TGWin32CallBackObject() { if (fParam) delete fParam; }
101 };
102 
103 ////////////////////////////////////////////////////////////////////////////////
104 class TGWin32ProxyBasePrivate {
105 public:
106  HANDLE fEvent; // event used for syncronization
107  TGWin32ProxyBasePrivate();
108  ~TGWin32ProxyBasePrivate();
109 };
110 
111 ////////////////////////////////////////////////////////////////////////////////
112 /// ctor
113 
114 TGWin32ProxyBasePrivate::TGWin32ProxyBasePrivate()
115 {
116  fEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
117 }
118 
119 ////////////////////////////////////////////////////////////////////////////////
120 /// dtor
121 
122 TGWin32ProxyBasePrivate::~TGWin32ProxyBasePrivate()
123 {
124  if (fEvent) ::CloseHandle(fEvent);
125  fEvent = 0;
126 }
127 
128 
135 
136 ////////////////////////////////////////////////////////////////////////////////
137 ////////////////////////////////////////////////////////////////////////////////
138 /// ctor
139 
141 {
142  fIsVirtualX = kFALSE;
143  fCallBack = 0;
144  fParam = 0;
145  fListOfCallBacks = new TList();
146  fBatchLimit = 100;
147  fId = ::GetCurrentThreadId();
148  fPimpl = new TGWin32ProxyBasePrivate();
149 
150  if (!fgPostMessageId) fgPostMessageId = ::RegisterWindowMessage("TGWin32ProxyBase::Post");
151  if (!fgPingMessageId) fgPingMessageId = ::RegisterWindowMessage("TGWin32ProxyBase::Ping");
152 }
153 
154 ////////////////////////////////////////////////////////////////////////////////
155 /// dtor
156 
158 {
159  fListOfCallBacks->Delete();
160  delete fListOfCallBacks;
161  fListOfCallBacks = 0;
162 
163  delete fPimpl;
164 }
165 
166 ////////////////////////////////////////////////////////////////////////////////
167 /// enter critical section
168 
170 {
171  TGWin32::Lock();
172 }
173 
174 ////////////////////////////////////////////////////////////////////////////////
175 /// leave critical section
176 
178 {
179  TGWin32::Unlock();
180 }
181 
182 ////////////////////////////////////////////////////////////////////////////////
183 /// lock any proxy (client thread)
184 
186 {
187  if (IsGloballyLocked()) return;
188  ::InterlockedIncrement(&fgLock);
189 }
190 
191 ////////////////////////////////////////////////////////////////////////////////
192 /// unlock any proxy (client thread)
193 
195 {
196  if (!IsGloballyLocked()) return;
197  ::InterlockedDecrement(&fgLock);
198 }
199 
200 ////////////////////////////////////////////////////////////////////////////////
201 /// send ping messsage to server thread
202 
204 {
205  return ::PostThreadMessage(fgMainThreadId, fgPingMessageId, (WPARAM)0, 0L);
206 }
207 
208 ////////////////////////////////////////////////////////////////////////////////
209 /// returns elapsed time in milliseconds with microseconds precision
210 
212 {
213  static LARGE_INTEGER freq;
214  static Bool_t first = kTRUE;
215  LARGE_INTEGER count;
216  static Double_t overhead = 0;
217 
218  if (first) {
219  LARGE_INTEGER count0;
220  ::QueryPerformanceFrequency(&freq);
221  ::QueryPerformanceCounter(&count0);
222  if (1) {
223  Double_t dummy;
224  dummy = ((Double_t)count0.QuadPart - overhead)*1000./((Double_t)freq.QuadPart);
225  }
226  ::QueryPerformanceCounter(&count);
227  overhead = (Double_t)count.QuadPart - (Double_t)count0.QuadPart;
228  first = kFALSE;
229  }
230 
231  ::QueryPerformanceCounter(&count);
232  return ((Double_t)count.QuadPart - overhead)*1000./((Double_t)freq.QuadPart);
233 }
234 
235 ////////////////////////////////////////////////////////////////////////////////
236 /// Executes all batched callbacks and the latest callback
237 /// This method is executed by server thread
238 
240 {
241  // process batched callbacks
242  if (fListOfCallBacks && fListOfCallBacks->GetSize()) {
243  TIter next(fListOfCallBacks);
244  TGWin32CallBackObject *obj;
245 
246  while ((obj = (TGWin32CallBackObject*)next())) {
247  obj->fCallBack(obj->fParam); // execute callback
248  }
249  }
250  if (sync) {
251  if (fCallBack) fCallBack(fParam);
252  ::SetEvent(fPimpl->fEvent);
253  }
254 }
255 
256 ////////////////////////////////////////////////////////////////////////////////
257 /// if sync is kTRUE:
258 /// - post message to main thread.
259 /// - execute callbacks from fListOfCallBacks
260 /// - wait for response
261 /// else
262 /// - add callback to fListOfCallBacks
263 ///
264 /// returns kTRUE if callback execution is delayed (batched)
265 
267 {
268  Int_t wait = 0;
269 
270  if (!fgMainThreadId) return kFALSE;
271 
272  while (IsGloballyLocked()) {
273  Ping();
274 #ifdef OLD_THREAD_IMPLEMENTATION
275  if (GetCurrentThreadId() == fgMainThreadId)
276  break;
277 #endif
278  ::SleepEx(10, 1); // take a rest
279  if (!fgMainThreadId) return kFALSE; // server thread terminated
280  }
281 
282  Bool_t batch = !sync && (fListOfCallBacks->GetSize() < fBatchLimit);
283 
284  // if it is a call to gVirtualX and comes from a secondary thread,
285  // delay it and process it via the main thread (to avoid deadlocks).
286  if (!fgUserThreadId && fIsVirtualX &&
287  (GetCurrentThreadId() != fgMainThreadId) &&
288  (fListOfCallBacks->GetSize() < fBatchLimit))
289  batch = kTRUE;
290 
291  if (batch) {
292  fListOfCallBacks->Add(new TGWin32CallBackObject(fCallBack, fParam));
293  return kTRUE;
294  }
295 
296  while (!::PostThreadMessage(fgMainThreadId, fgPostMessageId, (WPARAM)this, 0L)) {
297  // wait because there is a chance that message queue does not exist yet
298  ::SleepEx(50, 1);
299  if (wait++ > 5) return kFALSE; // failed to post
300  }
301 
302 #ifdef OLD_THREAD_IMPLEMENTATION
303  Int_t cnt = 0; //VO attempt counters
304 #endif
305  // limiting wait time
306  DWORD res = WAIT_TIMEOUT;
307  while (res == WAIT_TIMEOUT) {
308  res = ::WaitForSingleObject(fPimpl->fEvent, 100);
309 #ifdef OLD_THREAD_IMPLEMENTATION
310  if ((GetCurrentThreadId() == fgMainThreadId) ||
311  (!gROOT->IsLineProcessing() && IsGloballyLocked())) {
312  break;
313  }
314  if (cnt++ > 20) break; // VO after some efforts go out from loop
315 #endif
316  }
317  ::ResetEvent(fPimpl->fEvent);
318 
319  if (res == WAIT_TIMEOUT) { // server thread is blocked
320  GlobalLock();
321  return kTRUE;
322  }
323 
324  fListOfCallBacks->Delete();
325  return kFALSE;
326 }
327 
328 ////////////////////////////////////////////////////////////////////////////////
329 /// Check the status of the lock.
330 
332 {
333  return fgLock;
334 }
335 
336 ////////////////////////////////////////////////////////////////////////////////
337 /// send exit message to server thread
338 
340 {
341  ::PostThreadMessage(fgMainThreadId, WM_QUIT, 0, 0L);
342 }
343 
virtual void ExecuteCallBack(Bool_t sync)
Executes all batched callbacks and the latest callback This method is executed by server thread...
static void Lock()
Definition: TGWin32.cxx:946
static void GlobalUnlock()
unlock any proxy (client thread)
static UInt_t fMaxResponseTime
max period for waiting response from server thread
#define gROOT
Definition: TROOT.h:402
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
virtual ~TGWin32ProxyBase()
dtor
static void Lock()
enter critical section
virtual void SendExitMessage()
send exit message to server thread
static Long_t fgLock
fgLock=1 - all client threads locked
static void Unlock()
Definition: TGWin32.cxx:954
static void GlobalLock()
lock any proxy (client thread)
static constexpr double L
static ULong_t fgMainThreadId
main thread ID
A doubly linked list.
Definition: TList.h:44
static ULong_t fgPostMessageId
post message ID
static ULong_t fgUserThreadId
user (e.g. python) thread ID
unsigned int UInt_t
Definition: RtypesCore.h:42
const Bool_t kFALSE
Definition: RtypesCore.h:88
long Long_t
Definition: RtypesCore.h:50
double Double_t
Definition: RtypesCore.h:55
#define TRUE
unsigned long ULong_t
Definition: RtypesCore.h:51
static RooMathCoreReg dummy
void(* TGWin32CallBack)(void *)
virtual Bool_t ForwardCallBack(Bool_t sync)
if sync is kTRUE:
static ULong_t fgPingMessageId
ping message ID
Mother of all ROOT objects.
Definition: TObject.h:37
static Bool_t IsGloballyLocked()
Check the status of the lock.
#define FALSE
virtual Double_t GetMilliSeconds()
returns elapsed time in milliseconds with microseconds precision
Definition: first.py:1
const Bool_t kTRUE
Definition: RtypesCore.h:87
static Bool_t Ping()
send ping messsage to server thread
const char * cnt
Definition: TXMLSetup.cxx:74
static void Unlock()
leave critical section