| 1 | // This may look like C code, but it is really -*- C++ -*- | 
|---|
| 2 |  | 
|---|
| 3 | // ArchTOIPipe           (C)     CEA/DAPNIA/SPP IN2P3/LAL | 
|---|
| 4 | //                               Eric Aubourg | 
|---|
| 5 | //                               Christophe Magneville | 
|---|
| 6 | //                               Reza Ansari | 
|---|
| 7 | // $Id: toisegment.h,v 1.18 2002-03-23 23:05:22 aubourg Exp $ | 
|---|
| 8 |  | 
|---|
| 9 | #ifndef TOISEGMENT_H | 
|---|
| 10 | #define TOISEGMENT_H | 
|---|
| 11 |  | 
|---|
| 12 | #include "config.h" | 
|---|
| 13 | #include <vector> | 
|---|
| 14 | #include <set> | 
|---|
| 15 |  | 
|---|
| 16 | #include "toi.h" | 
|---|
| 17 |  | 
|---|
| 18 | // ------------ TOISegmented ------------------------------ | 
|---|
| 19 | // Classe de TOI pour echantillonage regulier, avec buffer | 
|---|
| 20 | // segmente pour optimiser le multithread et limiter les | 
|---|
| 21 | // verrous. | 
|---|
| 22 | // Il faut que les fournisseurs fassent arriver les donnees | 
|---|
| 23 | // par samplenum croissant et continu. | 
|---|
| 24 | // -------------------------------------------------------- | 
|---|
| 25 |  | 
|---|
| 26 | class TOISegmented : public TOIRegular { | 
|---|
| 27 | public: | 
|---|
| 28 | TOISegmented(int bufsz=1024, int maxseg=20); | 
|---|
| 29 | TOISegmented(string nm, int bufsz=1024, int maxseg=20); | 
|---|
| 30 | TOISegmented(char* cnm, int bufsz=1024, int maxseg=20); | 
|---|
| 31 | ~TOISegmented(); | 
|---|
| 32 |  | 
|---|
| 33 | virtual double        getData(int i); | 
|---|
| 34 | virtual void          getData(int i, double& data,  uint_8& flag); | 
|---|
| 35 | virtual void          getData(int i, int n, double* data, uint_8* flg=0); | 
|---|
| 36 | virtual void          putData(int i, double  value, uint_8  flag=0); | 
|---|
| 37 | virtual void          putData(int i, int n, double const* val, uint_8 const* flg=0); | 
|---|
| 38 | virtual void          wontNeedBefore(int i); | 
|---|
| 39 | virtual void          putDone(); | 
|---|
| 40 | virtual void          addConsumer(TOIProcessor*); | 
|---|
| 41 |  | 
|---|
| 42 | // Methodes ignorees car on reimplemente les methodes de base | 
|---|
| 43 | virtual DataStatus    isDataAvail(int iStart, int iEnd); | 
|---|
| 44 | virtual DataStatus    isDataAvail(int i); | 
|---|
| 45 | virtual DataStatus isDataAvailNL(int i); | 
|---|
| 46 | virtual DataStatus    isDataAvailNL(int iStart, int iEnd); // abstract | 
|---|
| 47 | virtual void          waitForData(int iStart, int iEnd); | 
|---|
| 48 | virtual void          waitForData(int i); | 
|---|
| 49 | virtual void          waitForAnyData(); | 
|---|
| 50 | virtual int           nextDataAvail(int iAfter); // abstract | 
|---|
| 51 | virtual bool          hasSomeData(); // abstract | 
|---|
| 52 | virtual void          doGetData(int i, double& data, uint_8& flag); // abs | 
|---|
| 53 | virtual void          doPutData(int i, double value, uint_8 flag=0); // abs | 
|---|
| 54 |  | 
|---|
| 55 |  | 
|---|
| 56 | protected: | 
|---|
| 57 | class BufferSegment; | 
|---|
| 58 | class BufferView; | 
|---|
| 59 | class MasterView; | 
|---|
| 60 |  | 
|---|
| 61 | MasterView* master; | 
|---|
| 62 |  | 
|---|
| 63 |  | 
|---|
| 64 | class BufferSegment { | 
|---|
| 65 | public: | 
|---|
| 66 | BufferSegment(int sz); | 
|---|
| 67 | ~BufferSegment(); | 
|---|
| 68 | static const int NEW = 0; | 
|---|
| 69 | static const int WRITE = 1;     // single-thread write access | 
|---|
| 70 | static const int COMMITTED = 2; // multiple read without lock are ok | 
|---|
| 71 |  | 
|---|
| 72 | int getStatus() {return status;} | 
|---|
| 73 | void incRefCount(); | 
|---|
| 74 | void decRefCount(); | 
|---|
| 75 | int  getRefCount(); | 
|---|
| 76 |  | 
|---|
| 77 | void putData(int sn, double data, uint_8 flag); | 
|---|
| 78 | void putData(int sn, int n, double const* data, uint_8 const* flag); | 
|---|
| 79 | inline double getData(int sn); | 
|---|
| 80 | inline uint_8 getFlag(int sn); | 
|---|
| 81 | void getData(int sn, int n, double* data, uint_8* flag); | 
|---|
| 82 |  | 
|---|
| 83 | bool isPastEnd(int sn) { | 
|---|
| 84 | return sn >= sn0+bufferSize; | 
|---|
| 85 | } | 
|---|
| 86 |  | 
|---|
| 87 | private: | 
|---|
| 88 | void checkCommitted() { | 
|---|
| 89 | if (status != COMMITTED) { | 
|---|
| 90 | cerr << "TOISegment: Read on not committed buffer segment" << endl; | 
|---|
| 91 | throw(ForbiddenError("TOISegment: Read on not committed buffer segment")); | 
|---|
| 92 | } | 
|---|
| 93 | } | 
|---|
| 94 |  | 
|---|
| 95 | void checkInRange(int sn) { | 
|---|
| 96 | if (sn < sn0 || sn >= sn0+bufferSize) { | 
|---|
| 97 | cerr << "TOISegment: out of range access in buffer segment " << sn << " not in " | 
|---|
| 98 | << sn0 << " - " << sn0+bufferSize << endl; | 
|---|
| 99 | throw(RangeCheckError("TOISegment: out of range access in buffer segment")); | 
|---|
| 100 | } | 
|---|
| 101 | } | 
|---|
| 102 |  | 
|---|
| 103 |  | 
|---|
| 104 | int status;      // NEW, WRITE, COMMITTED | 
|---|
| 105 | int bufferSize; | 
|---|
| 106 | int sn0;         // Samplenum du premier echantillon | 
|---|
| 107 |  | 
|---|
| 108 | int refcount;    // Nombre de vues qui utilisent | 
|---|
| 109 | pthread_mutex_t refcount_mutex; // Pour modification refcount | 
|---|
| 110 |  | 
|---|
| 111 | double* data; | 
|---|
| 112 | uint_8* flags; | 
|---|
| 113 |  | 
|---|
| 114 | friend class BufferView; | 
|---|
| 115 | friend class MasterView; | 
|---|
| 116 | }; | 
|---|
| 117 |  | 
|---|
| 118 | // Master view, gere le lock, et l'ecriture | 
|---|
| 119 | class MasterView { | 
|---|
| 120 | public: | 
|---|
| 121 | MasterView(int bufsz=256, int maxseg=20, string nm=""); | 
|---|
| 122 | ~MasterView(); | 
|---|
| 123 |  | 
|---|
| 124 | void putData(int sn, double data, uint_8 flag); | 
|---|
| 125 | double getData(int sn); | 
|---|
| 126 | uint_8 getFlag(int sn); | 
|---|
| 127 | void   getData(int i, int n, double* data, uint_8* flg); | 
|---|
| 128 | void   putData(int i, int n, double const* val, uint_8 const* flg); | 
|---|
| 129 | BufferView* getView(); // thread-specific | 
|---|
| 130 | void putDone(); | 
|---|
| 131 |  | 
|---|
| 132 | protected: | 
|---|
| 133 |  | 
|---|
| 134 | friend class BufferView; | 
|---|
| 135 | friend class TOISegmented; | 
|---|
| 136 | string name; | 
|---|
| 137 | void signalWaitingViews(); // views are waiting on read | 
|---|
| 138 | void signalWrite();        // we are waiting on write | 
|---|
| 139 | void nextSegment(); | 
|---|
| 140 | void waitForCleaning(); | 
|---|
| 141 | BufferView* createView(); | 
|---|
| 142 | void updateView(BufferView*); // called on reader thread of the view | 
|---|
| 143 |  | 
|---|
| 144 | BufferSegment*   currentSegment; | 
|---|
| 145 |  | 
|---|
| 146 | int maxSegments; | 
|---|
| 147 | int segmentSize; | 
|---|
| 148 | int sn0;                         // First sn in first segment | 
|---|
| 149 | vector<BufferSegment*> segments; // Committed segments | 
|---|
| 150 | int nConsumers; | 
|---|
| 151 |  | 
|---|
| 152 | pthread_mutex_t  views_mutex; // lock for master buffer list access | 
|---|
| 153 | pthread_cond_t   write_wait_condv; // waiting for cleaning (on writer thread) | 
|---|
| 154 | pthread_key_t    buffer_key; // thread-specific buffer view | 
|---|
| 155 | static void BufferDestroy(void *); | 
|---|
| 156 |  | 
|---|
| 157 | pthread_mutex_t  read_wait_mutex; | 
|---|
| 158 | pthread_cond_t   read_wait_condv; | 
|---|
| 159 |  | 
|---|
| 160 | bool   waitingOnWrite; // wait on writer thread | 
|---|
| 161 | int    waitingViews; | 
|---|
| 162 |  | 
|---|
| 163 | set<BufferView*>  allViews; | 
|---|
| 164 |  | 
|---|
| 165 | void checkDeadLock(); | 
|---|
| 166 | }; | 
|---|
| 167 |  | 
|---|
| 168 |  | 
|---|
| 169 | // per-thread read-only view of a buffer set | 
|---|
| 170 | class BufferView { | 
|---|
| 171 | public: | 
|---|
| 172 | BufferView(MasterView*); | 
|---|
| 173 | ~BufferView(); | 
|---|
| 174 |  | 
|---|
| 175 | double getData(int sn); | 
|---|
| 176 | uint_8 getFlag(int sn); | 
|---|
| 177 | void   getData(int i, int n, double* data, uint_8* flg); | 
|---|
| 178 |  | 
|---|
| 179 | void wontNeedBefore(int sn); | 
|---|
| 180 |  | 
|---|
| 181 | protected: | 
|---|
| 182 | void wait(int sn);  // Passe en attente d'un nouveau segment -- lecture | 
|---|
| 183 | void sync();  // recupere les nouveaux segments, resync avec master | 
|---|
| 184 | void ensure(int sn); | 
|---|
| 185 |  | 
|---|
| 186 | bool waiting; | 
|---|
| 187 | int  waitingFor; | 
|---|
| 188 |  | 
|---|
| 189 | friend class MasterView; | 
|---|
| 190 | MasterView* master; | 
|---|
| 191 | vector<BufferSegment*> segments; // Committed | 
|---|
| 192 | int sn0; | 
|---|
| 193 | int segmentSize; | 
|---|
| 194 | int firstNeeded; | 
|---|
| 195 | }; | 
|---|
| 196 |  | 
|---|
| 197 |  | 
|---|
| 198 |  | 
|---|
| 199 | }; | 
|---|
| 200 |  | 
|---|
| 201 | /***********************************/ | 
|---|
| 202 | /* Inline methods -- BufferSegment */ | 
|---|
| 203 | /***********************************/ | 
|---|
| 204 |  | 
|---|
| 205 | double TOISegmented::BufferSegment::getData(int sn) { | 
|---|
| 206 | checkCommitted(); | 
|---|
| 207 | checkInRange(sn); | 
|---|
| 208 | return data[sn-sn0]; | 
|---|
| 209 | } | 
|---|
| 210 |  | 
|---|
| 211 | uint_8 TOISegmented::BufferSegment::getFlag(int sn) { | 
|---|
| 212 | checkCommitted(); | 
|---|
| 213 | checkInRange(sn); | 
|---|
| 214 | return flags[sn-sn0]; | 
|---|
| 215 | } | 
|---|
| 216 |  | 
|---|
| 217 | #endif | 
|---|