Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

/magnus/back_end/SessionManager/include/Supervisor.h

Go to the documentation of this file.
00001 /*
00002  *   $Id: Supervisor.h,v 1.10 1998/05/14 19:47:41 bormotov Exp $
00003  */
00004  
00005 // Copyright (C) 1995 The New York Group Theory Cooperative
00006 // See magnus/doc/COPYRIGHT for the full notice.
00007 //
00008 // Contents: Declaration of mixin class Supervisor and helpers
00009 //
00010 // Principal Author: Roger Needham, Dmitry Bormotov
00011 //
00012 // Status: in progress
00013 //
00014 // Revision History:
00015 //
00016 // * 7/96 Dmitry B. made porting to gcc 2.7.2.
00017 //
00018 // * 06/97 @db added new functions:
00019 //
00020 //   virtual bool Supervisor::isSupervisor() const;
00021 //   void Supervisor::supervise( );
00022 //
00023 
00024 
00025 #ifndef _SUPERVISOR_H_
00026 #define _SUPERVISOR_H_
00027 
00028 
00029 #include "ARC.h"
00030 #include "ARCSlotID.h"
00031 #include "OID.h"
00032 #include "Associations.h"
00033 #include "viewStructure.h"
00034 #include "ComputationManager.h"
00035 #include "TheObjects.h"
00036 
00037 
00038 // A computation manager (CM) might supervise a fixed number (i.e., known
00039 // at compile time) of other CMs. We must support this functionality:
00040 // 
00041 //   - The subordinate CMs may need to be exported to the rest of the
00042 //     system, so that resources may be allocated to them, and they can
00043 //     be queried for results.
00044 // 
00045 //   - A subordinate CM should not be created (and thus consume memory
00046 //     and CPU time) until it is asked for.
00047 // 
00048 //   - Messages may arrive instructing the supervising CM to allocate
00049 //     resources to a subordinate, so the latter must be located
00050 //     easily. Since it may not exist at the time the FE is told about
00051 //     its *potential* existence, the FE cannot refer to an object id.
00052 // 
00053 // 
00054 // The facilities declared here automate this process. When a computation
00055 // manager `boss' of class B is to supervise a subordinate computation
00056 // manager of class W, B has a data member `worker' of class
00057 // Subordinate<B,W>. If worker is to be exported, this member is public.
00058 // The members of the W are accessed via the overloaded -> operator. For
00059 // example:
00060 // 
00061 //     if ( boss.worker->state() == ComputationManager::RUNNING ) ...
00062 // 
00063 // The operator invocation creates the W if necessary.
00064 // 
00065 // The reason that Subordinate<B,W> does not return a W& is that someone
00066 // might erroneously store the W& as, for example, a class data
00067 // member. The problem is that the system may not know about this
00068 // dependence on the W, so the W may be deleted, leaving a dangling
00069 // reference.
00070 // 
00071 // Now, it it possible to extract the W* from operator->(), and this is
00072 // safe within a function body, but you must NEVER, *EVER* STORE THE
00073 // RESULT OF operator->() beyond the duration of a function body. This
00074 // would create the worst possible bug: one that is unlikely to turn up
00075 // *even in testing*, since it depends on just the right sequence of end
00076 // user events. The convoluted syntax of operator->() should remind you
00077 // of this dire peril.
00078 // 
00079 // There appears to be no better solution. One could return an
00080 // intermediate object, with disabled copying, which duplicates the
00081 // needed parts of W's interface. One could arrange that the object is
00082 // always a temporary, so that attempts to store a reference or its
00083 // address would (hopefully) trigger a compiler warning. But it must be
00084 // the case that a sufficiently complex expression would evaluate to the
00085 // illicit reference or pointer, but fool the compiler. In fact, try
00086 // compiling this with gcc 2.6.3 and -Wall:
00087 //  
00088 //  #include <iostream.h>
00089 //  
00090 //  struct Foo { ~Foo( ) { cerr << "Kiss your Foo goodbye!\n" << flush; } };
00091 //  
00092 //  struct Bar {
00093 //    Bar(const Foo& f) : F( f ) { }
00094 //    ~Bar( ) { cerr << "Kiss your Bar goodbye!\n" << flush; }
00095 //    const Foo& F;
00096 //  };
00097 //  
00098 //  struct Baz {
00099 //    Baz(const Foo& f) : B( f ) { }
00100 //    Bar B;
00101 //  };
00102 //  
00103 //  main( ) {
00104 //    Baz* Bp = new Baz( Foo() );
00105 //    cerr << "I have not deleted Bp yet!\n" << flush;
00106 //    delete Bp;
00107 //  }
00108 //
00109 // 
00110 // In some cases, a computation manager might `supervise' another only in
00111 // that it presents a view to the end user for passing ARCs to a CM,
00112 // which is actually supervised by a third CM. For this case, we use
00113 // class MirrorSubordinate.
00114 // 
00115 // The facilites here can not be used for CMs, like the nilpotent
00116 // quotients CM, which must supervise an unbounded number of subordinate
00117 // CMs (class 2, class 3, ...).
00118 //
00119 // The mixin class Supervisor arranges for locating subordinate CMs, given
00120 // a `virtual OID', called, for `historical' reasons, an ARCSlotID.
00121 
00122 
00123 //---------------------------------------------------------------------------//
00124 //--------------------------- Subordinate -----------------------------------//
00125 //---------------------------------------------------------------------------//
00126 
00127 // As usual, we cannot hide a template class in class Supervisor.
00128 
00129 class SubordinateBase
00130 {
00131 public:
00132 
00133   SubordinateBase(class Supervisor& boss);
00134 
00135   ARCSlotID arcSlotID( ) const { return asi; }
00136   // This is used by class Supervisor as a `virtual OID'. That is, a
00137   // derivative of SubordinateBase can announce that either it wraps a
00138   // ComputationManager now, or will do in the future. The ARCSlotID
00139   // is the means by which the FE refers to this `virtual'
00140   // ComputationManager, since it may not have a real OID yet.
00141 
00142   virtual Supervisor& getBoss( ) const = 0;
00143 
00144   virtual ComputationManager* getWorker( ) const = 0;
00145 
00146   virtual void terminateWorker( ) = 0;
00147 
00148   virtual void deleteWorker() = 0;
00149   
00150   virtual bool exists( ) const = 0;
00151   // For querying existence of subordinate without triggering same.
00152 
00153   
00154 protected:
00155 
00156   friend class Supervisor;
00157 
00158   virtual void acceptAllocation(OID oid, ARCSlotID, ARC, bool overrides=true)=0;
00159   // Used by class Supervisor.
00160 
00161   void addDependent( SMObject& smo, OID oid ) const;
00162   // So derivatives need not be friends of SMObject.
00163 
00164 private:
00165 
00166   SubordinateBase( const SubordinateBase& );
00167   // Hidden, not to be implemented.
00168 
00169   ARCSlotID asi;
00170 };
00171 
00172 
00173 // Class Subordinate<B,W> assumes that:
00174 //
00175 //  1) Class B derives from class Supervisor.
00176 //  2) Class W derives from class ComputationManager.
00177 //  3) Class W has a constructor which takes a B.
00178 
00179 template <class B, class W> class Subordinate : public SubordinateBase
00180 {
00181 
00182 friend class MirrorSubordinate;
00183   
00184 public:
00185 
00186   Subordinate(B& boss)
00187     : SubordinateBase( boss ), theBoss( boss ), theWorker( 0 )
00188   { }
00189 
00190   // This does not need a dtor; since *theWorker is a dependent of the
00191   // supervisor, TheObjects deletes *theWorker when it deletes the
00192   // supervisor.
00193 
00194   // *** DANGER *** see below *** DANGER *** //
00195   W* operator -> ( ) {
00196          if ( ! theWorker ) {
00197                 theWorker = new W( theBoss );
00198                 theWorker->attachClient( theBoss );
00199                 addDependent( theBoss, theWorker->oid() );
00200          }
00201          return theWorker;
00202   }
00203   // *** YOU MUST NEVER, EVER STORE THE W* EXCEPT AS AN AUTOMATIC *** //
00204   // *** VARIABLE IN A FUNCTION BODY. See the comments above.     *** //
00205   // This is inlined for now to avoid the explicit template instantiation
00206   // required by gcc 2.6.3.
00207 
00208   Supervisor& getBoss( ) const { return theBoss; } // overrides SubordinateBase
00209 
00210   ComputationManager* getWorker( ) const { return theWorker; }
00211   // overrides SubordinateBase
00212 
00213   void terminateWorker( )
00214   {
00215       if ( theWorker ){
00216          theWorker->adminTerminate();
00217          deleteWorker();
00218       }
00219   }
00220 
00221   bool exists( ) const { return theWorker != 0; }  // overrides SubordinateBase
00222 
00223 protected:
00224 
00225   void acceptAllocation(OID oid, ARCSlotID asi, ARC arc, bool overrides) {
00226          // Overrides SubordinateBase.
00227          // Do not make theWorker only to give it 0 ARCs:
00228          if ( theWorker || arc ) {
00229                 ( operator->() )->acceptAllocation( oid, asi, arc, overrides );
00230          }
00231   }
00232 
00233 private:
00234 
00235   void deleteWorker()
00236   {
00237     TheObjects::remove( theWorker->oid() );
00238     theWorker = 0;
00239   }
00240   
00241   //Data members:
00242   
00243   B& theBoss;
00244   
00245   W* theWorker;
00246 };
00247 
00248 
00249 class MirrorSubordinate : public SubordinateBase
00250 {
00251 public:
00252 
00253   MirrorSubordinate(class Supervisor& boss, SubordinateBase&);
00254 
00255   Supervisor& getBoss( ) const { return theBoss; }
00256   // overrides SubordinateBase
00257 
00258   bool exists( ) const { return mirror.exists(); }
00259   // overrides SubordinateBase
00260 
00261   ComputationManager* getWorker( ) const;
00262   // overrides SubordinateBase
00263   //@db temporary hack
00264 
00265   void terminateWorker( );
00266 
00267   void deleteWorker(); 
00268   
00269 protected:
00270 
00271   void acceptAllocation(OID oid, ARCSlotID asi, ARC arc, bool overrides);
00272   // Overrides SubordinateBase.
00273 
00274 private:
00275 
00276   class Supervisor& theBoss;
00277 
00278   SubordinateBase& mirror;
00279 
00280   bool firstAccessToWorker;
00281 };
00282 
00283 
00284 //---------------------------------------------------------------------------//
00285 //--------------------------- Supervisor ------------------------------------//
00286 //---------------------------------------------------------------------------//
00287 
00288 // The purpose of class Supervisor is only to allow for locating the
00289 // appropriate Subordinate, given its ARCSlotID. In cooperation with
00290 // the SubordinateBase ctor, this assigns ARCSlotIDs.
00291 
00292 class Supervisor : public ComputationManager
00293 {
00294 public:
00295   
00296   bool isSupervisor( ) const { return true; }
00297 
00298   void supervise( );
00299   // checks and conrols dependents, then calls it's own takeControl()
00300   
00301 protected:
00302 
00303   friend MirrorSubordinate;
00304 
00305   Supervisor( bool display_in_fe )
00306     : ComputationManager( display_in_fe ), ARCSlotID_Counter( 1 ),
00307       theParameters( NULL )
00308   { 
00309     if( display_in_fe ) 
00310       attachClient( *this );
00311   }
00312 
00313   void readMessage(istream& istr);  // Overrides ComputationManager
00314 
00315   void forwardAllocation(OID oid, ARCSlotID to, ARCSlotID from, ARC arc,
00316                          bool overrides);
00317 
00318   void adminTerminate( );
00319   
00320   void submit(ostream& ostr,const EnumertatorProblemView& pv) const {
00321     Supervisor* This = (Supervisor* )this;
00322     This->theParameters = new ParameterStructure(pv.extractParameters());
00323     pv.done( ostr );
00324   }
00325   
00326   const ParameterStructure& getParameters()const{
00327     if (theParameters == NULL)
00328       error("const ParameterStructure& getParameters()const : "
00329             "viewStructure was not submited yet.");
00330     return *theParameters;
00331   }
00332   
00333 private:
00334 
00335   SubordinateBase* dereference(ARCSlotID asi) const;
00336   // This returns the SubordinateBase with the given ARCSlotID. For
00337   // robustness, it may return 0 if something has gone wrong.
00338 
00339   /////////////////////////////////////////////////////////////////////////
00340   //                                                                     //
00341   // `Public' Members Touched by Friends:                                //
00342   //                                                                     //
00343   /////////////////////////////////////////////////////////////////////////
00344 
00345   friend class SubordinateBase;
00346 
00347   ARCSlotID hire( SubordinateBase* worker );
00348 
00349   /////////////////////////////////////////////////////////////////////////
00350   //                                                                     //
00351   // Data Members:                                                       //
00352   //                                                                     //
00353   /////////////////////////////////////////////////////////////////////////
00354 
00355   AssociationsOf<int,SubordinateBase*> theWorkers;
00356   AssociationsOf<int,bool> theCrashedWorkers;
00357 
00358   int ARCSlotID_Counter;
00359   // By convention, ARCSlotID 0 always refers to the supervisor, so
00360   // this counter starts at 1.
00361 
00362    ParameterStructure* theParameters;
00363 
00364 };
00365 
00366 
00367 //---------------------------------------------------------------------------//
00368 //----------------------- UnboundedSupervisor -------------------------------//
00369 //---------------------------------------------------------------------------//
00370 
00371 // This is an experimental class (ok, kludge) which allows supervisors of
00372 // an unbounded number of CMs to get ad hoc access to private methods of
00373 // TheObjects and SMObject.
00374 
00375 class UnboundedSupervisor : public ComputationManager
00376 {
00377 protected:
00378 
00379   UnboundedSupervisor( bool display_in_fe )
00380     : ComputationManager( display_in_fe )
00381   { }
00382 
00383   void remove(OID oid) { TheObjects::remove( oid ); }
00384 
00385   void addDependent(OID oid) { SMObject::addDependent( oid ); }
00386 
00387 };
00388 
00389 #endif

Generated at Tue Jun 19 09:49:39 2001 for Magnus Classes by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001