Logo ROOT  
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
15Proxy classes provide thread-safe interface to global objects.
16
17For example: TGWin32VirtualXProxy (to gVirtualX).
18
19Proxy 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
23For 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
33Howto 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 global object
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 TVirtualX *RealObject();
58 static TVirtualX *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(VirtualX)
65 - the names of other macros say about itself.
66
67 For example:
68 VOID_METHOD_ARG0(VirtualX,SetFillAttributes,1)
69 void TGWin32VirtualXProxy::SetFillAttributes()
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*/
78
79
80#include "Windows4Root.h"
81#include <windows.h>
82
83#include "TGWin32ProxyBase.h"
84#include "TRefCnt.h"
85#include "TList.h"
86#include "TGWin32.h"
87#include "TROOT.h"
88
89////////////////////////////////////////////////////////////////////////////////
90class TGWin32CallBackObject : public TObject {
91public:
92 TGWin32CallBack fCallBack; // callback function (called by GUI thread)
93 void *fParam; // arguments passed to/from callback function
94
95 TGWin32CallBackObject(TGWin32CallBack cb,void *p):fCallBack(cb),fParam(p) {}
96 ~TGWin32CallBackObject() { if (fParam) delete fParam; }
97};
98
99////////////////////////////////////////////////////////////////////////////////
100class TGWin32ProxyBasePrivate {
101public:
102 HANDLE fEvent; // event used for syncronization
103 TGWin32ProxyBasePrivate();
104 ~TGWin32ProxyBasePrivate();
105};
106
107////////////////////////////////////////////////////////////////////////////////
108/// ctor
109
110TGWin32ProxyBasePrivate::TGWin32ProxyBasePrivate()
111{
112 fEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
113}
114
115////////////////////////////////////////////////////////////////////////////////
116/// dtor
117
118TGWin32ProxyBasePrivate::~TGWin32ProxyBasePrivate()
119{
120 if (fEvent) ::CloseHandle(fEvent);
121 fEvent = 0;
122}
123
124
131
132////////////////////////////////////////////////////////////////////////////////
133////////////////////////////////////////////////////////////////////////////////
134/// ctor
135
137{
139 fCallBack = 0;
140 fParam = 0;
141 fListOfCallBacks = new TList();
142 fBatchLimit = 100;
143 fId = ::GetCurrentThreadId();
144 fPimpl = new TGWin32ProxyBasePrivate();
145
146 if (!fgPostMessageId) fgPostMessageId = ::RegisterWindowMessage("TGWin32ProxyBase::Post");
147 if (!fgPingMessageId) fgPingMessageId = ::RegisterWindowMessage("TGWin32ProxyBase::Ping");
148}
149
150////////////////////////////////////////////////////////////////////////////////
151/// dtor
152
154{
156 delete fListOfCallBacks;
158
159 delete fPimpl;
160}
161
162////////////////////////////////////////////////////////////////////////////////
163/// enter critical section
164
166{
168}
169
170////////////////////////////////////////////////////////////////////////////////
171/// leave critical section
172
174{
176}
177
178////////////////////////////////////////////////////////////////////////////////
179/// lock any proxy (client thread)
180
182{
183 if (IsGloballyLocked()) return;
184 ::InterlockedIncrement(&fgLock);
185}
186
187////////////////////////////////////////////////////////////////////////////////
188/// unlock any proxy (client thread)
189
191{
192 if (!IsGloballyLocked()) return;
193 ::InterlockedDecrement(&fgLock);
194}
195
196////////////////////////////////////////////////////////////////////////////////
197/// send ping messsage to server thread
198
200{
201 return ::PostThreadMessage(fgMainThreadId, fgPingMessageId, (WPARAM)0, 0L);
202}
203
204////////////////////////////////////////////////////////////////////////////////
205/// returns elapsed time in milliseconds with microseconds precision
206
208{
209 static LARGE_INTEGER freq;
210 static Bool_t first = kTRUE;
211 LARGE_INTEGER count;
212 static Double_t overhead = 0;
213
214 if (first) {
215 LARGE_INTEGER count0;
216 ::QueryPerformanceFrequency(&freq);
217 ::QueryPerformanceCounter(&count0);
218 if (1) {
220 dummy = ((Double_t)count0.QuadPart - overhead)*1000./((Double_t)freq.QuadPart);
221 }
222 ::QueryPerformanceCounter(&count);
223 overhead = (Double_t)count.QuadPart - (Double_t)count0.QuadPart;
224 first = kFALSE;
225 }
226
227 ::QueryPerformanceCounter(&count);
228 return ((Double_t)count.QuadPart - overhead)*1000./((Double_t)freq.QuadPart);
229}
230
231////////////////////////////////////////////////////////////////////////////////
232/// Executes all batched callbacks and the latest callback
233/// This method is executed by server thread
234
236{
237 // process batched callbacks
240 TGWin32CallBackObject *obj;
241
242 while ((obj = (TGWin32CallBackObject*)next())) {
243 obj->fCallBack(obj->fParam); // execute callback
244 }
245 }
246 if (sync) {
248 ::SetEvent(fPimpl->fEvent);
249 }
250}
251
252////////////////////////////////////////////////////////////////////////////////
253/// if sync is kTRUE:
254/// - post message to main thread.
255/// - execute callbacks from fListOfCallBacks
256/// - wait for response
257/// else
258/// - add callback to fListOfCallBacks
259///
260/// returns kTRUE if callback execution is delayed (batched)
261
263{
264 Int_t wait = 0;
265
266 if (!fgMainThreadId) return kFALSE;
267
268 while (IsGloballyLocked()) {
269 Ping();
270#ifdef OLD_THREAD_IMPLEMENTATION
271 if (GetCurrentThreadId() == fgMainThreadId)
272 break;
273#endif
274 ::SleepEx(10, 1); // take a rest
275 if (!fgMainThreadId) return kFALSE; // server thread terminated
276 }
277
278 Bool_t batch = !sync && (fListOfCallBacks->GetSize() < fBatchLimit);
279
280 // if it is a call to gVirtualX and comes from a secondary thread,
281 // delay it and process it via the main thread (to avoid deadlocks).
282 if (!fgUserThreadId && fIsVirtualX &&
283 (GetCurrentThreadId() != fgMainThreadId) &&
285 batch = kTRUE;
286
287 if (batch) {
288 fListOfCallBacks->Add(new TGWin32CallBackObject(fCallBack, fParam));
289 return kTRUE;
290 }
291
292 while (!::PostThreadMessage(fgMainThreadId, fgPostMessageId, (WPARAM)this, 0L)) {
293 // wait because there is a chance that message queue does not exist yet
294 ::SleepEx(50, 1);
295 if (wait++ > 5) return kFALSE; // failed to post
296 }
297
298#ifdef OLD_THREAD_IMPLEMENTATION
299 Int_t cnt = 0; //VO attempt counters
300#endif
301 // limiting wait time
302 DWORD res = WAIT_TIMEOUT;
303 while (res == WAIT_TIMEOUT) {
304 res = ::WaitForSingleObject(fPimpl->fEvent, 100);
305#ifdef OLD_THREAD_IMPLEMENTATION
306 if ((GetCurrentThreadId() == fgMainThreadId) ||
307 (!gROOT->IsLineProcessing() && IsGloballyLocked())) {
308 break;
309 }
310 if (cnt++ > 20) break; // VO after some efforts go out from loop
311#endif
312 }
313 ::ResetEvent(fPimpl->fEvent);
314
315 if (res == WAIT_TIMEOUT) { // server thread is blocked
316 GlobalLock();
317 return kTRUE;
318 }
319
321 return kFALSE;
322}
323
324////////////////////////////////////////////////////////////////////////////////
325/// Check the status of the lock.
326
328{
329 return fgLock;
330}
331
332////////////////////////////////////////////////////////////////////////////////
333/// send exit message to server thread
334
336{
337 ::PostThreadMessage(fgMainThreadId, WM_QUIT, 0, 0L);
338}
339
static RooMathCoreReg dummy
unsigned int UInt_t
Definition: RtypesCore.h:44
const Bool_t kFALSE
Definition: RtypesCore.h:90
unsigned long ULong_t
Definition: RtypesCore.h:53
long Long_t
Definition: RtypesCore.h:52
double Double_t
Definition: RtypesCore.h:57
const Bool_t kTRUE
Definition: RtypesCore.h:89
void(* TGWin32CallBack)(void *)
#define gROOT
Definition: TROOT.h:406
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Definition: TCollection.h:182
virtual ~TGWin32ProxyBase()
dtor
static Bool_t IsGloballyLocked()
Check the status of the lock.
static ULong_t fgPingMessageId
ping message ID
static void Lock()
enter critical section
static void GlobalUnlock()
unlock any proxy (client thread)
TList * fListOfCallBacks
list of callbacks (used for batch processing)
Int_t fBatchLimit
batch limit
virtual Double_t GetMilliSeconds()
returns elapsed time in milliseconds with microseconds precision
static UInt_t fMaxResponseTime
max period for waiting response from server thread
static Long_t fgLock
fgLock=1 - all client threads locked
virtual void SendExitMessage()
send exit message to server thread
static Bool_t Ping()
send ping messsage to server thread
static void Unlock()
leave critical section
static void GlobalLock()
lock any proxy (client thread)
virtual Bool_t ForwardCallBack(Bool_t sync)
if sync is kTRUE:
static ULong_t fgUserThreadId
user (e.g. python) thread ID
TGWin32ProxyBasePrivate * fPimpl
very private data
static ULong_t fgPostMessageId
post message ID
ULong_t fId
thread id. There is one proxy per client thread
static ULong_t fgMainThreadId
main thread ID
void * fParam
arguments passed to/from callback function
virtual void ExecuteCallBack(Bool_t sync)
Executes all batched callbacks and the latest callback This method is executed by server thread.
Bool_t fIsVirtualX
true if actual TVirtualX implementation
TGWin32CallBack fCallBack
callback function (executed by "main" thread)
static void Unlock()
Definition: TGWin32.cxx:940
static void Lock()
Definition: TGWin32.cxx:932
A doubly linked list.
Definition: TList.h:44
virtual void Add(TObject *obj)
Definition: TList.h:87
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
Definition: TList.cxx:469
Mother of all ROOT objects.
Definition: TObject.h:37
#define TRUE
Definition: mesh.c:42
#define FALSE
Definition: mesh.c:45
static constexpr double L
Definition: first.py:1
const char * cnt
Definition: TXMLSetup.cxx:74