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