eb2f5f39be3757e3b4897b8dfa53e1a8d9abde07
[IRC.git] / Robust / src / Runtime / DSTM / interface / threadnotify.c
1 #include "threadnotify.h"
2
3 notifyhashtable_t nlookup; //Global hash table
4
5 /* This function creates a new node in the linked list of threads waiting
6  * for an update notification from a particular object.
7  * This takes in the head of the linked list and inserts the new node to it */
8 void insNode(threadlist_t *head, unsigned int threadid, unsigned int mid) {
9         threadlist_t *ptr;
10         if(head == NULL) {
11                 if((head = calloc(1, sizeof(threadlist_t))) == NULL) {
12                         printf("Calloc Error %s, %d,\n", __FILE__, __LINE__);
13                         return;
14                 }
15                 head->threadid = threadid;
16                 head->mid = mid;
17                 head->next = NULL;
18         } else {
19                 if((ptr = calloc(1, sizeof(threadlist_t))) == NULL) {
20                         printf("Calloc Error %s, %d,\n", __FILE__, __LINE__);
21                         return;
22                 }
23                 ptr->threadid = threadid;
24                 ptr->mid = mid;
25                 ptr->next = head;
26                 head = ptr;
27         }
28 }
29
30 /* This function displays the linked list of threads waiting on update notification
31  * from an object */
32 void display(threadlist_t *head) {
33         threadlist_t *ptr;
34         if(head == NULL) {
35                 printf("No thread is waiting\n");
36                 return;
37         } else {
38                 while(head != NULL) {
39                         ptr = head;
40                         printf("The threadid waiting is = %d\n", ptr->threadid);
41                         printf("The mid on which thread present = %d\n", ptr->mid);
42                         head = ptr->next;
43                 }
44         }
45 }
46
47 /* This function creates a new hash table that stores a mapping between the threadid and
48  * a pointer to the thread notify data */
49 unsigned int notifyhashCreate(unsigned int size, float loadfactor) { 
50         notifylistnode_t *nodes;
51
52         // Allocate space for the hash table 
53         if((nodes = calloc(size, sizeof(notifylistnode_t))) == NULL) {
54                 printf("Calloc error %s %d\n", __FILE__, __LINE__);
55                 return 1;
56         }
57
58         nlookup.table = nodes;
59         nlookup.size = size;
60         nlookup.numelements = 0; // Initial number of elements in the hash
61         nlookup.loadfactor = loadfactor;
62         //Initialize the pthread_mutex variable         
63         pthread_mutex_init(&nlookup.locktable, NULL);
64         return 0;
65 }
66
67 // Assign to tids to bins inside hash table
68 unsigned int notifyhashFunction(unsigned int tid) {
69         return( tid % (nlookup.size));
70 }
71
72 // Insert pointer to the notify data and threadid mapping into the hash table
73 unsigned int notifyhashInsert(unsigned int tid, notifydata_t *ndata) {
74         unsigned int newsize;
75         int index;
76         notifylistnode_t *ptr, *node;
77
78         if (nlookup.numelements > (nlookup.loadfactor * nlookup.size)) {
79                 //Resize Table
80                 newsize = 2 * nlookup.size + 1;         
81                 pthread_mutex_lock(&nlookup.locktable);
82                 notifyhashResize(newsize);
83                 pthread_mutex_unlock(&nlookup.locktable);
84         }
85         ptr = nlookup.table;
86         nlookup.numelements++;
87
88         index = notifyhashFunction(tid);
89 #ifdef DEBUG
90         printf("DEBUG -> index = %d, threadid = %d\n", index, tid);
91 #endif
92         pthread_mutex_lock(&nlookup.locktable);
93         if(ptr[index].next == NULL && ptr[index].threadid == 0) {       // Insert at the first position in the hashtable
94                 ptr[index].threadid = tid;
95                 ptr[index].ndata = ndata;
96         } else {                        // Insert in the beginning of linked list
97                 if ((node = calloc(1, sizeof(notifylistnode_t))) == NULL) {
98                         printf("Calloc error %s, %d\n", __FILE__, __LINE__);
99                         pthread_mutex_unlock(&nlookup.locktable);
100                         return 1;
101                 }
102                 node->threadid = tid;
103                 node->ndata = ndata;
104                 node->next = ptr[index].next;
105                 ptr[index].next = node;
106         }
107         pthread_mutex_unlock(&nlookup.locktable);
108         return 0;
109 }
110
111 // Return pointer to thread notify data for a given threadid in the hash table
112 notifydata_t  *notifyhashSearch(unsigned int tid) {
113         int index;
114         notifylistnode_t *ptr, *node;
115
116         ptr = nlookup.table;    // Address of the beginning of hash table       
117         index = notifyhashFunction(tid);
118         node = &ptr[index];
119         pthread_mutex_lock(&nlookup.locktable);
120         while(node != NULL) {
121                 if(node->threadid == tid) {
122                         pthread_mutex_unlock(&nlookup.locktable);
123                         return node->ndata;
124                 }
125                 node = node->next;
126         }
127         pthread_mutex_unlock(&nlookup.locktable);
128         return NULL;
129 }
130
131 // Remove an entry from the hash table
132 unsigned int notifyhashRemove(unsigned int tid) {
133         int index;
134         notifylistnode_t *curr, *prev, *ptr, *node;
135
136         ptr = nlookup.table;
137         index = notifyhashFunction(tid);
138         curr = &ptr[index];
139
140         pthread_mutex_lock(&nlookup.locktable);
141         for (; curr != NULL; curr = curr->next) {
142                 if (curr->threadid == tid) {         // Find a match in the hash table
143                         nlookup.numelements--;  // Decrement the number of elements in the global hashtable
144                         if ((curr == &ptr[index]) && (curr->next == NULL))  { // Delete the first item inside the hashtable with no linked list of notifylistnode_t 
145                                 curr->threadid = 0;
146                                 curr->ndata = NULL;
147                         } else if ((curr == &ptr[index]) && (curr->next != NULL)) { //Delete the first bin item with a linked list of notifylistnode_t  connected 
148                                 curr->threadid = curr->next->threadid;
149                                 curr->ndata = curr->next->ndata;
150                                 node = curr->next;
151                                 curr->next = curr->next->next;
152                                 free(node);
153                         } else {                                                // Regular delete from linked listed    
154                                 prev->next = curr->next;
155                                 free(curr);
156                         }
157                         pthread_mutex_unlock(&nlookup.locktable);
158                         return 0;
159                 }       
160                 prev = curr; 
161         }
162         pthread_mutex_unlock(&nlookup.locktable);
163         return 1;
164 }
165
166 // Resize table
167 unsigned int notifyhashResize(unsigned int newsize) {
168         notifylistnode_t *node, *ptr, *curr, *next;     // curr and next keep track of the current and the next notifyhashlistnodes in a linked list
169         unsigned int oldsize;
170         int isfirst;    // Keeps track of the first element in the notifylistnode_t for each bin in hashtable
171         int i,index;    
172         notifylistnode_t *newnode;              
173
174         ptr = nlookup.table;
175         oldsize = nlookup.size;
176
177         if((node = calloc(newsize, sizeof(notifylistnode_t))) == NULL) {
178                 printf("Calloc error %s %d\n", __FILE__, __LINE__);
179                 return 1;
180         }
181
182         nlookup.table = node;           //Update the global hashtable upon resize()
183         nlookup.size = newsize;
184         nlookup.numelements = 0;
185
186         for(i = 0; i < oldsize; i++) {                  //Outer loop for each bin in hash table
187                 curr = &ptr[i];
188                 isfirst = 1;                    
189                 while (curr != NULL) {                  //Inner loop to go through linked lists
190                         if (curr->threadid == 0) {              //Exit inner loop if there the first element for a given bin/index is NULL
191                                 break;                  //threadid = threadcond =0 for element if not present within the hash table
192                         }
193                         next = curr->next;
194                         index = notifyhashFunction(curr->threadid);
195 #ifdef DEBUG
196                         printf("DEBUG(resize) -> index = %d, threadid = %d\n", index, curr->threadid);
197 #endif
198                         // Insert into the new table
199                         if(nlookup.table[index].next == NULL && nlookup.table[index].threadid == 0) { 
200                                 nlookup.table[index].threadid = curr->threadid;
201                                 nlookup.table[index].ndata = curr->ndata;
202                                 nlookup.numelements++;
203                         }else { 
204                                 if((newnode = calloc(1, sizeof(notifylistnode_t))) == NULL) { 
205                                         printf("Calloc error %s, %d\n", __FILE__, __LINE__);
206                                         return 1;
207                                 }       
208                                 newnode->threadid = curr->threadid;
209                                 newnode->ndata = curr->ndata;
210                                 newnode->next = nlookup.table[index].next;
211                                 nlookup.table[index].next = newnode;    
212                                 nlookup.numelements++;
213                         }       
214
215                         //free the linked list of notifylistnode_t if not the first element in the hash table
216                         if (isfirst != 1) {
217                                 free(curr);
218                         } 
219
220                         isfirst = 0;
221                         curr = next;
222                 }
223         }
224
225         free(ptr);              //Free the memory of the old hash table 
226         return 0;
227 }