1 #include "hashStructure.h"
2 //#include "WaitingQueue.h"
4 #include "rcr_runtime.h"
8 __thread HashStructure ** allHashStructures;
9 #define ISWRITEBIN(x) (x&BINMASK)
10 #define ISREADBIN(x) (!(x&BINMASK))
11 //#define POPCOUNT(x) __builtin_popcountll(x)
12 //__builtin_popcountll
16 inline enqueuerecord(struct rcrRecord *rcrrec, int tmpkey, BinItem_rcr *item) {
17 if (likely(rcrrec!=NULL)) {
18 struct rcrRecord * tmprec;
19 if(likely(rcrrec->index<RCRSIZE)) {
20 int index=rcrrec->index++;
21 rcrrec->ptrarray[index]=(void *) item;
22 rcrrec->array[index]=tmpkey;
23 } else if(likely((tmprec=rcrrec->next)!=NULL)&&likely(tmprec->index<RCRSIZE)) {
24 int index=tmprec->index++;
25 tmprec->ptrarray[index]=(void *) item;
26 tmprec->array[index]=tmpkey;
28 struct rcrRecord *trec=RUNMALLOC(sizeof(struct rcrRecord));
29 trec->ptrarray[0]=(void *) item;
30 trec->array[0]=tmpkey;
38 HashStructure ** rcr_createMasterHashTableArray(int maxSize){
39 return (HashStructure **) malloc(sizeof(HashStructure *) * maxSize);
42 HashStructure* rcr_createHashtable(){
44 HashStructure* newTable=(HashStructure*)RUNMALLOC(sizeof(HashStructure));
45 for(i=0;i<RNUMBINS;i++){
46 newTable->array[i].head=NULL;
47 newTable->array[i].tail=NULL;
49 //newTable->memPoolRead = poolcreate( sizeof(ReadBinItem_rcr), NULL );
50 //newTable->memPoolWrite = poolcreate( sizeof(WriteBinItem_rcr), NULL );
54 WriteBinItem_rcr* rcr_createWriteBinItem( HashStructure* htable ){
55 //WriteBinItem_rcr* binitem=(WriteBinItem_rcr*)poolalloc( htable->memPoolWrite );
56 WriteBinItem_rcr* binitem=(WriteBinItem_rcr*)RUNMALLOC(sizeof(WriteBinItem_rcr));
57 binitem->item.type=WRITEBIN;
58 binitem->item.next=NULL;
62 ReadBinItem_rcr* rcr_createReadBinItem( HashStructure* htable ){
63 //ReadBinItem_rcr* binitem=(ReadBinItem_rcr*)poolalloc( htable->memPoolRead );
64 ReadBinItem_rcr* binitem=(ReadBinItem_rcr*)RUNMALLOC(sizeof(ReadBinItem_rcr));
66 binitem->item.type=READBIN;
67 binitem->item.next=NULL;
71 inline int rcr_generateKey(void * ptr){
72 return (((struct ___Object___ *) ptr)->oid)&RH_MASK;
75 inline int rcr_BWRITEBINCASE(HashStructure *T, int key, SESEcommon *task, struct rcrRecord *rcrrec, int index, int mode) {
76 //chain of bins exists => tail is valid
77 //if there is something in front of us, then we are not ready
79 BinElement_rcr* be= &(T->array[key]); //do not grab head from here since it's locked (i.e. = 0x1)
81 //LOCK is still needed as different threads will remove items...
83 val=(BinItem_rcr *)0x1;
84 val=(BinItem_rcr *)LOCKXCHG((unsigned INTPTR*)&(be->head), (unsigned INTPTR)val);
85 } while(val==(BinItem_rcr*)0x1);
88 if (((INTPTR)task)&PARENTBIN) {
93 BinItem_rcr * b=(BinItem_rcr*)rcr_createWriteBinItem( T );
94 WriteBinItem_rcr * td = (WriteBinItem_rcr*)b;
98 //common to both types
100 td->bitindexrd=td->bitindexwr=ONEVAL<<index;
102 BARRIER();//do tail before head
105 enqueuerecord(rcrrec, key, b);
108 BARRIER();//read head before tail
109 BinItem_rcr *bintail=be->tail;
110 bitvt rdmask=0,wrmask=0;
113 if (ISWRITEBIN(bintail->type)) {
114 WriteBinItem_rcr * td = (WriteBinItem_rcr *)bintail;
115 //last one is to check for SESE blocks in a while loop.
116 if(unlikely(td->task == task)) {
118 bitvt bit=ONEVAL<<index;
119 if (!(bit & td->bitindexwr)) {
124 while(bintail->status!=READY) {
129 return bintail->status;
137 TraverserData * td = &((ReadBinItem_rcr *)bintail)->array[((ReadBinItem_rcr *)bintail)->index - 1];
138 if(unlikely(td->task == task)) {
139 //if it matches, then we remove it and the code below will upgrade it to a write.
140 ((ReadBinItem_rcr *)bintail)->index--;
141 atomic_dec(&bintail->total);
143 if (bintail->status!=READY)
149 WriteBinItem_rcr *b=rcr_createWriteBinItem( T );
153 bitvt bit=ONEVAL<<index;
155 //count already includes this
158 b->bitindexwr=bit|wrmask;
159 b->bitindexrd=bit|rdmask;
160 b->item.status=status;
161 bintail->next=(BinItem_rcr*)b;
162 be->tail=(BinItem_rcr*)b;
163 MBARRIER(); //need to make sure that the read below doesn't pass the write above
164 if (bintail->status==READY&&bintail->total==0) {
165 //we may have to set write as ready
167 if (val==((BinItem_rcr *)b)) {
168 if (((INTPTR)task)&PARENTBIN) {
173 b->item.status=READY;
178 enqueuerecord(rcrrec, key, (BinItem_rcr *) b);
181 } else if (val->total!=0) {
184 //TODO: WHEN WE DO POOLALLOC, WE LEAK NODES HERE AND ACCESS THEM W/O LOCKING BIN...
192 while(b->item.status==NOTREADY) {
196 enqueuerecord(rcrrec, key, (BinItem_rcr *) b);
200 enqueuerecord(rcrrec, key, (BinItem_rcr *) b);
205 inline int rcr_BREADBINCASE(HashStructure *T, int key, SESEcommon *task, struct rcrRecord *rcrrec, int index, int mode) {
207 BinElement_rcr * be = &(T->array[key]);
209 //LOCK is still needed as different threads will remove items...
211 val=(BinItem_rcr *)0x1;
212 val=(BinItem_rcr *)LOCKXCHG((unsigned INTPTR*)&(be->head), (unsigned INTPTR)val);
213 } while(val==(BinItem_rcr*)0x1);
216 if (((INTPTR)task)&PARENTBIN) {
221 BinItem_rcr * b=(BinItem_rcr*)rcr_createReadBinItem( T );
222 ReadBinItem_rcr* readbin=(ReadBinItem_rcr*)b;
223 TraverserData * td = &(readbin->array[readbin->index++]);
227 //common to both types
229 td->bitindex=ONEVAL<<index;
234 enqueuerecord(rcrrec, key, b);
239 BinItem_rcr * bintail=be->tail;
241 //check if already added item or not.
242 if (ISWRITEBIN(bintail->type)) {
243 WriteBinItem_rcr * td = (WriteBinItem_rcr *)bintail;
244 if(unlikely(td->task==task)) {
246 bitvt bit=ONEVAL<<index;
247 int status=bintail->status;
248 if (!(td->bitindexrd & bit)) {
255 while(bintail->status!=READY) {
263 rcr_TAILWRITECASE(T, val, bintail, key, task, rcrrec, index);
265 struct BinItem_rcr * bt=be->tail;
266 while(bt->status!=READY) {
274 TraverserData * td = &((ReadBinItem_rcr *)bintail)->array[((ReadBinItem_rcr *)bintail)->index - 1];
275 if (unlikely(td->task==task)) {
277 bitvt bit=ONEVAL<<index;
278 int status=bintail->status;
279 if (!(td->bitindex & bit)) {
285 while(bintail->status!=READY) {
292 if ((((INTPTR)task)&PARENTBIN)&&(bintail->status==READY)) {
297 int stat=rcr_TAILREADCASE(T, val, bintail, key, task, rcrrec, index);
299 struct BinItem_rcr * bt=be->tail;
300 while(bt->status!=READY) {
311 int rcr_WRITEBINCASE(HashStructure *T, int key, SESEcommon *task, struct rcrRecord *rcrrec, int index) {
312 return rcr_BWRITEBINCASE(T, key, task, rcrrec, index, 0);
314 int rcr_READBINCASE(HashStructure *T, int key, SESEcommon * task, struct rcrRecord *rcrrec, int index) {
315 return rcr_BREADBINCASE(T, key, task, rcrrec, index, 0);
318 int rcr_WTWRITEBINCASE(HashStructure *T, int key, SESEcommon *task, struct rcrRecord *rcrrec, int index) {
319 return rcr_BWRITEBINCASE(T, key, task, rcrrec, index, 1);
322 int rcr_WTREADBINCASE(HashStructure *T, int key, SESEcommon * task, struct rcrRecord *rcrrec, int index) {
323 return rcr_BREADBINCASE(T, key, task, rcrrec, index, 1);
326 int rcr_TAILREADCASE(HashStructure *T, BinItem_rcr *val, BinItem_rcr *bintail, int key, SESEcommon * task, struct rcrRecord * rcrrec, int index) {
327 ReadBinItem_rcr * readbintail=(ReadBinItem_rcr*)T->array[key].tail;
330 if (readbintail->item.status==READY) {
338 if (readbintail->index==RNUMREAD) { // create new read group
339 ReadBinItem_rcr* rb=rcr_createReadBinItem( T );
340 td = &rb->array[rb->index++];
343 rb->item.status=status;
344 T->array[key].tail->next=(BinItem_rcr*)rb;
345 T->array[key].tail=(BinItem_rcr*)rb;
346 enqueuerecord(rcrrec, key, (BinItem_rcr *) rb);
347 } else { // group into old tail
348 td = &readbintail->array[readbintail->index++];
349 atomic_inc(&readbintail->item.total);
350 enqueuerecord(rcrrec, key, (BinItem_rcr *) readbintail);
354 td->bitindex=ONEVAL<<index;
356 T->array[key].head=val;//released lock
360 void rcr_TAILWRITECASE(HashStructure *T, BinItem_rcr *val, BinItem_rcr *bintail, int key, SESEcommon * task, struct rcrRecord *rcrrec, int index) {
361 ReadBinItem_rcr* rb=rcr_createReadBinItem( T );
362 TraverserData * td = &(rb->array[rb->index++]);
364 rb->item.status=NOTREADY;
367 td->bitindex=ONEVAL<<index;
368 enqueuerecord(rcrrec, key, (BinItem_rcr *) rb);
370 T->array[key].tail->next=(BinItem_rcr*)rb;
371 T->array[key].tail=(BinItem_rcr*)rb;
372 T->array[key].head=val;//released lock
375 void rcr_RETIREHASHTABLE(HashStructure *T, SESEcommon *task, int key, BinItem_rcr *b) {
376 atomic_dec(&b->total);
378 //Need to clear ourself out of the read bin so that we aren't resolved after being freed
379 if(ISREADBIN(b->type)) {
380 //Have to clear our entry out of bin if we retired early
382 if (b->status==NOTREADY) {
383 ReadBinItem_rcr* rptr=(ReadBinItem_rcr*)b;
384 BinElement_rcr * be = &(T->array[key]);
386 // CHECK FIRST IF next is nonnull to guarantee that b.total cannot change
387 BinItem_rcr * val=(BinItem_rcr *)0x1;
389 val=(BinItem_rcr*)LOCKXCHG((unsigned INTPTR*)&(be->head), (unsigned INTPTR)val);
390 } while(val==(BinItem_rcr*)0x1);
392 for (i=0;i<rptr->index;i++) {
393 TraverserData * td=&rptr->array[i];
394 if (task==td->task) {
395 //remove item from bin...
402 if (b->next==NULL || b->total>0) {
408 //We either have a write bin or we are at the end of a read bin
409 BinElement_rcr * be = &(T->array[key]);
411 // CHECK FIRST IF next is nonnull to guarantee that b.total cannot change
412 BinItem_rcr * val=(BinItem_rcr *)0x1;
414 val=(BinItem_rcr*)LOCKXCHG((unsigned INTPTR*)&(be->head), (unsigned INTPTR)val);
415 } while(val==(BinItem_rcr*)0x1);
417 // at this point have locked bin
418 BinItem_rcr *ptr=val;
424 if (ISREADBIN(ptr->type)) {
425 if (ptr->status==NOTREADY) {
426 ReadBinItem_rcr* rptr=(ReadBinItem_rcr*)ptr;
427 for (i=0;i<rptr->index;i++) {
428 TraverserData * td=&rptr->array[i];
429 SESEcommon *record=td->task;
430 if (((INTPTR)rptr->array[i].task)&PARENTBIN) {
431 //parents go immediately
432 atomic_dec(&rptr->item.total);
433 record=(SESEcommon *)(((INTPTR)record)&~1ULL);
436 RESOLVE(record, td->bitindex);
440 if (ptr->next==NULL) {
445 } else if (ptr==val) {
448 // THE 3 POOLFREE's IN THIS FUNCTION ARE TOO EARLY:
449 // OTHER FUNCTIONS IN THIS COMPILATION UNIT LOCK THE BIN ELEMENT
450 // BUT MAY TOUCH THE STATUS FIELDS OF BIN ITEMS AFTER RELEASING
451 // THE LOCK, WE HAVE TO MAKE SOME CAREFUL CHANGES TO ALLOW THE
452 // POOLFREE's TO WORK!
454 //poolfreeinto( T->memPoolRead, ptr );
456 } else if (ptr->total==0) {
457 //skip past retired item
460 //poolfreeinto( T->memPoolWrite, ptr );
466 if(ptr->status==NOTREADY) {
467 WriteBinItem_rcr* wptr=(WriteBinItem_rcr*)ptr;
468 RESOLVE((SESEcommon *)(((INTPTR)wptr->task)&~1ULL), wptr->bitindexwr);
470 if(((INTPTR)wptr->task)&PARENTBIN) {
472 //poolfreeinto( T->memPoolWrite, ptr );
480 be->head=val; // release lock
484 void RESOLVE(SESEcommon *record, bitvt mask) {
486 struct rcrRecord * array=(struct rcrRecord *)(((char *)record)+record->offsetToParamRecords);
488 int shift=__builtin_ctzll(mask)+1;
490 if (atomic_sub_and_test(1,&array[index].count)) {
491 if(unlikely(record->classID<0)) {
492 //parent stall...clear it
493 psem_give_tag(record->parentsStallSem, ((SESEstall *)record)->tag);
494 //mark the record unused
497 #ifndef OOO_DISABLE_TASKMEMPOOL
498 RELEASE_REFERENCE_TO(record);
501 int flag=LOCKXCHG32(&array[index].flag,0);
503 if(atomic_sub_and_test(1, &(record->unresolvedDependencies)))
504 workScheduleSubmit((void *)record);