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