Logo ROOT   6.16/01
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 TGWin32InterpreterProxy (to gInterpreter).
19
20Proxy 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
24For 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
34Howto 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////////////////////////////////////////////////////////////////////////////////
94class TGWin32CallBackObject : public TObject {
95public:
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////////////////////////////////////////////////////////////////////////////////
104class TGWin32ProxyBasePrivate {
105public:
106 HANDLE fEvent; // event used for syncronization
107 TGWin32ProxyBasePrivate();
108 ~TGWin32ProxyBasePrivate();
109};
110
111////////////////////////////////////////////////////////////////////////////////
112/// ctor
113
114TGWin32ProxyBasePrivate::TGWin32ProxyBasePrivate()
115{
116 fEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
117}
118
119////////////////////////////////////////////////////////////////////////////////
120/// dtor
121
122TGWin32ProxyBasePrivate::~TGWin32ProxyBasePrivate()
123{
124 if (fEvent) ::CloseHandle(fEvent);
125 fEvent = 0;
126}
127
128
135
136////////////////////////////////////////////////////////////////////////////////
137////////////////////////////////////////////////////////////////////////////////
138/// ctor
139
141{
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{
160 delete fListOfCallBacks;
162
163 delete fPimpl;
164}
165
166////////////////////////////////////////////////////////////////////////////////
167/// enter critical section
168
170{
172}
173
174////////////////////////////////////////////////////////////////////////////////
175/// leave critical section
176
178{
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) {
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
244 TGWin32CallBackObject *obj;
245
246 while ((obj = (TGWin32CallBackObject*)next())) {
247 obj->fCallBack(obj->fParam); // execute callback
248 }
249 }
250 if (sync) {
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) &&
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
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
static RooMathCoreReg dummy
int Int_t
Definition: RtypesCore.h:41
unsigned int UInt_t
Definition: RtypesCore.h:42
const Bool_t kFALSE
Definition: RtypesCore.h:88
unsigned long ULong_t
Definition: RtypesCore.h:51
long Long_t
Definition: RtypesCore.h:50
bool Bool_t
Definition: RtypesCore.h:59
double Double_t
Definition: RtypesCore.h:55
const Bool_t kTRUE
Definition: RtypesCore.h:87
void(* TGWin32CallBack)(void *)
#define gROOT
Definition: TROOT.h:410
#define TRUE
#define FALSE
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:955
static void Lock()
Definition: TGWin32.cxx:947
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:467
Mother of all ROOT objects.
Definition: TObject.h:37
static constexpr double L
Definition: first.py:1
const char * cnt
Definition: TXMLSetup.cxx:74