| Tekkotsu Homepage | Demos | Overview | Downloads | Dev. Resources | Reference | Credits |
WorldStatePool.hGo to the documentation of this file.00001 //-*-c++-*- 00002 #ifndef INCLUDED_WorldStatePool_h_ 00003 #define INCLUDED_WorldStatePool_h_ 00004 00005 #include "WorldState.h" 00006 #include "IPC/MutexLock.h" 00007 #include "IPC/ListMemBuf.h" 00008 #include "Shared/Resource.h" 00009 #include "Motion/PostureEngine.h" 00010 #include <stdexcept> 00011 00012 class RCRegion; 00013 00014 #ifndef WORLDSTATEPOOL_NUM_STATES 00015 //! provides default value for WorldStatePool::NUM_STATES, allows you to override from build settings, without touching source 00016 #define WORLDSTATEPOOL_NUM_STATES 3 00017 #endif 00018 00019 //! holds multiple instances of WorldState, allows one process to be updating while another is reading 00020 /*! 00021 Use the AutoGetReadState and AutoGetWriteState to access individual WorldState entries... their 00022 constructors and destructors allow WorldStatePool to keep track of which entries are in use. 00023 00024 When a state wants to write, it is given the oldest unused entry to write into. During writing, 00025 other accessors can read the newest (complete) entry, or concurrently write into a different 00026 entry (in case they don't want to wait for the other process to finish). 00027 00028 A global lock (#lock) is used while choosing an entry, and individual locks (#writeLocks) are 00029 used while writing into entries (to easily allow readers to block on the lock until writing is done) 00030 00031 One point of trickiness is that entries being written are moved to the end of the list when 00032 the writing begins, not when it is complete. Readers can always scan backwards in the list 00033 to find the newest entries, but writers must check the end to see if newer (or equivalent) 00034 frames are already in progress, as well as the beginning to find the oldest unreferenced. 00035 00036 When a writer tries to access an entry, and another writer is already processing that frame, 00037 if blocking is set then the writer will given that entry once the original is done with it (so 00038 check your frame index when you receive it so you can tell if it was already processed). 00039 If blocking is *not* set, then you will get a separate entry with no indication another process 00040 is also working on the same frame. 00041 */ 00042 class WorldStatePool : public Resource { 00043 public: 00044 class Request : public Resource::Data { 00045 protected: 00046 //! constructor, sets the WorldState point to be assigned, whether to block, and whether is an instance of ReadRequest 00047 /*! @a wantRead is because we can't trust RTTI (i.e. dynamic_cast) to work correctly on Aperios :( */ 00048 Request(WorldState*& target, bool block, bool wantRead) : Resource::Data(), 00049 bufUsed(-1U), tgt(target), prev(NULL), bl(block), depth(0), isRead(wantRead) 00050 {} 00051 //! shallow copy constructor supported 00052 Request(const Request& r) : Resource::Data(r), bufUsed(r.bufUsed), tgt(r.tgt), prev(r.prev), bl(r.bl), depth(r.depth), isRead(r.isRead) {} 00053 //! shallow assignment supported 00054 Request& operator=(const Request& r) { bufUsed=r.bufUsed; tgt=r.tgt; prev=r.prev; bl=r.bl; depth=r.depth; Resource::Data::operator=(r); return *this; } 00055 00056 public: 00057 unsigned int bufUsed; //!< the entry index used 00058 WorldState*& tgt; //!< reference to pointer, which is set to an element of the pool when the request goes through 00059 WorldState* prev; //!< stores previous value at #tgt so it can be restored upon release (needed to support recursive usage) 00060 bool bl; //!< whether to block if a write is in progress, or use most recent "complete" entry 00061 unsigned int depth; //!< supports recursive read requests 00062 bool isRead; //!< true if instance is a read request 00063 }; 00064 //! retrieves the current WorldState entry, and through it's destructor, marks the entry available again when it goes out of scope 00065 class ReadRequest : public Request { 00066 public: 00067 //! stores the current completed WorldState into #tgt, optionally blocking if an update is in progress (otherwise it returns the previous completed entry) 00068 ReadRequest(WorldState*& target, bool block) : Request(target,block,true) {} 00069 //! shallow copy constructor supported 00070 ReadRequest(const ReadRequest& r) : Request(r) {} 00071 //! shallow assignment supported 00072 ReadRequest& operator=(const ReadRequest& r) { Request::operator=(r); return *this; } 00073 }; 00074 //! retrieves the current WorldState entry, and through it's destructor, marks the entry available again when it goes out of scope 00075 /*! By default, when the release occurs, the entry is marked "complete" unless you have called setComplete(false) before then */ 00076 class WriteRequest : public Request { 00077 public: 00078 //! stores the oldest unreferenced WorldState into #tgt, optionally blocking if an update is currently in progress for the same frame 00079 WriteRequest(WorldState*& target, bool block, unsigned int frame_number) : Request(target,block,false), 00080 src(NULL), srcRequest(src,false), frame(frame_number), statusCache(0), completeCache(false) 00081 {} 00082 //! shallow copy constructor supported 00083 WriteRequest(const WriteRequest& r) : Request(r), src(r.src), srcRequest(r.srcRequest), frame(r.frame), statusCache(r.statusCache), completeCache(r.completeCache) {} 00084 //! shallow assignment supported 00085 WriteRequest& operator=(const WriteRequest& r) { src=r.src; srcRequest=r.srcRequest; frame=r.frame; statusCache=r.statusCache; completeCache=r.completeCache; Request::operator=(r); return *this; } 00086 00087 WorldState* src; //!< will be set to the previously written element, so you can copy over unmodified values 00088 ReadRequest srcRequest; //!< used to get #src 00089 unsigned int frame; //!< should be initialized to the frame number about to be written 00090 00091 unsigned int getStatus() const { return statusCache; } //!< returns the WorldStatePool::status value for the target WorldState entry (see documentation for WorldStatePool::status) 00092 void setStatus(unsigned int status) { statusCache=status; } //!< sets the WorldStatePool::status value for the target WorldState entry (see documentation for WorldStatePool::status) 00093 bool getComplete() const { return completeCache; } //!< returns the WorldStatePool::complete value for the target WorldState entry (see documentation for WorldStatePool::complete) 00094 void setComplete(bool complete) { completeCache=complete; } //!< returns the WorldStatePool::complete value for the target WorldState entry (see documentation for WorldStatePool::complete) 00095 00096 protected: 00097 unsigned int statusCache; //!< when using resource, this field is set to the status field for that entry, and when released, this value is stored back 00098 bool completeCache; //!< when using resource, this field is set to the complete flag for that entry, and when released, this value is stored back 00099 }; 00100 00101 //! constructor 00102 WorldStatePool(); 00103 00104 #ifdef PLATFORM_APERIOS 00105 //! returned by isUnread containing information parsed from the incoming message 00106 class UpdateInfo { 00107 public: 00108 //! constructor, sets #msg to NULL, #frameNumber to -1U 00109 UpdateInfo() 00110 #ifdef DEBUG 00111 : msg(NULL), frameNumber(-1U), intendedBuf(-1U) {} 00112 #else 00113 : msg(NULL), frameNumber(-1U) {} 00114 #endif 00115 OSensorFrameVectorData* msg; //!< incoming data 00116 unsigned int frameNumber; //!< serial number of the message 00117 #ifdef DEBUG 00118 unsigned int intendedBuf; //!< the write buffer read() is expected to use; This is for debugging, if this isn't the buffer selected, display warning 00119 #endif 00120 private: 00121 UpdateInfo(const UpdateInfo&); //!< not implemented 00122 UpdateInfo operator=(const UpdateInfo&); //!< not implemented 00123 }; 00124 00125 //! returns true if the process should call WorldState::read (i.e. @a msg has new or unprocessed data (such as motion needs to supply feedback)) 00126 /*! only one call to this can be made at a time per process (not threadsafe, but is multi-process safe) 00127 * @param msg the incoming sensor data from the system -- should be const, but accessor functions from Sony aren't marked const themselves :-/ 00128 * @param[out] lastFrameNumber if the incoming frame is already complete (no need to read), then the frame's number will be assigned here 00129 * @return returns a static UpdateInfo structure (to be passed to read()) if the message is unread, otherwise returns NULL. The structure is static -- DO NOT DELETE IT */ 00130 WorldStatePool::UpdateInfo* isUnread(OSensorFrameVectorData& msg, unsigned int& lastFrameNumber); 00131 00132 #else //PLATFORM_LOCAL 00133 //! flags for the status field on each WriteRequest -- tracks partial completion when multiple writers are involved 00134 enum status_t { 00135 SENSORS_APPLIED=1<<0, //!< bit flag signals sensor data has been applied to the write target 00136 FEEDBACK_APPLIED=1<<1 //!< bit flag signals motion feedback has been applied to the write target (only required if feedback is being generated) 00137 }; 00138 00139 //! returned by isUnread containing information parsed from the incoming message 00140 class UpdateInfo { 00141 public: 00142 UpdateInfo() 00143 #ifdef DEBUG 00144 : verbose(false), frameNumber(-1U), filename(), dataInQueue(false), payload(NULL), payloadSize(0), intendedBuf(-1U) {} 00145 #else 00146 : verbose(false), frameNumber(-1U), filename(), dataInQueue(false), payload(NULL), payloadSize(0) {} 00147 #endif 00148 bool verbose; //!< status of processing the message should be displayed 00149 unsigned int frameNumber; //!< serial number of the message 00150 std::string filename; //!< source of the data in the message 00151 bool dataInQueue; //!< sender indicates data is in the queue (if this is heartbeat, treat it as data) 00152 char* payload; //!< pointer to beginning of the data (NULL if no data available, i.e. heartbeat message) 00153 unsigned int payloadSize; //!< size of data (0 if no data available, i.e. heartbeat message) 00154 #ifdef DEBUG 00155 unsigned int intendedBuf; //!< the write buffer read() is expected to use; This is for debugging, if this isn't the buffer selected, display warning 00156 #endif 00157 private: 00158 UpdateInfo(const UpdateInfo&); //!< not implemented 00159 UpdateInfo operator=(const UpdateInfo&); //!< not implemented 00160 }; 00161 00162 //! returns true if the process should call read (i.e. @a msg has new or unprocessed data (such as motion needs to supply feedback)) 00163 /*! only one call to this can be made at a time per process (not threadsafe, but is multi-process safe) 00164 * @param msg incoming message to test 00165 * @param curFrameNumber the most recent frame number sent, i.e. SharedGlobals::MotionSimConfig::frameNumber 00166 * @param[out] lastFrameNumber if the incoming frame is already complete (no need to read), then the frame's number will be assigned here 00167 * @param haveFeedback you should pass true if motion feedback <em>can be</em> provided to read() (note the feedback doesn't necessarily need to be available right now, just if the call to read is necessary) 00168 * @param motionOverride true if motion feedback overrides sensor data (i.e SharedGlobals::MotionSimConfig::override) 00169 * @return returns a static UpdateInfo structure (to be passed to read()) if the message is unread, otherwise returns NULL. The structure is static -- DO NOT DELETE IT */ 00170 WorldStatePool::UpdateInfo* isUnread(const RCRegion& msg, unsigned int curFrameNumber, unsigned int& lastFrameNumber, bool haveFeedback, bool motionOverride); 00171 //! takes a sensor update from the simulator/system, updates an entry in the pool with the new information 00172 /*! If isUnread() returns non-NULL, you should acquire a WriteRequest, and check that it succeeds, is current, and is still incomplete, before calling read() 00173 * @param info the info structure returned by isUnread 00174 * @param wsw the WriteRequest aquired before calling read (yes, you should submit a WriteRequest for @a info.frameNumber between isUnread() and read()) 00175 * @param feedbackGenerated pass true if feedback will be generated by a caller to read() -- doesn't need to be <em>this</em> process, but <em>a</em> process. 00176 * @param zeroPIDFeedback pass true if sensor data should override motion feedback for joints with 0's for PID control (i.e. SharedGlobals::MotionSimConfig::zeroPIDFeedback) 00177 * @param feedback pointer to actual motion feedback, or NULL if not available in this process (weight values of feedback are ignored, assumes all values are valid) */ 00178 bool read(const UpdateInfo& info, WriteRequest& wsw, bool feedbackGenerated, bool zeroPIDFeedback, const PostureEngine* feedback=NULL); 00179 #endif 00180 00181 //! processes a request, passed as either a ReadRequest or WriteRequest, to access an entry in the pool 00182 virtual void useResource(Data& d) { doUseResource(d); } 00183 //! completes access to an entry in the pool, you must pass the same request instance here which you originally passed to useResource() 00184 virtual void releaseResource(Data& d) { doReleaseResource(d); } 00185 00186 //! does the actual work of useResource() 00187 /*! this is split off as a non-virtual function to avoid some process 00188 * identity issues that occur with virtual functions under Aperios */ 00189 void doUseResource(Data& d); 00190 //! does the actual work of releaseResource() 00191 /*! this is split off as a non-virtual function to avoid some process 00192 * identity issues that occur with virtual functions under Aperios */ 00193 void doReleaseResource(Data& d); 00194 00195 #ifdef PLATFORM_APERIOS 00196 //! registers #stateLookupMap with WorldState::setWorldStateLookup() 00197 void InitAccess() { WorldState::setWorldStateLookup(stateLookupMap); } 00198 #endif 00199 00200 protected: 00201 //! number of buffers to set up 00202 static const unsigned int NUM_STATES=WORLDSTATEPOOL_NUM_STATES; 00203 00204 //! shorthand for the type of #order 00205 typedef ListMemBuf<unsigned int, NUM_STATES> order_t; 00206 //! indicies of entries, in the order they were written (i.e. corresponding value in #frames should be monotonically increasing) 00207 order_t order; 00208 00209 //! shorthand to test if all three P, I, and D values are 0 for the specified joint index (relative to 0, not PIDJointOffset) 00210 static bool isZeroPID(WorldState* s, unsigned int i) { return s->pids[i][0]==0 && s->pids[i][1]==0 && s->pids[i][2]==0; } 00211 00212 //! called when access to an entry for reading is requested 00213 unsigned int getCurrentReadState(WorldState*& tgt, bool block); 00214 //! called when an read access to an entry is complete 00215 void doneReadingState(unsigned int i); 00216 00217 //! returns true if the specified element of #states has been marked completed 00218 bool isComplete(unsigned int idx) const; 00219 //! returns index of buffer in #states to use for write request 00220 unsigned int selectWriteState(unsigned int frame, bool block) const { order_t::index_t idx; return selectWriteState(frame,block,idx); } 00221 //! returns index of buffer in #states to use for write request, stores index of corresponding entry of #order in @a idx 00222 unsigned int selectWriteState(unsigned int frame, bool block, order_t::index_t& idx) const; 00223 //! called when access to an entry for writing is requested 00224 unsigned int getCurrentWriteState(WorldState*& tgt, unsigned int frame, bool block); 00225 //! called when an write access to an entry is complete 00226 void doneWritingState(unsigned int i, bool completed); 00227 00228 //! entries to hand out 00229 WorldState states[NUM_STATES]; 00230 //! serial numbers of corresponding entries in #states, set when writing begins, should be monotonically increasing relative to #order (i.e. if you run through #order and look at corresponding values in #frames, should be monotonically increasing serial numbers) 00231 unsigned int frames[NUM_STATES]; 00232 //! flag set when a reader is blocking for writing to finish, until read is satisified 00233 unsigned int reading[NUM_STATES]; 00234 //! count of writers in line for access (occurs when a writer is blocking on another writer of the same frame, or no other frames are free) 00235 unsigned int writing[NUM_STATES]; 00236 //! the status is intended as a bitfield to support communication between writers if they need to cooperatively fill out an entry 00237 /*! The value is set to 0 before handing out to a writer with a new frame number */ 00238 unsigned int status[NUM_STATES]; 00239 #ifdef PLATFORM_APERIOS 00240 //! this lock indicates/controls whether the state is available for reading 00241 /*! The lock is set before handing out to a writer with a new frame number, and released 00242 * when a writer has marked the entry complete (via the WriteRequest upon releaseResource()) */ 00243 MutexLock<ProcessID::NumProcesses> complete[NUM_STATES]; 00244 #else 00245 //! this semaphore is set to positive value when writing begins, and then lowered to zero when complete 00246 /*! A semaphore is used on "normal" systems because the MutexLock also implies a 00247 * thread lock, which we actually don't want in this case because a different thread 00248 * may complete the entry than the one which started it. Since Aperios does not allow 00249 * multithreading, we don't have to worry about it there. 00250 * 00251 * As an aside, we @e could use this to store #writing, but that would only be feasible if 00252 * Aperios gave us semaphores. Bah. */ 00253 SemaphoreManager::semid_t complete[NUM_STATES]; 00254 #endif 00255 00256 //! locks to be acquired before handing out corresponding #states entry for writing 00257 MutexLock<ProcessID::NumProcesses> writeLocks[NUM_STATES]; 00258 //! lock on WorldStatePool's own members 00259 MutexLock<ProcessID::NumProcesses> lock; 00260 00261 #ifdef PLATFORM_APERIOS 00262 //! the current state in use by each process 00263 WorldState* stateLookupMap[ProcessID::NumProcesses]; 00264 #endif 00265 00266 private: 00267 WorldStatePool(const WorldStatePool&); //!< this shouldn't be called... 00268 WorldStatePool& operator=(const WorldStatePool&); //!< this shouldn't be called... 00269 }; 00270 00271 /*! @file 00272 * @brief 00273 * @author Ethan Tira-Thompson (ejt) (Creator) 00274 * 00275 * $Author: ejt $ 00276 * $Name: tekkotsu-3_0 $ 00277 * $Revision: 1.15 $ 00278 * $State: Exp $ 00279 * $Date: 2006/09/19 05:39:33 $ 00280 */ 00281 00282 #endif |
|
Tekkotsu v3.0 |
Generated Wed Oct 4 00:03:47 2006 by Doxygen 1.4.7 |