1 #include "hashStructure.h"
2 #include "WaitingQueue.h"
6 //NOTE: this is only temporary (for testing) and will be removed in favor of thread local variables
7 //It's basically an array of hashStructures so we can simulate what would happen in a many-threaded version
8 HashStructure ** allHashStructures;
10 //NOTE: only temporary
11 void createMasterHashTableArray(int maxSize){
13 allHashTables = (HashTable**) malloc(sizeof(Hashtable) * maxSize);
15 for(i = 0; i < maxSize; i++) {
16 allHashTables[i] = createHashtable();
20 HashStructure* createHashtable(int sizeofWaitingQueue){
22 HashStructure* newTable=(HashStructure*)RUNMALLOC(sizeof(HashStructure));
23 for(i=0;i<NUMBINS;i++){
24 newTable->array[i].head=NULL;
25 newTable->array[i].tail=NULL;
28 newTable->waitingQueue=mallocWaitingQueue(sizeofWaitingQueue);
32 WriteBinItem_rcr* createWriteBinItem(){
33 WriteBinItem_rcr* binitem=(WriteBinItem_rcr*)RUNMALLOC(sizeof(WriteBinItem_rcr));
34 binitem->item.type=WRITEBIN;
38 ReadBinItem_rcr* createReadBinItem(){
39 ReadBinItem_rcr* binitem=(ReadBinItem_rcr*)RUNMALLOC(sizeof(ReadBinItem_rcr));
40 binitem->tail_Index=0;
41 binitem->head_Index=0;
42 binitem->item.type=READBIN;
46 int isReadBinItem(BinItem_rcr* b){
47 return b->type==READBIN;
50 int isWriteBinItem(BinItem_rcr* b){
51 return b->type==WRITEBIN;
54 inline int generateKey(void * ptr){
55 return (((struct genericObjectStruct *) ptr)->oid)&H_MASK;
58 //TODO handle logic for waiting Queues separately
59 //TODO pass in task to traverser
60 int ADDTABLEITEM(HashStructure* table, void * ptr, int type, int traverserID, SESEcommon *task, void * heaproot){
62 int key=generateKey(ptr);
64 //LOCK is still needed as different threads will remove items...
66 val=(BinItem_rcr *)0x1;
67 val=(BinItem_rcr *)LOCKXCHG((unsigned INTPTR*)&(table->array[key]->bin->head), (unsigned INTPTR)val);
68 } while(val==(BinItem_rcr*)0x1);
71 return EMPTYBINCASE(table, table->array[key], ptr, type, traverserID, task, heaproot);
74 if (type == WRITEEFFECT) {
75 return WRITEBINCASE(table, ptr, val, key, traverserID, task, heaproot);
76 } else if (type == READEFFECT) {
77 return READBINCASE(table, ptr, val, key, traverserID, task, heaproot);
82 int EMPTYBINCASE(HashStructure *T, BinElement_rcr* be, void *ptr, int type, int traverserId, SESEcommon * task, void *heaproot){
85 //TODO: NEED PARENT CHECK HERE!!!!!!!!!
88 if (type == WRITEEFFECT) {
89 b=(BinItem_rcr*)createWriteBinItem();
90 td = &((WriteBinItem_rcr*)b)->val;
91 } else if (type == READEFFECT) {
92 b=(BinItem_rcr*)createReadBinItem();
93 ReadBinItem_rcr* readbin=(ReadBinItem_rcr*)b;
94 td = &(readbin->array[readbin->tail_Index++]);
100 //common to both types
105 td->traverserID = traverserId;
106 td->heaproot = heaproot;
116 int WRITEBINCASE(HashStructure *T, void *ptr, BinItem * val, int key, int traverserID, SESEcommon *task, void *heaproot) {
117 //chain of bins exists => tail is valid
118 //if there is something in front of us, then we are not ready
120 BinElement_rcr* be= &(T->array[key]); //do not grab head from here since it's locked (i.e. = 0x1)
121 BinItem *bintail=be->tail;
123 if (bintail->type == WRITEBIN) {
124 TraverserData * td = &(((WriteBinItem_rcr *)bintail)->val);
125 //last one is to check for SESE blocks in a while loop.
126 if(unlikely(td->resumePtr == ptr) && td->traverserID == traverserID && td->task == task) {
127 return bintail->status;
129 } else if (bintail->type == READBIN) {
130 TraverserData * td = &((ReadBinItem_rcr *)bintail)->array[((ReadBinItem_rcr *)bintail)->index - 1];
131 if(unlikely(td->resumePtr == ptr) && td->traverserID == traverserID) {
132 //if it matches, then we remove it and the code below will upgrade it to a write.
133 ((ReadBinItem_rcr *)bintail)->index--;
138 WriteBinItem_rcr *b=createWriteBinItem();
139 TraverserData * td = &b->val;
142 //fillout traverserData
143 //Note: this list could be smaller in the future, for now I'm just including all the info I may need.
148 td->traverserID = traverserID;
149 td->heaproot = heaproot;
151 b->item.status=status;
152 bintail->next=(BinItem_rcr*)b;
153 be->tail=(BinItem_rcr*)b;
159 int READBINCASE(HashStructure *T, void *ptr, BinItem *val, int key, int traverserID, SESEcommon * task, void *heaproot) {
160 BinElement_rcr * be = &(T->array[key]);
161 BinItem_rcr * bintail=be->tail;
162 //check if already added item or not.
163 if (bintail->type == WRITEBIN) {
164 TraverserData * td = &(((WriteBinItem_rcr *)bintail)->val);
165 if(unlikely(td->resumePtr == ptr) && td->traverserID == traverserID) {
168 return bintail->status;
170 } else if (bintail->type == READEFFECT) {
171 TraverserData * td = &((ReadBinItem_rcr *)bintail)->array[((ReadBinItem_rcr *)bintail)->index - 1];
172 if (unlikely(td->resumePtr == ptr) && td->traverserID == traverserID) {
175 return bintail->status;
179 if (isReadBinItem(bintail)) {
180 return TAILREADCASE(T, ptr, val, bintail, key, traverserID, task, heaproot);
181 } else if (!isReadBinItem(bintail)) {
182 TAILWRITECASE(T, ptr, val, bintail, key, traverserID, task, heaproot);
188 int TAILREADCASE(HashStructure *T, void * ptr, BinItem *val, BinItem_rcr *bintail, int key, int traverserID, SESEcommon * task, void *heaproot) {
189 ReadBinItem_rcr * readbintail=(ReadBinItem_rcr*)T->array[key].tail;
192 if (readbintail->item.status==READY) {
200 if (readbintail->tail_Index==NUMREAD) { // create new read group
201 ReadBinItem_rcr* rb=createReadBinItem();
202 td = &rb->array[rb->tail_Index++];
205 rb->item.status=status;
206 T->array[key].tail->next=(BinItem_rcr*)rb;
207 T->array[key].tail=(BinItem_rcr*)rb;
208 } else { // group into old tail
209 td = &readbintail->array[readbintail->tail_Index++];
210 atomic_inc(&readbintail->item.total);
211 //printf("grouping with %d\n",readbintail->index);
214 td->binitem = bintail;
218 td->traverserID = traverserID;
219 td->heaproot = heaproot;
221 T->array[key]->head=val;//released lock
225 void TAILWRITECASE(HashStructure *T, void *ptr, BinItem *val, BinItem_rcr *bintail, int key, int traverserID, SESEcommon * task, void *heaproot) {
226 ReadBinItem_rcr* rb=createReadBinItem();
227 TraverserData * td = &(rb->array[rb->tail_Index++]);
229 rb->item.status=NOTREADY;
235 td->traverserID = traverserID;
236 td->heaproot = heaproot;
238 T->array[key].tail->next=(BinItem_rcr*)rb;
239 T->array[key].tail=(BinItem_rcr*)rb;
240 T->array[key]->head=val;//released lock
243 //TODO write deletion/removal methods
245 RETIREHASHTABLE(MemoryQueue *q, REntry *r) {
246 Hashtable *T=r->hashtable;
247 BinItem *b=r->binitem;
251 RETIREBIN(Hashtable *T, REntry *r, BinItem *b) {
252 int key=generateKey( OBJPTRPTR_2_OBJOID( r->pointer ) );
254 atomic_dec(&b->total);
256 if (isFineWrite(r) || (isFineRead(r) && b->next!=NULL && b->total==0)) {
257 // CHECK FIRST IF next is nonnull to guarantee that b.total cannot change
261 val=(BinItem*)LOCKXCHG((unsigned INTPTR*)&(T->array[key]->head), (unsigned INTPTR)val);
262 } while(val==(BinItem*)0x1);
263 // at this point have locked bin
268 if (isReadBinItem(ptr)) {
269 ReadBinItem* rptr=(ReadBinItem*)ptr;
270 if (rptr->item.status==NOTREADY) {
271 for (i=0;i<rptr->index;i++) {
272 resolveDependencies(rptr->array[i]);
273 if (isParent(rptr->array[i])) {
274 //parents go immediately
275 atomic_dec(&rptr->item.total);
276 atomic_dec(&T->item.total);
280 rptr->item.status=READY;
281 if (rptr->item.next==NULL) {
284 if (rptr->item.total!=0) {
286 } else if ((BinItem*)rptr==val) {
289 } else if(isWriteBinItem(ptr)) {
292 if(ptr->status==NOTREADY){
293 resolveDependencies(((WriteBinItem*)ptr)->val);
295 if(isParent(((WriteBinItem*)ptr)->val)){
296 atomic_dec(&T->item.total);
300 }else{ // write bin is already resolved
306 T->array[key]->head=val; // release lock
310 //Int will return success/fail. -1 indicates error (i.e. there's nothing there).
311 //0 = nothing removed, >0 something was removed
312 int REMOVETABLEITEM(HashStructure* table, void * ptr, int traverserID, SESEcommon *task, void * heaproot) {
313 int key = generateKey(ptr);
314 BinElement_rcr * bucket = table->array[key];
316 if(bucket->head == NULL) {
318 //This can occur if we try to remove something that's in the waitingQueue directly from the hashtable.
321 if(bucket->head->type == WRITEBIN) {
322 TraverserData * td = &(((WriteBinItem_rcr *) head)->val);
323 if(td->resumePtr == ptr && td->traverserID == traverserID && td->heaproot == heaproot) {
324 BinItem_rcr * temp = bucket->head;
325 bucket->head = bucket->head->next;
326 free(temp); //TODO perhaps implement a linked list of free BinElements as was done in WaitingQueue
328 //Handle items behind write item
329 if(bucket->head == NULL) {
330 bucket->tail == NULL;
334 int type = bucket->head->type;
335 switch(bucket->head->type) {
337 bucket->head->status = READY;
338 //TODO Decrement dependency count
340 case WAITINGQUEUENOTE:
341 int retval = removeFromWaitingQueue(table->waitingQueue, ((WaitingQueueNote *) bucket->head)->allocSiteID, traverserID);
343 //we set both to NULL because the note should ALWAYS be the last item in the hashStructure.
349 BinItem_rcr * temp = bucket->head;
350 while(temp != NULL && temp->type == READBIN) {
351 temp->status = READY;
353 //TODO decrement dependency count
362 if(bucket->head->type == READBIN) {
363 //TODO There's an issue here; bins are groups of items that may be enqueued by different ids.
364 //I may have to search through them to find which one to remove but then there'd be a blank spot in an
365 //otherwise clean array. It wouldn't make sense to just check the first one since reads are reorderable.
366 //Nor does it make sense to lop off the reads since that may signal the next write to be ready even before it
370 if(bucket->head->type == WAITINGQUEUENOTE) {
371 int retval = removeFromWaitingQueue(table->waitingQueue, ((WaitingQueueNote *) bucket->head)->allocSiteID, traverserID);