Back to index

lightning-sunbird  0.9+nobinonly
GUSIContext.h
Go to the documentation of this file.
00001 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
00002 // % Project  :      GUSI                        -      Grand Unified Socket Interface                    
00003 // % File            :      GUSIContext.nw              -      Thread and Process structures               
00004 // % Author   :      Matthias Neeracher                                           
00005 // % Language :      C++                                                        
00006 // %                                                                       
00007 // % $Log: GUSIContext.h,v $
00008 // % Revision 1.1  2001/03/11 22:33:38  sgehani%netscape.com
00009 // % First Checked In.
00010 // %                                              
00011 // % Revision 1.22  2001/01/22 04:31:11  neeri                             
00012 // % Last minute changes for 2.1.5                                         
00013 // %                                                                       
00014 // % Revision 1.21  2001/01/17 08:43:42  neeri                             
00015 // % Tweak scheduling                                                      
00016 // %                                                                       
00017 // % Revision 1.20  2000/12/23 06:09:21  neeri                             
00018 // % May need to create context for IO completions                         
00019 // %                                                                       
00020 // % Revision 1.19  2000/10/16 04:34:22  neeri                             
00021 // % Releasing 2.1.2                                                       
00022 // %                                                                       
00023 // % Revision 1.18  2000/06/01 06:31:09  neeri                             
00024 // % Delete SigContext                                                     
00025 // %                                                                       
00026 // % Revision 1.17  2000/05/23 06:56:19  neeri                             
00027 // % Improve formatting, add socket closing queue, tune scheduling         
00028 // %                                                                       
00029 // % Revision 1.16  2000/03/15 07:11:50  neeri                             
00030 // % Fix detached delete (again), switcher restore                         
00031 // %                                                                       
00032 // % Revision 1.15  2000/03/06 08:10:09  neeri                             
00033 // % Fix sleep in main thread                                              
00034 // %                                                                       
00035 // % Revision 1.14  2000/03/06 06:13:46  neeri                             
00036 // % Speed up thread/process switching through minimal quotas              
00037 // %                                                                       
00038 // % Revision 1.13  1999/12/13 02:40:50  neeri                             
00039 // % GUSISetThreadSwitcher had Boolean <-> bool inconsistency              
00040 // %                                                                       
00041 // % Revision 1.12  1999/11/15 07:25:32  neeri                             
00042 // % Safe context setup. Check interrupts only in foreground.              
00043 // %                                                                       
00044 // % Revision 1.11  1999/09/09 07:18:06  neeri                             
00045 // % Added support for foreign threads                                     
00046 // %                                                                       
00047 // % Revision 1.10  1999/08/26 05:44:59  neeri                             
00048 // % Fixes for literate edition of source code                             
00049 // %                                                                       
00050 // % Revision 1.9  1999/06/28 05:59:02  neeri                              
00051 // % Add signal handling support                                           
00052 // %                                                                       
00053 // % Revision 1.8  1999/05/30 03:09:29  neeri                              
00054 // % Added support for MPW compilers                                       
00055 // %                                                                       
00056 // % Revision 1.7  1999/03/17 09:05:05  neeri                              
00057 // % Added GUSITimer, expanded docs                                        
00058 // %                                                                       
00059 // % Revision 1.6  1999/02/25 03:34:24  neeri                              
00060 // % Introduced GUSIContextFactory, simplified wakeup                      
00061 // %                                                                       
00062 // % Revision 1.5  1998/11/22 23:06:51  neeri                              
00063 // % Releasing 2.0a4 in a hurry                                            
00064 // %                                                                       
00065 // % Revision 1.4  1998/10/11 16:45:11  neeri                              
00066 // % Ready to release 2.0a2                                                
00067 // %                                                                       
00068 // % Revision 1.3  1998/08/01 21:26:18  neeri                              
00069 // % Switch dynamically to threading model                                 
00070 // %                                                                       
00071 // % Revision 1.2  1998/02/11 12:57:11  neeri                              
00072 // % PowerPC Build                                                         
00073 // %                                                                       
00074 // % Revision 1.1  1998/01/25 21:02:41  neeri                              
00075 // % Engine implemented, except for signals & scheduling                   
00076 // %                                                                       
00077 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
00078 //                                                                         
00079 // \chapter{Thread and Process structures}                                 
00080 //                                                                         
00081 // This section defines the process and thread switching engine of GUSI.   
00082 //                                                                         
00083 // In some execution environments, completion routines execute at interrupt level.
00084 // GUSI therefore is designed so all information needed to operate from interrupt
00085 // level is accessible from a [[GUSISocket]]. This information is separated into
00086 // per-process data, collected in [[GUSIProcess]], and per-thread data, collected 
00087 // in [[GUSIContext]]. [[GUSIProcess]] is always a singleton, while [[GUSIContext]]
00088 // is a singleton if threading is disabled, and has multiple instances if threading
00089 // is enabled. By delegating the [[GUSIContext]] creation process to an instance
00090 // of a [[GUSIContextFactory]], we gain some extra flexibility.            
00091 //                                                                         
00092 // As soon as GUSI has started an asynchronous call, it calls the [[Wait]] member
00093 // function of its context. [[msec]] will set a time limit after which the call will 
00094 // return in any case. Exceptional events may also cause [[GUSIWait]] to return, so 
00095 // it is not safe to assume that the call will have completed upon return. 
00096 //                                                                         
00097 //                                                                         
00098 // <GUSIContext.h>=                                                        
00099 #ifndef _GUSIContext_
00100 #define _GUSIContext_
00101 
00102 #include <errno.h>
00103 #include <sys/cdefs.h>
00104 #include <sys/signal.h>
00105 
00106 #include <MacTypes.h>
00107 #include <Threads.h>
00108 
00109 __BEGIN_DECLS
00110 // To maintain correct state, we have to remain informed which thread is active, so
00111 // we install all sorts of hooks. Clients have to use the C++ interface or call
00112 // [[GUSINewThread]], [[GUSISetThreadSwitcher]], and [[GUSISetThreadTerminator]].
00113 // instead of the thread manager routines.                                 
00114 //                                                                         
00115 // <Definition of thread manager hooks>=                                   
00116 OSErr GUSINewThread(
00117               ThreadStyle threadStyle, ThreadEntryProcPtr threadEntry, void *threadParam, 
00118               Size stackSize, ThreadOptions options, 
00119               void **threadResult, ThreadID *threadMade);
00120 OSErr GUSISetThreadSwitcher(ThreadID thread, 
00121               ThreadSwitchProcPtr threadSwitcher, void *switchProcParam, Boolean inOrOut);
00122 OSErr GUSISetThreadTerminator(ThreadID thread, 
00123               ThreadTerminationProcPtr threadTerminator, void *terminationProcParam); 
00124 __END_DECLS
00125 
00126 #ifndef GUSI_SOURCE
00127 
00128 typedef struct GUSIContext GUSIContext;
00129 
00130 #else
00131 
00132 #include "GUSISpecific.h"
00133 #include "GUSIBasics.h"
00134 #include "GUSIContextQueue.h"
00135 
00136 #include <Files.h>
00137 #include <Processes.h>
00138 #include <OSUtils.h>
00139 
00140 // \section{Definition of completion handling}                             
00141 //                                                                         
00142 // {\tt GUSIContext} is heavily circular both with classes declared herein and
00143 // in other files. Therefore, we start by declaring a few class names.     
00144 //                                                                         
00145 // <Name dropping for file GUSIContext>=                                   
00146 class GUSISocket;
00147 class GUSIContext;
00148 class GUSIProcess;
00149 class GUSISigProcess;
00150 class GUSISigContext;
00151 class GUSITimer;
00152 
00153 #include <ConditionalMacros.h>
00154 
00155 #if PRAGMA_STRUCT_ALIGN
00156 #pragma options align=native
00157 #endif
00158 
00159 // Ultimately, we will call through to the thread manager, but if an application uses foreign 
00160 // sources of threads, we might have to go through indirections.           
00161 //                                                                         
00162 // <Definition of class [[GUSIThreadManagerProxy]]>=                       
00163 class GUSIThreadManagerProxy {
00164 public:
00165        virtual OSErr NewThread(
00166                             ThreadStyle threadStyle, ThreadEntryProcPtr threadEntry, void *threadParam, 
00167                             Size stackSize, ThreadOptions options, void **threadResult, ThreadID *threadMade);
00168        virtual OSErr SetThreadSwitcher(
00169                             ThreadID thread, ThreadSwitchProcPtr threadSwitcher, void *switchProcParam, 
00170                             Boolean inOrOut);
00171        virtual OSErr SetThreadTerminator(
00172                             ThreadID thread, ThreadTerminationProcPtr threadTerminator, void *terminatorParam);
00173        
00174        virtual ~GUSIThreadManagerProxy() {}
00175        
00176        static GUSIThreadManagerProxy * Instance();
00177 protected:
00178        GUSIThreadManagerProxy()    {}
00179        
00180        static GUSIThreadManagerProxy * MakeInstance();
00181 };
00182 // A [[GUSIProcess]] contains all the data needed to wake up a process:    
00183 //                                                                         
00184 // \begin{itemize}                                                         
00185 // \item The [[ProcessSerialNumber]] of the process.                       
00186 // \item The [[ThreadTaskRef]] if threads are enabled.                     
00187 // \item The contents of the A5 register.                                  
00188 // \end{itemize}                                                           
00189 //                                                                         
00190 // The sole instance of [[GUSIProcess]] is obtained by calling the [[GUSIProcess::Instance]] static member
00191 // function, which will create the instance if necessary. Interrupt level prcedures may access the application's 
00192 // A5 register either manually by calling [[GetA5]] or simply by declaring a [[GUSIProcess::A5Saver]] in a scope.
00193 //                                                                         
00194 // <Definition of class [[GUSIProcess]]>=                                  
00195 enum GUSIYieldMode {
00196        kGUSIPoll,           // Busy wait for some unblockable condition
00197        kGUSIBlock,          // Wait for some blockable condition
00198        kGUSIYield           // Yield to some other eligible thread
00199 };
00200 
00201 class GUSIProcess {
00202 public:
00203        static GUSIProcess * Instance();
00204        static void                        DeleteInstance();
00205        void                               GetPSN(ProcessSerialNumber * psn);
00206        void                               AcquireTaskRef();
00207        ThreadTaskRef               GetTaskRef();
00208        long                               GetA5();
00209        bool                               Threading();
00210        void                               Yield(GUSIYieldMode wait);
00211        void                               Wakeup();
00212        GUSISigProcess *            SigProcess() { return fSigProcess; }
00213        void                               QueueForClose(GUSISocket * sock);
00214        // A [[GUSIProcess::A5Saver]] is a class designed to restore the process A5 
00215  // register for the scope of its declaration.                              
00216  //                                                                         
00217  // <Definition of class [[GUSIProcess::A5Saver]]>=                         
00218  class A5Saver {
00219  public:
00220        A5Saver(long processA5);
00221        A5Saver(GUSIContext * context);
00222        A5Saver(GUSIProcess * process);
00223        ~A5Saver();
00224  private:
00225        long   fSavedA5;
00226  };
00227 protected:
00228        friend class GUSIContext;
00229        
00230        GUSIProcess(bool threading);
00231        ~GUSIProcess();
00232        
00233        int                                       fReadyThreads;
00234        int                                       fExistingThreads;
00235        GUSISigProcess *            fSigProcess;
00236 private:
00237        // \section{Implementation of completion handling}                         
00238  //                                                                         
00239  // [[Instance]] returns the sole instance of [[GUSIProcess]], creating it if
00240  // necessary.                                                              
00241  //                                                                         
00242  // <Privatissima of [[GUSIProcess]]>=                                      
00243  static GUSIProcess *       sInstance;
00244  // Much of the information stored in a [[GUSIProcess]] is static and read-only.
00245  //                                                                         
00246  // <Privatissima of [[GUSIProcess]]>=                                      
00247  ProcessSerialNumber fProcess;
00248  ThreadTaskRef              fTaskRef;
00249  long                       fA5;
00250  // The exception is the [[fClosing]] socket queue and some yielding related flags.
00251  //                                                                         
00252  // <Privatissima of [[GUSIProcess]]>=                                      
00253  GUSISocket *        fClosing;
00254  UInt32                            fResumeTicks;
00255  bool                       fWillSleep;
00256  bool                       fDontSleep;
00257 };
00258 // A [[GUSIContext]] gathers thread related data. The central operation on a 
00259 // [[GUSIContext]] is [[Wakeup]]. If the process is not asleep when [[Wakeup]] 
00260 // is called, it is marked for deferred wakeup.                            
00261 //                                                                         
00262 // A [[GUSIContext]] can either be created from an existing thread manager 
00263 // [[ThreadID]] or by specifying the parameters for a [[NewThread]] call.  
00264 //                                                                         
00265 // [[Current]] returns the current [[GUSIContext]]. [[Setup]] initializes the
00266 // default context for either the threading or the non-threading model.    
00267 //                                                                         
00268 // [[Yield]] suspends the current process or thread until something interesting
00269 // happens if [[wait]] is [[kGUSIBlock]. Otherwise, [[Yield]] switches,    
00270 // but does not suspend. For an ordinary thread context, [[Yield]] simply yields 
00271 // the thread. For the context in a non-threading application, [[Yield]] does a 
00272 // [[WaitNextEvent]]. For the main thread context, [[Yield]] does both.    
00273 //                                                                         
00274 // [[Done]] tests whether the thread has terminated yet. If [[join]] is set,
00275 // the caller is willing to wait. [[Result]] returns the default location to store 
00276 // the thread result if no other is specified.                             
00277 //                                                                         
00278 // By default, a context is joinable. Calling [[Detach]] will cause the context to
00279 // be destroyed automatically upon thread termination, and joins are no longer allowed.
00280 // A joinable context will not be destroyed automatically before the end of the 
00281 // program, so you will have to call [[Liquidate]] to do that.             
00282 //                                                                         
00283 // [[SetSwitchIn]], [[SetSwitchOut]], and [[SetTerminator]] set per-thread user
00284 // switch and termination procedures. [[SwitchIn]], [[SwitchOut]], and [[Terminate]]
00285 // call the user defined procedures then perform their own actions.        
00286 //                                                                         
00287 // <Definition of class [[GUSIContext]]>=                                  
00288 class GUSIContext : public GUSISpecificTable {
00289 public:
00290        friend class GUSIProcess;
00291        friend class GUSIContextFactory;
00292        
00293        ThreadID                           ID()                 {      return fThreadID;                  }
00294        virtual void                Wakeup();
00295        void                               ClearWakeups()       { fWakeup = false;                 }
00296        GUSIProcess *               Process()            {      return fProcess;                   }
00297        void                               Detach()             {      fFlags |= detached;                }
00298        void                               Liquidate();
00299        OSErr                              Error()                     {      return sError;                            }
00300        bool                               Done(bool join);
00301        void *                             Result()             {   return fResult;                       }
00302        GUSISigContext *            SigContext()  {      return fSigContext;                }
00303 
00304        static GUSIContext * Current()            {      return sCurrentContext;            }
00305        static GUSIContext * CreateCurrent(bool threading = false)     
00306               {      if (!sCurrentContext) Setup(threading);   return sCurrentContext;     }
00307        static GUSIContext * Lookup(ThreadID id);
00308        static void                        Setup(bool threading);
00309        static bool                        Yield(GUSIYieldMode wait);
00310        static void                        SigWait(sigset_t sigs);
00311        static void                        SigSuspend();
00312        static bool                        Raise(bool allSigs = false);
00313        static sigset_t                    Pending();
00314        static sigset_t                    Blocked();
00315        
00316        void SetSwitchIn(ThreadSwitchProcPtr switcher, void *switchParam);
00317        void SetSwitchOut(ThreadSwitchProcPtr switcher, void *switchParam);
00318        void SetTerminator(ThreadTerminationProcPtr terminator, void *terminationParam);    
00319        
00320        static GUSIContextQueue::iterator  begin()       {      return sContexts.begin();   }
00321        static GUSIContextQueue::iterator  end()  {      return sContexts.end();            }
00322        static void   LiquidateAll()                                   {      sContexts.LiquidateAll();   }
00323 protected:
00324        // <Friends of [[GUSIContext]]>=                                           
00325  friend class GUSIContextFactory;
00326  // The thread switcher updates the pointer to the current context and switches
00327  // the global error variables.                                             
00328  //                                                                         
00329  // <Friends of [[GUSIContext]]>=                                           
00330  friend pascal void GUSIThreadSwitchIn(ThreadID thread, GUSIContext * context);
00331  friend pascal void GUSIThreadSwitchOut(ThreadID thread, GUSIContext * context);
00332  // The terminator wakes up the joining thread if a join is pending.        
00333  //                                                                         
00334  // <Friends of [[GUSIContext]]>=                                           
00335  friend pascal void GUSIThreadTerminator(ThreadID thread, GUSIContext * context);
00336 
00337        GUSIContext(ThreadID id);   
00338        GUSIContext(
00339               ThreadEntryProcPtr threadEntry, void *threadParam, 
00340               Size stackSize, ThreadOptions options = kCreateIfNeeded, 
00341               void **threadResult = nil, ThreadID *threadMade = nil);
00342 
00343        virtual void SwitchIn();
00344        virtual void SwitchOut();
00345        virtual void Terminate();
00346        
00347        // At this point, we need to introduce all the private data of a [[GUSIContext]].
00348  //                                                                         
00349  // \begin{itemize}                                                         
00350  // \item [[fThreadID]] stores the thread manager thread ID.                
00351  // \item [[fProcess]] keeps a pointer to the process structure, so completion 
00352  // routines can get at it.                                                 
00353  // \item [[sCurrentContext]] always points at the current context.         
00354  // \item [[sContexts]] contains a queue of all contexts.                   
00355  // \item [[sHasThreads]] reminds us whether we are threading or not.       
00356  // \item We define our own switch-in and termination procedures. If the user specifies procedures 
00357  // we store them in [[fSwitchInProc]], [[fSwitchOutProc]], and [[fTerminateProc]] and their parameters 
00358  // in [[fSwitchInParam]], [[fSwitchOutParam]], and [[fTerminateParam]] so we can call through to them 
00359  // from our procedures.                                                    
00360  // \item [[fJoin]] contains the context waiting for us to die;             
00361  // \item [[done]] reminds us if the thread is still alive. [[detached]] guarantees
00362  // that we will never wait for that thread anymore.                        
00363  // \item Last of all, we keep the global error variables [[errno]] and [[h_errno]] 
00364  // for each context in the [[fErrno]] and [[fHostErrno]] fields.           
00365  // \end{itemize}                                                           
00366  //                                                                         
00367  //                                                                         
00368  // <Privatissima of [[GUSIContext]]>=                                      
00369  ThreadID                                 fThreadID;    
00370  GUSIProcess *                            fProcess;
00371  GUSIContext *                            fNext;
00372  GUSISigContext *                  fSigContext;
00373  ThreadSwitchProcPtr               fSwitchInProc;
00374  ThreadSwitchProcPtr               fSwitchOutProc;
00375  ThreadTerminationProcPtr   fTerminateProc;
00376  void *                                          fSwitchInParam;
00377  void *                                          fSwitchOutParam;
00378  void *                                          fTerminateParam;
00379  void *                                          fResult;
00380  GUSIContext *                            fJoin;
00381  enum {
00382        done   = 1 << 0, 
00383        detached= 1 << 1,
00384        asleep = 1 << 2
00385  };
00386  char                                     fFlags;
00387  bool                                     fWakeup;
00388  UInt32                                          fEntryTicks;
00389  int                                             fErrno;
00390  int                                             fHostErrno;
00391 
00392  class Queue : public GUSIContextQueue {
00393  public:
00394        void LiquidateAll();
00395        
00396        ~Queue()                    { LiquidateAll(); }
00397  };
00398 
00399  static Queue               sContexts;
00400  static GUSIContext *       sCurrentContext;
00401  static bool                       sHasThreading;
00402  static OSErr               sError;
00403  // The [[GUSIContext]] constructor links the context into the queue of existing
00404  // contexts and installs the appropriate thread hooks. We split this into two 
00405  // routines: [[StartSetup]] does static setup before the thread id is determined,
00406  // [[FinishSetup]] does the queueing.                                      
00407  //                                                                         
00408  // <Privatissima of [[GUSIContext]]>=                                      
00409  void StartSetup();
00410  void FinishSetup();
00411  // Destruction of a [[GUSIContext]] requires some cleanup.                 
00412  //                                                                         
00413  // <Privatissima of [[GUSIContext]]>=                                      
00414  ~GUSIContext();
00415 };
00416 // [[GUSIContext]] instances are created by instances of [[GUSIContextFactory]].
00417 //                                                                         
00418 // <Definition of class [[GUSIContextFactory]]>=                           
00419 class GUSIContextFactory {
00420 public:
00421        static GUSIContextFactory * Instance();
00422        static void                        SetInstance(GUSIContextFactory * instance);
00423        
00424        virtual GUSIContext  * CreateContext(ThreadID id);
00425        virtual GUSIContext * CreateContext(
00426               ThreadEntryProcPtr threadEntry, void *threadParam, 
00427               Size stackSize, ThreadOptions options = kCreateIfNeeded, 
00428               void **threadResult = nil, ThreadID *threadMade = nil);
00429 
00430        virtual ~GUSIContextFactory();
00431 protected:
00432        GUSIContextFactory();
00433 };
00434 // Many asynchronous calls take the same style of I/O parameter block and thus
00435 // can be handled by the same completion procedure. [[StartIO]] prepares   
00436 // a parameter block for asynchronous I/O; [[FinishIO]] waits for the I/O  
00437 // to complete. The parameter block has to be wrapped in a [[GUSIIOPBWrapper]].
00438 //                                                                         
00439 // <Definition of IO wrappers>=                                            
00440 void GUSIStartIO(IOParam * pb);
00441 OSErr GUSIFinishIO(IOParam * pb);
00442 OSErr GUSIControl(IOParam * pb);
00443 template <class PB> struct GUSIIOPBWrapper {
00444        GUSIContext * fContext;
00445        PB                          fPB;
00446        
00447        GUSIIOPBWrapper()                         {}
00448        GUSIIOPBWrapper(const PB & pb)     { memcpy(&fPB, &pb, sizeof(PB));                 }
00449        
00450        PB * operator->(){ return &fPB;                                                                                 }
00451        void StartIO()        { GUSIStartIO(reinterpret_cast<IOParam *>(&fPB));                    }
00452        OSErr FinishIO() { return GUSIFinishIO(reinterpret_cast<IOParam *>(&fPB));   }
00453        OSErr Control()       { return GUSIControl(reinterpret_cast<IOParam *>(&fPB));      }
00454 };
00455 
00456 #if PRAGMA_STRUCT_ALIGN
00457 #pragma options align=reset
00458 #endif
00459 
00460 // <Inline member functions for file GUSIContext>=                         
00461 inline GUSIProcess * GUSIProcess::Instance()
00462 {
00463        if (!sInstance) 
00464               sInstance = new GUSIProcess(GUSIContext::sHasThreading);
00465        return sInstance;
00466 }
00467 inline void GUSIProcess::DeleteInstance()
00468 {
00469        delete sInstance;
00470        sInstance = 0;
00471 }
00472 // <Inline member functions for file GUSIContext>=                         
00473 inline void                 GUSIProcess::GetPSN(ProcessSerialNumber * psn)   
00474                                                  { *psn = fProcess;   }
00475 inline void                        GUSIProcess::AcquireTaskRef()
00476                                                  { GetThreadCurrentTaskRef(&fTaskRef); }
00477 inline ThreadTaskRef GUSIProcess::GetTaskRef()                        
00478                                                  { return fTaskRef;   }
00479 inline long                        GUSIProcess::GetA5()                                                  
00480                                                  { return fA5;        }
00481 inline bool                        GUSIProcess::Threading()                                              
00482                                                  { return fTaskRef!=0;}
00483 // An [[A5Saver]] is trivially implemented but it simplifies bookkeeping.  
00484 //                                                                         
00485 // <Inline member functions for file GUSIContext>=                         
00486 inline GUSIProcess::A5Saver::A5Saver(long processA5)           
00487        {      fSavedA5 = SetA5(processA5);                                   }
00488 inline GUSIProcess::A5Saver::A5Saver(GUSIProcess * process)
00489        {      fSavedA5 = SetA5(process->GetA5());                     }
00490 inline GUSIProcess::A5Saver::A5Saver(GUSIContext * context)
00491        {      fSavedA5 = SetA5(context->Process()->GetA5());   }
00492 inline GUSIProcess::A5Saver::~A5Saver()
00493        {      SetA5(fSavedA5);                                                      }
00494 
00495 #endif /* GUSI_SOURCE */
00496 
00497 #endif /* _GUSIContext_ */