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 reenqueuerecord(struct rcrRecord *rcrrec, int tmpkey, BinItem_rcr *olditem, BinItem_rcr *newitem) {
17 if (likely(rcrrec!=NULL)) {
18 struct rcrRecord * tmprec=rcrrec;;
21 for(i=tmprec->index-1;i>=0;i--) {
22 if (tmprec->ptrarray[i]==olditem&&tmprec->array[i]==tmpkey) {
23 tmprec->ptrarray[i]=newitem;
32 inline enqueuerecord(struct rcrRecord *rcrrec, int tmpkey, BinItem_rcr *item) {
33 if (likely(rcrrec!=NULL)) {
34 struct rcrRecord * tmprec;
35 if(likely(rcrrec->index<RCRSIZE)) {
36 int index=rcrrec->index++;
37 rcrrec->ptrarray[index]=(void *) item;
38 rcrrec->array[index]=tmpkey;
39 } else if(likely((tmprec=rcrrec->next)!=NULL)&&likely(tmprec->index<RCRSIZE)) {
40 int index=tmprec->index++;
41 tmprec->ptrarray[index]=(void *) item;
42 tmprec->array[index]=tmpkey;
44 struct rcrRecord *trec=RUNMALLOC(sizeof(struct rcrRecord));
45 trec->ptrarray[0]=(void *) item;
46 trec->array[0]=tmpkey;
54 HashStructure ** rcr_createMasterHashTableArray(int maxSize){
55 return (HashStructure **) malloc(sizeof(HashStructure *) * maxSize);
58 HashStructure* rcr_createHashtable(){
60 HashStructure* newTable=(HashStructure*)RUNMALLOC(sizeof(HashStructure));
61 for(i=0;i<RNUMBINS;i++){
62 newTable->array[i].head=NULL;
63 newTable->array[i].tail=NULL;
65 //newTable->memPoolRead = poolcreate( sizeof(ReadBinItem_rcr), NULL );
66 //newTable->memPoolWrite = poolcreate( sizeof(WriteBinItem_rcr), NULL );
71 __thread WriteBinItem_rcr* bank=NULL;
72 __thread offset=WBMAX;
75 WriteBinItem_rcr* rcr_createWriteBinItem( HashStructure* htable ){
76 //WriteBinItem_rcr* binitem=(WriteBinItem_rcr*)poolalloc( htable->memPoolWrite );
78 bank=(WriteBinItem_rcr*)RUNMALLOC(sizeof(WriteBinItem_rcr)*WBMAX);
82 WriteBinItem_rcr* binitem=&bank[offset++];
83 //(WriteBinItem_rcr*)RUNMALLOC(sizeof(WriteBinItem_rcr));
84 binitem->item.type=WRITEBIN;
85 binitem->item.next=NULL;
90 ReadBinItem_rcr* rcr_createReadBinItem( HashStructure* htable ){
91 //ReadBinItem_rcr* binitem=(ReadBinItem_rcr*)poolalloc( htable->memPoolRead );
92 ReadBinItem_rcr* binitem=(ReadBinItem_rcr*)RUNMALLOC(sizeof(ReadBinItem_rcr));
94 binitem->item.type=READBIN;
95 binitem->item.next=NULL;
99 inline int rcr_generateKey(void * ptr){
100 return (((struct ___Object___ *) ptr)->oid)&RH_MASK;
103 inline int rcr_BWRITEBINCASE(HashStructure *T, int key, SESEcommon *task, struct rcrRecord *rcrrec, int index, int mode) {
104 //chain of bins exists => tail is valid
105 //if there is something in front of us, then we are not ready
107 BinElement_rcr* be= &(T->array[key]); //do not grab head from here since it's locked (i.e. = 0x1)
109 //LOCK is still needed as different threads will remove items...
111 val=(BinItem_rcr *)0x1;
112 val=(BinItem_rcr *)LOCKXCHG((unsigned INTPTR*)&(be->head), (unsigned INTPTR)val);
113 } while(val==(BinItem_rcr*)0x1);
116 if (((INTPTR)task)&PARENTBIN) {
121 BinItem_rcr * b=(BinItem_rcr*)rcr_createWriteBinItem( T );
122 WriteBinItem_rcr * td = (WriteBinItem_rcr*)b;
126 //common to both types
128 td->bitindexrd=td->bitindexwr=ONEVAL<<index;
130 BARRIER();//do tail before head
133 enqueuerecord(rcrrec, key, b);
136 BARRIER();//read head before tail
137 BinItem_rcr *bintail=be->tail;
138 bitvt rdmask=0,wrmask=0;
142 if (ISWRITEBIN(bintail->type)) {
143 WriteBinItem_rcr * td = (WriteBinItem_rcr *)bintail;
144 //last one is to check for SESE blocks in a while loop.
145 if(unlikely(td->task == task)) {
147 bitvt bit=ONEVAL<<index;
148 if (!(bit & td->bitindexwr)) {
153 while(bintail->status!=READY) {
158 return bintail->status;
165 b=rcr_createWriteBinItem( T );
167 TraverserData * td = &((ReadBinItem_rcr *)bintail)->array[((ReadBinItem_rcr *)bintail)->index - 1];
168 b=rcr_createWriteBinItem( T );
169 if(unlikely(td->task == task)) {
170 //if it matches, then we remove it and the code below will upgrade it to a write.
171 ((ReadBinItem_rcr *)bintail)->index--;
172 atomic_dec(&bintail->total);
174 if (bintail->status!=READY)
178 //yank the old one out of the retire list and put us in place
179 int oldindex=__builtin_ctz(rdmask);
180 struct rcrRecord * oldrec=&rcrrec[oldindex-index];
181 reenqueuerecord(oldrec, key, bintail, (BinItem_rcr *) b);
189 bitvt bit=ONEVAL<<index;
191 //count already includes this
194 b->bitindexwr=bit|wrmask;
195 b->bitindexrd=bit|rdmask;
196 b->item.status=status&READYMASK;
197 bintail->next=(BinItem_rcr*)b;
198 be->tail=(BinItem_rcr*)b;
199 MBARRIER(); //need to make sure that the read below doesn't pass the write above
200 if (bintail->status==READY&&bintail->total==0) {
201 //we may have to set write as ready
203 if (val==((BinItem_rcr *)b)) {
204 if (((INTPTR)task)&PARENTBIN) {
209 b->item.status=READY;
214 enqueuerecord(rcrrec, key, (BinItem_rcr *) b);
217 } else if (val->total!=0) {
220 //TODO: WHEN WE DO POOLALLOC, WE LEAK NODES HERE AND ACCESS THEM W/O LOCKING BIN...
228 while(b->item.status==NOTREADY) {
232 enqueuerecord(rcrrec, key, (BinItem_rcr *) b);
236 enqueuerecord(rcrrec, key, (BinItem_rcr *) b);
241 inline int rcr_BREADBINCASE(HashStructure *T, int key, SESEcommon *task, struct rcrRecord *rcrrec, int index, int mode) {
243 BinElement_rcr * be = &(T->array[key]);
245 //LOCK is still needed as different threads will remove items...
247 val=(BinItem_rcr *)0x1;
248 val=(BinItem_rcr *)LOCKXCHG((unsigned INTPTR*)&(be->head), (unsigned INTPTR)val);
249 } while(val==(BinItem_rcr*)0x1);
252 if (((INTPTR)task)&PARENTBIN) {
257 BinItem_rcr * b=(BinItem_rcr*)rcr_createReadBinItem( T );
258 ReadBinItem_rcr* readbin=(ReadBinItem_rcr*)b;
259 TraverserData * td = &(readbin->array[readbin->index++]);
263 //common to both types
265 td->bitindex=ONEVAL<<index;
270 enqueuerecord(rcrrec, key, b);
275 BinItem_rcr * bintail=be->tail;
277 //check if already added item or not.
278 if (ISWRITEBIN(bintail->type)) {
279 WriteBinItem_rcr * td = (WriteBinItem_rcr *)bintail;
280 if(unlikely(td->task==task)) {
282 bitvt bit=ONEVAL<<index;
283 int status=bintail->status;
284 if (!(td->bitindexrd & bit)) {
291 while(bintail->status!=READY) {
299 rcr_TAILWRITECASE(T, val, bintail, key, task, rcrrec, index);
301 struct BinItem_rcr * bt=be->tail;
302 while(bt->status!=READY) {
310 TraverserData * td = &((ReadBinItem_rcr *)bintail)->array[((ReadBinItem_rcr *)bintail)->index - 1];
311 if (unlikely(td->task==task)) {
313 bitvt bit=ONEVAL<<index;
314 int status=bintail->status;
315 if (!(td->bitindex & bit)) {
321 while(bintail->status!=READY) {
328 if ((((INTPTR)task)&PARENTBIN)&&(bintail->status==READY)) {
333 int stat=rcr_TAILREADCASE(T, val, bintail, key, task, rcrrec, index);
335 struct BinItem_rcr * bt=be->tail;
336 while(bt->status!=READY) {
347 int rcr_WRITEBINCASE(HashStructure *T, int key, SESEcommon *task, struct rcrRecord *rcrrec, int index) {
348 return rcr_BWRITEBINCASE(T, key, task, rcrrec, index, 0);
350 int rcr_READBINCASE(HashStructure *T, int key, SESEcommon * task, struct rcrRecord *rcrrec, int index) {
351 return rcr_BREADBINCASE(T, key, task, rcrrec, index, 0);
354 int rcr_WTWRITEBINCASE(HashStructure *T, int key, SESEcommon *task, struct rcrRecord *rcrrec, int index) {
355 return rcr_BWRITEBINCASE(T, key, task, rcrrec, index, 1);
358 int rcr_WTREADBINCASE(HashStructure *T, int key, SESEcommon * task, struct rcrRecord *rcrrec, int index) {
359 return rcr_BREADBINCASE(T, key, task, rcrrec, index, 1);
362 int rcr_TAILREADCASE(HashStructure *T, BinItem_rcr *val, BinItem_rcr *bintail, int key, SESEcommon * task, struct rcrRecord * rcrrec, int index) {
363 ReadBinItem_rcr * readbintail=(ReadBinItem_rcr*)T->array[key].tail;
366 if (readbintail->item.status==READY) {
374 if (readbintail->index==RNUMREAD) { // create new read group
375 ReadBinItem_rcr* rb=rcr_createReadBinItem( T );
376 td = &rb->array[rb->index++];
378 td->bitindex=ONEVAL<<index;
380 rb->item.status=status;
381 T->array[key].tail->next=(BinItem_rcr*)rb;
382 T->array[key].tail=(BinItem_rcr*)rb;
383 enqueuerecord(rcrrec, key, (BinItem_rcr *) rb);
384 } else { // group into old tail
385 td = &readbintail->array[readbintail->index];
387 td->bitindex=ONEVAL<<index;
388 BARRIER();//ordering is to prevent retiring task from trashing us...
389 readbintail->index++;
390 atomic_inc(&readbintail->item.total);
391 enqueuerecord(rcrrec, key, (BinItem_rcr *) readbintail);
396 T->array[key].head=val;//released lock
400 void rcr_TAILWRITECASE(HashStructure *T, BinItem_rcr *val, BinItem_rcr *bintail, int key, SESEcommon * task, struct rcrRecord *rcrrec, int index) {
401 ReadBinItem_rcr* rb=rcr_createReadBinItem( T );
402 TraverserData * td = &(rb->array[rb->index++]);
404 rb->item.status=NOTREADY;
407 td->bitindex=ONEVAL<<index;
408 enqueuerecord(rcrrec, key, (BinItem_rcr *) rb);
410 T->array[key].tail->next=(BinItem_rcr*)rb;
411 T->array[key].tail=(BinItem_rcr*)rb;
412 T->array[key].head=val;//released lock
415 void rcr_RETIREHASHTABLE(HashStructure *T, SESEcommon *task, int key, BinItem_rcr *b) {
416 atomic_dec(&b->total);
418 //Need to clear ourself out of the read bin so that we aren't resolved after being freed
419 if(ISREADBIN(b->type)) {
420 //Have to clear our entry out of bin if we retired early
422 if (b->status==NOTREADY) {
423 ReadBinItem_rcr* rptr=(ReadBinItem_rcr*)b;
424 BinElement_rcr * be = &(T->array[key]);
426 // CHECK FIRST IF next is nonnull to guarantee that b.total cannot change
427 BinItem_rcr * val=(BinItem_rcr *)0x1;
429 val=(BinItem_rcr*)LOCKXCHG((unsigned INTPTR*)&(be->head), (unsigned INTPTR)val);
430 } while(val==(BinItem_rcr*)0x1);
431 for (i=0;i<rptr->index;i++) {
432 TraverserData * td=&rptr->array[i];
433 if (task==td->task) {
434 //remove item from bin...
441 if (b->next==NULL || b->total>0) {
442 //need to remove ourself to avoid writecombining problems
443 ReadBinItem_rcr* rptr=(ReadBinItem_rcr*)b;
444 TraverserData * td=&rptr->array[rptr->index-1];
452 //We either have a write bin or we are at the end of a read bin
453 BinElement_rcr * be = &(T->array[key]);
455 // CHECK FIRST IF next is nonnull to guarantee that b.total cannot change
456 BinItem_rcr * val=(BinItem_rcr *)0x1;
458 val=(BinItem_rcr*)LOCKXCHG((unsigned INTPTR*)&(be->head), (unsigned INTPTR)val);
459 } while(val==(BinItem_rcr*)0x1);
461 // at this point have locked bin
462 BinItem_rcr *ptr=val;
468 if (ISREADBIN(ptr->type)) {
469 if (ptr->status==NOTREADY) {
470 ReadBinItem_rcr* rptr=(ReadBinItem_rcr*)ptr;
471 for (i=0;i<rptr->index;i++) {
472 TraverserData * td=&rptr->array[i];
473 SESEcommon *record=td->task;
474 if (((INTPTR)record)&PARENTBIN) {
475 //parents go immediately
476 atomic_dec(&rptr->item.total);
477 record=(SESEcommon *)(((INTPTR)record)&~1ULL);
480 RESOLVE(record, td->bitindex);
484 if (ptr->next==NULL) {
489 } else if (ptr==val) {
492 // THE 3 POOLFREE's IN THIS FUNCTION ARE TOO EARLY:
493 // OTHER FUNCTIONS IN THIS COMPILATION UNIT LOCK THE BIN ELEMENT
494 // BUT MAY TOUCH THE STATUS FIELDS OF BIN ITEMS AFTER RELEASING
495 // THE LOCK, WE HAVE TO MAKE SOME CAREFUL CHANGES TO ALLOW THE
496 // POOLFREE's TO WORK!
498 //poolfreeinto( T->memPoolRead, ptr );
500 } else if (ptr->total==0) {
501 //skip past retired item
504 //poolfreeinto( T->memPoolWrite, ptr );
510 if(ptr->status==NOTREADY) {
511 WriteBinItem_rcr* wptr=(WriteBinItem_rcr*)ptr;
512 RESOLVE((SESEcommon *)(((INTPTR)wptr->task)&~1ULL), wptr->bitindexwr);
514 if(((INTPTR)wptr->task)&PARENTBIN) {
516 //poolfreeinto( T->memPoolWrite, ptr );
524 be->head=val; // release lock
528 void RESOLVE(SESEcommon *record, bitvt mask) {
530 struct rcrRecord * array=(struct rcrRecord *)(((char *)record)+record->offsetToParamRecords);
532 int shift=__builtin_ctzll(mask)+1;
534 if (atomic_sub_and_test(1,&array[index].count)) {
535 if(unlikely(record->classID<0)) {
536 //parent stall...clear it
537 psem_give_tag(record->parentsStallSem, ((SESEstall *)record)->tag);
538 //mark the record unused
541 #ifndef OOO_DISABLE_TASKMEMPOOL
542 RELEASE_REFERENCE_TO(record);
545 int flag=LOCKXCHG32(&array[index].flag,0);
547 if(atomic_sub_and_test(1, &(record->unresolvedDependencies)))
548 workScheduleSubmit((void *)record);