1 #ifndef __MLP_RUNTIME__
2 #define __MLP_RUNTIME__
13 #include "psemaphore.h"
40 #define PARENTCOARSE 5
50 #define H_MASK (NUMBINS)-1
61 // these are useful for interpreting an INTPTR to an
62 // Object at runtime to retrieve the object's type
63 // or object id (OID), 64-bit safe
64 #define OBJPTRPTR_2_OBJTYPE( opp ) ((int*)*(opp))[0]
65 #define OBJPTRPTR_2_OBJOID( opp ) ((int*)*(opp))[1]
67 // forwarding list elements is a linked
68 // structure of arrays, should help task
69 // dispatch because the first element is
70 // an embedded member of the task record,
71 // only have to do memory allocation if
72 // a lot of items are on the list
73 #define FLIST_ITEMS_PER_ELEMENT 30
74 typedef struct ForwardingListElement_t {
76 struct ForwardingListElement_t* nextElement;
77 INTPTR items[FLIST_ITEMS_PER_ELEMENT];
78 } ForwardingListElement;
82 // these fields are common to any SESE, and casting the
83 // generated SESE record to this can be used, because
84 // the common structure is always the first item in a
85 // customized SESE record
86 typedef struct SESEcommon_t {
88 // the identifier for the class of sese's that
89 // are instances of one particular static code block
90 // IMPORTANT: the class ID must be the first field of
91 // the task record so task dispatch works correctly!
93 volatile int unresolvedDependencies;
95 // a parent waits on this semaphore when stalling on
96 // this child, the child gives it at its SESE exit
97 psemaphore* parentsStallSem;
100 // NOTE: first element is embedded in the task
101 // record, so don't free it!
102 //ForwardingListElement forwardList;
103 struct Queue forwardList;
105 volatile int doneExecuting;
106 volatile int numRunningChildren;
108 struct SESEcommon_t* parent;
112 int unresolvedRentryIdx;
113 volatile int refCount;
114 int numDependentSESErecords;
115 int offsetToDepSESErecords;
116 struct MemPool_t * taskRecordMemPool;
118 struct MemoryQueue_t** memoryQueueArray;
119 struct REntry_t* rentryArray[NUMRENTRY];
120 struct REntry_t* unresolvedRentryArray[NUMRENTRY];
123 struct Hashtable_rcr ** allHashStructures;
124 int offsetToParamRecords;
125 volatile int rcrstatus;
126 volatile int retired;
129 // the lock guards the following data SESE's
130 // use to coordinate with one another
131 pthread_mutex_t lock;
132 pthread_cond_t runningChildrenCond;
135 // a thread-local var refers to the currently
137 extern __thread SESEcommon* runningSESE;
138 extern __thread int childSESE;
140 // there only needs to be one stall semaphore
141 // per thread, just give a reference to it to
142 // the task you are about to block on
143 extern __thread psemaphore runningSESEstallSem;
147 typedef struct REntry_t{
148 // fine read:0, fine write:1, parent read:2,
149 // parent write:3 coarse: 4, parent coarse:5, scc: 6
156 struct MemoryQueueItem_t *qitem;
157 struct BinItem_t* binitem;
158 struct MemoryQueue_t* queue;
165 psemaphore * parentStallSem;
172 #define RUNBIAS 1000000
179 void * ptrarray[RCRSIZE];
180 struct rcrRecord *next;
183 typedef struct SESEstall_t {
187 struct ___Object___* ___obj___;
188 struct rcrRecord rcrRecords[1];
193 typedef struct MemoryQueueItem_t {
194 int type; // hashtable:0, vector:1, singleitem:2
195 int total; //total non-retired
196 int status; //NOTREADY, READY
197 struct MemoryQueueItem_t *next;
201 typedef struct MemoryQueue_t {
202 MemoryQueueItem * head;
203 MemoryQueueItem * tail;
204 REntry * binbuf[NUMBINS];
205 REntry * buf[NUMRENTRY];
207 #ifndef OOO_DISABLE_TASKMEMPOOL
208 MemPool * rentrypool;
212 typedef struct BinItem_t {
214 int status; //NOTREADY, READY
215 int type; //READBIN:0, WRITEBIN:1
216 struct BinItem_t * next;
219 typedef struct Hashtable_t {
220 MemoryQueueItem item;
221 struct BinElement_t* array[NUMBINS];
222 struct Queue* unresolvedQueue;
225 typedef struct BinElement_t {
230 typedef struct WriteBinItem_t {
235 typedef struct ReadBinItem_t {
237 REntry * array[NUMREAD];
241 typedef struct Vector_t {
242 MemoryQueueItem item;
243 REntry * array[NUMITEMS];
247 typedef struct SCC_t {
248 MemoryQueueItem item;
252 int ADDRENTRY(MemoryQueue* q, REntry * r);
253 void RETIRERENTRY(MemoryQueue* Q, REntry * r);
258 static inline void ADD_FORWARD_ITEM( ForwardingListElement* e,
260 //atomic_inc( &(s->refCount) );
263 // simple mechanical allocation and
264 // deallocation of SESE records
265 void* mlpAllocSESErecord( int size );
266 void mlpFreeSESErecord( SESEcommon* seseRecord );
268 MemoryQueue** mlpCreateMemoryQueueArray(int numMemoryQueue);
269 REntry* mlpCreateFineREntry(MemoryQueue *q, int type, SESEcommon* seseToIssue, void* dynID);
271 REntry* mlpCreateREntry(MemoryQueue *q, int type, SESEcommon* seseToIssue, INTPTR mask);
273 REntry* mlpCreateREntry(MemoryQueue *q, int type, SESEcommon* seseToIssue);
275 MemoryQueue* createMemoryQueue();
276 void rehashMemoryQueue(SESEcommon* seseParent);
277 void TAILWRITECASE(Hashtable *T, REntry *r, BinItem *val, BinItem *bintail, int key, int inc);
278 void RETIRESCC(MemoryQueue *Q, REntry *r);
279 void RETIREHASHTABLE(MemoryQueue *q, REntry *r);
280 void RETIREBIN(Hashtable *T, REntry *r, BinItem *b);
281 void RETIREVECTOR(MemoryQueue *Q, REntry *r);
282 void RESOLVECHAIN(MemoryQueue *Q);
283 void RESOLVEHASHTABLE(MemoryQueue *Q, Hashtable *T);
284 void RESOLVEVECTOR(MemoryQueue *q, Vector *V);
285 void RESOLVESCC(MemoryQueue *q, SCC *S);
286 void resolveDependencies(REntry* rentry);
289 int RESOLVEBUF(MemoryQueue * q, SESEcommon *seseCommon);
290 void resolvePointer(REntry* rentry);
293 static inline void ADD_REFERENCE_TO( SESEcommon* seseRec ) {
294 atomic_inc( &(seseRec->refCount) );
297 static inline int RELEASE_REFERENCE_TO( SESEcommon* seseRec ) {
298 if( atomic_sub_and_test( 1, &(seseRec->refCount) ) ) {
299 poolfreeinto( seseRec->parent->taskRecordMemPool, seseRec );
305 static inline int RELEASE_REFERENCES_TO( SESEcommon* seseRec, int refCount) {
306 if( atomic_sub_and_test( refCount, &(seseRec->refCount) ) ) {
307 poolfreeinto( seseRec->parent->taskRecordMemPool, seseRec );
313 #define CHECK_RECORD(x) ;
316 ////////////////////////////////////////////////
318 // Some available debug versions of the above
319 // pool allocation-related helpers. The lower
320 // 'x' appended to names means they are not hooked
321 // up, but check em in so we can switch names and
322 // use them for debugging
324 ////////////////////////////////////////////////
325 #define ADD_REFERENCE_TOx(x) atomic_inc( &((x)->refCount) ); printf("0x%x ADD 0x%x on %d\n",(INTPTR)runningSESE,(INTPTR)(x),__LINE__);
327 #define RELEASE_REFERENCE_TOx(x) if (atomic_sub_and_test(1, &((x)->refCount))) {poolfreeinto(x->parent->taskRecordMemPool, x);printf("0x%x REL 0x%x on %d\n",(INTPTR)runningSESE,(INTPTR)(x),__LINE__);}
329 #define CHECK_RECORDx(x) { \
330 if( ((SESEcommon*)(x))->refCount < 0 || \
331 ((SESEcommon*)(x))->refCount < 0 ) { \
332 printf( "Acquired 0x%x from poolalloc, with refCount=%d\n", (INTPTR)(x), ((SESEcommon*)(x))->refCount ); } \
337 // this is for using a memPool to allocate task records,
338 // pass this into the poolcreate so it will run your
339 // custom init code ONLY for fresh records, reused records
340 // can be returned as is
341 void freshTaskRecordInitializer( void* seseRecord );
344 #endif /* __MLP_RUNTIME__ */