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 int offsetToParamRecords;
124 volatile int rcrstatus;
125 volatile int retired;
128 // the lock guards the following data SESE's
129 // use to coordinate with one another
130 pthread_mutex_t lock;
131 pthread_cond_t runningChildrenCond;
134 // a thread-local var refers to the currently
136 extern __thread SESEcommon* runningSESE;
137 extern __thread int childSESE;
139 // there only needs to be one stall semaphore
140 // per thread, just give a reference to it to
141 // the task you are about to block on
142 extern __thread psemaphore runningSESEstallSem;
146 typedef struct REntry_t{
147 // fine read:0, fine write:1, parent read:2,
148 // parent write:3 coarse: 4, parent coarse:5, scc: 6
151 MemoryQueueItem *qitem;
152 struct BinItem_t* binitem;
153 struct MemoryQueue_t* queue;
156 psemaphore * parentStallSem;
165 #define RUNBIAS 1000000
172 void * ptrarray[RCRSIZE];
173 struct rcrRecord *next;
176 typedef struct SESEstall_t {
180 struct ___Object___* ___obj___;
181 struct rcrRecord rcrRecords[1];
186 typedef struct MemoryQueueItem_t {
187 int type; // hashtable:0, vector:1, singleitem:2
188 int total; //total non-retired
189 int status; //NOTREADY, READY
190 struct MemoryQueueItem_t *next;
194 typedef struct MemoryQueue_t {
195 MemoryQueueItem * head;
196 MemoryQueueItem * tail;
197 REntry * binbuf[NUMBINS];
198 REntry * buf[NUMRENTRY];
200 #ifndef OOO_DISABLE_TASKMEMPOOL
201 MemPool * rentrypool;
205 typedef struct BinItem_t {
207 int status; //NOTREADY, READY
208 int type; //READBIN:0, WRITEBIN:1
209 struct BinItem_t * next;
212 typedef struct Hashtable_t {
213 MemoryQueueItem item;
214 struct BinElement_t* array[NUMBINS];
215 struct Queue* unresolvedQueue;
218 typedef struct BinElement_t {
223 typedef struct WriteBinItem_t {
228 typedef struct ReadBinItem_t {
230 REntry * array[NUMREAD];
234 typedef struct Vector_t {
235 MemoryQueueItem item;
236 REntry * array[NUMITEMS];
240 typedef struct SCC_t {
241 MemoryQueueItem item;
245 int ADDRENTRY(MemoryQueue* q, REntry * r);
246 void RETIRERENTRY(MemoryQueue* Q, REntry * r);
251 static inline void ADD_FORWARD_ITEM( ForwardingListElement* e,
253 //atomic_inc( &(s->refCount) );
256 // simple mechanical allocation and
257 // deallocation of SESE records
258 void* mlpAllocSESErecord( int size );
259 void mlpFreeSESErecord( SESEcommon* seseRecord );
261 MemoryQueue** mlpCreateMemoryQueueArray(int numMemoryQueue);
262 REntry* mlpCreateFineREntry(MemoryQueue *q, int type, SESEcommon* seseToIssue, void* dynID);
264 REntry* mlpCreateREntry(MemoryQueue *q, int type, SESEcommon* seseToIssue, INTPTR mask);
266 REntry* mlpCreateREntry(MemoryQueue *q, int type, SESEcommon* seseToIssue);
268 MemoryQueue* createMemoryQueue();
269 void rehashMemoryQueue(SESEcommon* seseParent);
271 static inline void ADD_REFERENCE_TO( SESEcommon* seseRec ) {
272 atomic_inc( &(seseRec->refCount) );
275 static inline int RELEASE_REFERENCE_TO( SESEcommon* seseRec ) {
276 if( atomic_sub_and_test( 1, &(seseRec->refCount) ) ) {
277 poolfreeinto( seseRec->parent->taskRecordMemPool, seseRec );
283 #define CHECK_RECORD(x) ;
286 ////////////////////////////////////////////////
288 // Some available debug versions of the above
289 // pool allocation-related helpers. The lower
290 // 'x' appended to names means they are not hooked
291 // up, but check em in so we can switch names and
292 // use them for debugging
294 ////////////////////////////////////////////////
295 #define ADD_REFERENCE_TOx(x) atomic_inc( &((x)->refCount) ); printf("0x%x ADD 0x%x on %d\n",(INTPTR)runningSESE,(INTPTR)(x),__LINE__);
297 #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__);}
299 #define CHECK_RECORDx(x) { \
300 if( ((SESEcommon*)(x))->refCount != 0 ) { \
301 printf( "Acquired 0x%x from poolalloc, with refCount=%d\n", (INTPTR)(x), ((SESEcommon*)(x))->refCount ); } \
302 if( ((SESEcommon*)(x))->fresh != 1 ) { \
303 printf("0x%x reclaimed 0x%x on %d\n",(INTPTR)runningSESE,(INTPTR)(x),__LINE__); } \
304 ((SESEcommon*)(x))->fresh = 0; \
309 // this is for using a memPool to allocate task records,
310 // pass this into the poolcreate so it will run your
311 // custom init code ONLY for fresh records, reused records
312 // can be returned as is
313 void freshTaskRecordInitializer( void* seseRecord );
316 #endif /* __MLP_RUNTIME__ */