TGWin32ProxyBase.cxx

Go to the documentation of this file.
00001 // @(#)root/win32gdk:$Id: TGWin32ProxyBase.cxx 32129 2010-01-28 08:31:05Z bellenot $
00002 // Author: Valeriy Onuchin  08/08/2003
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //
00014 // Proxy classes provide thread-safe interface to global objects.
00015 //
00016 // For example: TGWin32VirtualXProxy (to gVirtualX),  
00017 //              TGWin32InterpreterProxy (to gInterpreter).
00018 //
00019 // Proxy object creates callback object and posts a windows message to 
00020 // "processing thread". When windows message is received callback 
00021 // ("real method") is executed.
00022 // 
00023 // For example: 
00024 //    gVirtualX->ClearWindow()
00025 //
00026 //    - callback object created containing pointer to function
00027 //      corresponding TGWin32::ClearWindow() method
00028 //    - message to "processing thread" (main thread) is posted
00029 //    - TGWin32::ClearWindow() method is executed inside main thread
00030 //    - thread containing gVirtualX proxy object waits for reply
00031 //      from main thread that TGWin32::ClearWindow() is completed. 
00032 //
00033 // Howto create proxy class:
00034 //
00035 //  1. Naming. 
00036 //       name of proxy = TGWin32 + the name of "virtual base class" + Proxy
00037 //
00038 //       e.g. TGWin32VirtualXProxy = TGWin32 + VirtualX + Proxy
00039 //
00040 //  2. Definition of global object
00041 //       As example check definition and implementation of 
00042 //       gVirtualX, gInterpreter global objects
00043 //
00044 //  3. Class definition.
00045 //       proxy class must be inherited from "virtual base class" and
00046 //       TGWin32ProxyBase class. For example:
00047 //
00048 //       class TGWin32VirtualX : public TVirtualX , public  TGWin32ProxyBase
00049 //
00050 //  4. Constructors, destructor, extra methods.
00051 //     - constructors and destructor of proxy class do nothing
00052 //     - proxy class must contain two extra static methods 
00053 //       RealObject(), ProxyObject(). Each of them return pointer to object
00054 //       of virtual base class.
00055 //
00056 //     For example:
00057 //       static TInterpreter *RealObject();
00058 //       static TInterpreter *ProxyObject();
00059 //
00060 //  5. Implementation
00061 //       TGWin32ProxyDefs.h file contains a set of macros which very
00062 //       simplify implementation.
00063 //     - RETURN_PROXY_OBJECT macro implements ProxyObject() method, e.g.
00064 //       RETURN_PROXY_OBJECT(Interpreter)         
00065 //     - the names of other macros say about itself.
00066 //
00067 //       For example:
00068 //          VOID_METHOD_ARG0(Interpreter,ClearFileBusy,1)
00069 //             void TGWin32InterpreterProxy::ClearFileBusy()
00070 //  
00071 //          RETURN_METHOD_ARG0_CONST(VirtualX,Visual_t,GetVisual)
00072 //             Visual_t TGWin32VirtualXProxy::GetVisual() const
00073 //
00074 //          RETURN_METHOD_ARG2(VirtualX,Int_t,OpenPixmap,UInt_t,w,UInt_t,h)
00075 //             Int_t TGWin32VirtualXProxy::OpenPixmap,UInt_t w,UInt_t h)
00076 //
00077 //     - few methods has _LOCK part in the name
00078 //          VOID_METHOD_ARG1_LOCK(Interpreter,CreateListOfMethods,TClass*,cl)
00079 //   
00080 //
00081 ///////////////////////////////////////////////////////////////////////////////
00082 
00083 #include "Windows4Root.h"
00084 #include <windows.h>
00085 
00086 #include "TGWin32ProxyBase.h"
00087 #include "TRefCnt.h"
00088 #include "TList.h"
00089 #include "TGWin32.h"
00090 #include "TROOT.h"
00091 
00092 ////////////////////////////////////////////////////////////////////////////////
00093 class TGWin32CallBackObject : public TObject {
00094 public:
00095    TGWin32CallBack   fCallBack;  // callback function (called by GUI thread)
00096    void              *fParam;    // arguments passed to/from callback function
00097 
00098    TGWin32CallBackObject(TGWin32CallBack cb,void *p):fCallBack(cb),fParam(p) {}
00099    ~TGWin32CallBackObject() { if (fParam) delete fParam; }
00100 };
00101 
00102 ////////////////////////////////////////////////////////////////////////////////
00103 class TGWin32ProxyBasePrivate {
00104 public:
00105    HANDLE   fEvent;   // event used for syncronization
00106    TGWin32ProxyBasePrivate();
00107    ~TGWin32ProxyBasePrivate();
00108 };
00109 
00110 //______________________________________________________________________________
00111 TGWin32ProxyBasePrivate::TGWin32ProxyBasePrivate()
00112 {
00113    // ctor
00114 
00115    fEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
00116 }
00117 
00118 //______________________________________________________________________________
00119 TGWin32ProxyBasePrivate::~TGWin32ProxyBasePrivate()
00120 {
00121    // dtor
00122 
00123    if (fEvent) ::CloseHandle(fEvent);
00124    fEvent = 0;
00125 }
00126 
00127 
00128 ULong_t TGWin32ProxyBase::fgPostMessageId = 0;
00129 ULong_t TGWin32ProxyBase::fgPingMessageId = 0;
00130 ULong_t TGWin32ProxyBase::fgMainThreadId = 0;
00131 ULong_t TGWin32ProxyBase::fgUserThreadId = 0;
00132 Long_t  TGWin32ProxyBase::fgLock = 0;
00133 UInt_t  TGWin32ProxyBase::fMaxResponseTime = 0;
00134 
00135 ////////////////////////////////////////////////////////////////////////////////
00136 //______________________________________________________________________________
00137 TGWin32ProxyBase::TGWin32ProxyBase()
00138 {
00139    // ctor
00140 
00141    fIsVirtualX = kFALSE;
00142    fCallBack = 0;
00143    fParam = 0;
00144    fListOfCallBacks = new TList();
00145    fBatchLimit = 100;
00146    fId = ::GetCurrentThreadId();
00147    fPimpl = new TGWin32ProxyBasePrivate();
00148 
00149    if (!fgPostMessageId) fgPostMessageId = ::RegisterWindowMessage("TGWin32ProxyBase::Post");
00150    if (!fgPingMessageId) fgPingMessageId = ::RegisterWindowMessage("TGWin32ProxyBase::Ping");
00151 }
00152 
00153 //______________________________________________________________________________
00154 TGWin32ProxyBase::~TGWin32ProxyBase()
00155 {
00156    // dtor
00157 
00158    fListOfCallBacks->Delete();
00159    delete fListOfCallBacks;
00160    fListOfCallBacks = 0;
00161 
00162    delete fPimpl;
00163 }
00164 
00165 //______________________________________________________________________________
00166 void TGWin32ProxyBase::Lock()
00167 {
00168    // enter critical section
00169 
00170    TGWin32::Lock();
00171 }
00172 
00173 //______________________________________________________________________________
00174 void TGWin32ProxyBase::Unlock()
00175 {
00176    // leave critical section
00177 
00178    TGWin32::Unlock();
00179 }
00180 
00181 //______________________________________________________________________________
00182 void TGWin32ProxyBase::GlobalLock()
00183 {
00184    // lock any proxy (client thread)
00185 
00186    if (IsGloballyLocked()) return;
00187    ::InterlockedIncrement(&fgLock);
00188 }
00189 
00190 //______________________________________________________________________________
00191 void TGWin32ProxyBase::GlobalUnlock()
00192 {
00193    //  unlock any proxy (client thread)
00194 
00195    if (!IsGloballyLocked()) return;
00196    ::InterlockedDecrement(&fgLock);
00197 }
00198 
00199 //______________________________________________________________________________
00200 Bool_t TGWin32ProxyBase::Ping()
00201 {
00202    // send ping messsage to server thread
00203 
00204    return ::PostThreadMessage(fgMainThreadId, fgPingMessageId, (WPARAM)0, 0L);
00205 }
00206 
00207 //______________________________________________________________________________
00208 Double_t TGWin32ProxyBase::GetMilliSeconds()
00209 {
00210    // returns elapsed time in milliseconds with microseconds precision
00211 
00212    static LARGE_INTEGER freq;
00213    static Bool_t first = kTRUE;
00214    LARGE_INTEGER count;
00215    static Double_t overhead = 0;
00216 
00217    if (first) {
00218       LARGE_INTEGER count0;
00219       ::QueryPerformanceFrequency(&freq);
00220       ::QueryPerformanceCounter(&count0);
00221       if (1) {
00222          Double_t dummy;
00223          dummy = ((Double_t)count0.QuadPart - overhead)*1000./((Double_t)freq.QuadPart);
00224       }
00225       ::QueryPerformanceCounter(&count);
00226       overhead = (Double_t)count.QuadPart - (Double_t)count0.QuadPart;
00227       first = kFALSE;
00228    }
00229 
00230    ::QueryPerformanceCounter(&count);
00231    return ((Double_t)count.QuadPart - overhead)*1000./((Double_t)freq.QuadPart);
00232 }
00233 
00234 //______________________________________________________________________________
00235 void TGWin32ProxyBase::ExecuteCallBack(Bool_t sync)
00236 {
00237    // Executes all batched callbacks and the latest callback
00238    // This method is executed by server thread
00239 
00240    // process batched callbacks
00241    if (fListOfCallBacks && fListOfCallBacks->GetSize()) {
00242       TIter next(fListOfCallBacks);
00243       TGWin32CallBackObject *obj;
00244 
00245       while ((obj = (TGWin32CallBackObject*)next())) {
00246          obj->fCallBack(obj->fParam);  // execute callback
00247       }
00248    }
00249    if (sync) {
00250       if (fCallBack) fCallBack(fParam);
00251       ::SetEvent(fPimpl->fEvent);
00252    }
00253 }
00254 
00255 //______________________________________________________________________________
00256 Bool_t TGWin32ProxyBase::ForwardCallBack(Bool_t sync)
00257 {
00258    // if sync is kTRUE:
00259    //    - post message to main thread.
00260    //    - execute callbacks from fListOfCallBacks
00261    //    - wait for response
00262    // else
00263    //    -  add callback to fListOfCallBacks
00264    //
00265    // returns kTRUE if callback execution is delayed (batched)
00266 
00267    Int_t wait = 0;
00268 
00269    if (!fgMainThreadId) return kFALSE;
00270 
00271    while (IsGloballyLocked()) {
00272       Ping();
00273       if (GetCurrentThreadId() == fgMainThreadId)
00274          break;
00275       ::SleepEx(10, 1); // take a rest
00276       if (!fgMainThreadId) return kFALSE; // server thread terminated 
00277    }
00278 
00279    Bool_t batch = !sync && (fListOfCallBacks->GetSize() < fBatchLimit);
00280 
00281    // if it is a call to gVirtualX and comes from a secondary thread, 
00282    // delay it and process it via the main thread (to avoid deadlocks).
00283    if (!fgUserThreadId && fIsVirtualX && 
00284        (GetCurrentThreadId() != fgMainThreadId) &&
00285        (fListOfCallBacks->GetSize() < fBatchLimit))
00286       batch = kTRUE;
00287 
00288    if (batch) {
00289       fListOfCallBacks->Add(new TGWin32CallBackObject(fCallBack, fParam));
00290       return kTRUE;
00291    }
00292 
00293    while (!::PostThreadMessage(fgMainThreadId, fgPostMessageId, (WPARAM)this, 0L)) {
00294       // wait because there is a chance that message queue does not exist yet
00295       ::SleepEx(50, 1);
00296       if (wait++ > 5) return kFALSE; // failed to post
00297    }
00298 
00299    Int_t cnt = 0; //VO attempt counters
00300    // limiting wait time
00301    DWORD res = WAIT_TIMEOUT;
00302    while (res ==  WAIT_TIMEOUT) {
00303       res = ::WaitForSingleObject(fPimpl->fEvent, 100);
00304       if ((GetCurrentThreadId() == fgMainThreadId) || 
00305          (!gROOT->IsLineProcessing() && IsGloballyLocked())) {
00306          break;
00307       }
00308       if (cnt++ > 20) break; // VO after some efforts go out from loop
00309    }
00310    ::ResetEvent(fPimpl->fEvent);
00311 
00312    if (res == WAIT_TIMEOUT) { // server thread is blocked
00313       GlobalLock();
00314       return kTRUE;    
00315    }
00316 
00317    fListOfCallBacks->Delete();
00318    return kFALSE;
00319 }
00320 
00321 //______________________________________________________________________________
00322 Bool_t TGWin32ProxyBase::IsGloballyLocked()
00323 {
00324    // Check the status of the lock. 
00325 
00326    return fgLock;
00327 }
00328 
00329 //______________________________________________________________________________
00330 void TGWin32ProxyBase::SendExitMessage()
00331 {
00332    // send exit message to server thread
00333 
00334    ::PostThreadMessage(fgMainThreadId, WM_QUIT, 0, 0L);
00335 }
00336 

Generated on Tue Jul 5 14:14:45 2011 for ROOT_528-00b_version by  doxygen 1.5.1