edee6a00dfcb545e41a7b312db4080dd832a50c6
[charm.git] / src / conv-core / conv-conds.c
1 #include <stdio.h>
2
3 #include "converse.h"
4
5 static void InsertInHeap(double Time, CcdVoidFn fnp, void *arg);
6 static void RemoveFromHeap(int index);
7 static void SwapHeapEntries(int index1, int index2);
8
9 typedef struct fn_arg {
10   CcdVoidFn fn;
11   void *arg;
12   struct fn_arg *next;
13 } FN_ARG;
14
15 /* We have a fixed number of these elements .. */
16 typedef struct {
17   FN_ARG *fn_arg_list;
18 } CONDS;
19
20 typedef struct {
21     double timeVal;     /* the actual time value we sort on           */
22     CcdVoidFn fn; 
23     void *arg; 
24 } HeapIndexType;
25
26 #define MAXTIMERHEAPENTRIES       512
27 #define MAXCONDCHKARRAYELTS       512
28
29 /** Note : The heap is only stored in elements 
30     timerHeap[0] to timerHeap[numHeapEntries] */
31
32 CpvStaticDeclare(HeapIndexType*, timerHeap); 
33 CpvStaticDeclare(CONDS*, CondArr);   
34 CpvStaticDeclare(FN_ARG*, PeriodicCalls);
35 CpvStaticDeclare(int, numHeapEntries);
36
37 CpvDeclare(int, CcdNumChecks);
38
39 extern double CmiWallTimer(void);
40
41 void CcdModuleInit(void)
42 {
43    int i;
44
45    CpvInitialize(HeapIndexType*, timerHeap);
46    CpvInitialize(CONDS*, CondArr);
47    CpvInitialize(FN_ARG*, PeriodicCalls);
48    CpvInitialize(int, numHeapEntries);
49    CpvInitialize(int, CcdNumChecks);
50
51    CpvAccess(timerHeap) = 
52      (HeapIndexType*) malloc(sizeof(HeapIndexType)*(MAXTIMERHEAPENTRIES + 1));
53    CpvAccess(CondArr) = (CONDS*) malloc(sizeof(CONDS)*(MAXCONDCHKARRAYELTS));
54    CpvAccess(CcdNumChecks) = 0;
55    CpvAccess(numHeapEntries) = 0;
56    CpvAccess(PeriodicCalls) = (FN_ARG *) 0;
57    for(i=0; i<MAXCONDCHKARRAYELTS; i++)
58      CpvAccess(CondArr)[i].fn_arg_list = 0;
59 }
60
61
62
63 /*****************************************************************************
64   Add a function that will be called when a particular condition is raised
65  *****************************************************************************/
66 void CcdCallOnCondition(int condnum,CcdVoidFn fnp,void *arg)
67 {
68   FN_ARG *newEntry = (FN_ARG *) malloc(sizeof(FN_ARG)); 
69   newEntry->fn = fnp;  
70   newEntry->arg  = arg;
71   newEntry->next = CpvAccess(CondArr)[condnum].fn_arg_list;
72   CpvAccess(CondArr)[condnum].fn_arg_list =  newEntry;
73
74
75 /*****************************************************************************
76   Add a function that will be called during next call to PeriodicChecks
77  *****************************************************************************/
78 void CcdPeriodicallyCall(CcdVoidFn fnp, void *arg)
79 {
80   FN_ARG *temp = (FN_ARG *) malloc(sizeof(FN_ARG)); 
81   temp->fn = fnp;
82   temp->arg = arg;
83   temp->next = CpvAccess(PeriodicCalls);
84   CpvAccess(PeriodicCalls) = temp;
85   CpvAccess(CcdNumChecks)++;
86 }
87
88 /*****************************************************************************
89   Call all the functions that are waiting for this condition to be raised
90  *****************************************************************************/
91 void CcdRaiseCondition(int condNum)
92 {
93   FN_ARG *temp, *del;
94   temp = CpvAccess(CondArr)[condNum].fn_arg_list;
95   CpvAccess(CondArr)[condNum].fn_arg_list = 0;
96   while(temp) {
97     (*(temp->fn))(temp->arg);
98     del = temp;
99     temp = temp->next;
100     free(del);
101   }
102 }
103
104 /*****************************************************************************
105   Call the function with the provided argument after a minimum delay of deltaT
106  *****************************************************************************/
107 void CcdCallFnAfter(CcdVoidFn fnp, void *arg, unsigned int deltaT)
108 {
109   double tPrime, currT;
110   currT  = CmiWallTimer();                /* get current time */
111   tPrime = currT + (double)deltaT/1000.0; /* add delta to determine what time
112                                             to actually execute fn */
113   InsertInHeap(tPrime, fnp, arg); /* insert into tmr hp */
114
115
116 /*****************************************************************************
117   If any of the CallFnAfter functions can now be called, call them 
118   ****************************************************************************/
119 void CcdCallBacks()
120 {
121   double currTime;
122   int index;
123   int i,j;
124   FN_ARG *temp, *next;
125   
126   if ( CpvAccess(numHeapEntries) > 0 ) {
127     currTime = CmiWallTimer();
128     while ((CpvAccess(numHeapEntries) > 0) && 
129            CpvAccess(timerHeap)[1].timeVal < currTime)
130     {
131       (*(CpvAccess(timerHeap)[1].fn))(CpvAccess(timerHeap)[1].arg);
132       RemoveFromHeap(1);
133     }
134   }
135
136   temp = CpvAccess(PeriodicCalls); 
137   CpvAccess(PeriodicCalls) = 0 ;
138   for(; temp; temp = next) {
139     CpvAccess(CcdNumChecks)--;
140     (*(temp->fn))(temp->arg);
141     next = temp->next ;
142     free(temp) ;
143   }
144
145
146 /*****************************************************************************
147   These are internal functions
148   ****************************************************************************/
149
150 static void InsertInHeap(double theTime, CcdVoidFn fnp, void *arg)
151 {
152   int child, parent;
153   
154   if(CpvAccess(numHeapEntries) > MAXTIMERHEAPENTRIES) 
155     {
156       CmiPrintf("Heap overflow (InsertInHeap), exiting...\n");
157       exit(1);
158     }
159   else 
160     {
161       CpvAccess(CcdNumChecks)++;
162       CpvAccess(numHeapEntries)++;
163       CpvAccess(timerHeap)[CpvAccess(numHeapEntries)].timeVal    = theTime;
164       CpvAccess(timerHeap)[CpvAccess(numHeapEntries)].fn = fnp;
165       CpvAccess(timerHeap)[CpvAccess(numHeapEntries)].arg = arg;
166       child  = CpvAccess(numHeapEntries);    
167       parent = child / 2;
168       while((parent>0) && (CpvAccess(timerHeap)[child].timeVal<CpvAccess(timerHeap)[parent].timeVal))
169         {
170           SwapHeapEntries(child,parent);
171           child  = parent;
172           parent = parent / 2;
173         }
174     }
175
176
177 static void RemoveFromHeap(int index)
178 {
179   int parent,child;
180   
181   parent = index;
182   if(!CpvAccess(numHeapEntries) || (index != 1)) 
183     {
184       CmiPrintf("Internal inconsistency (RemoveFromHeap), exiting ...\n");
185       exit(1);
186     } 
187   else 
188     {
189       CpvAccess(timerHeap)[index].arg = 0;
190       SwapHeapEntries(index,CpvAccess(numHeapEntries)); /* put deleted value at end 
191                                                 of heap */
192       CpvAccess(numHeapEntries)--;
193       CpvAccess(CcdNumChecks)--;
194       if(CpvAccess(numHeapEntries)) 
195         {             /* if any left, then bubble up values */
196           child = 2 * parent;
197           while(child <= CpvAccess(numHeapEntries)) 
198             {
199               if(((child + 1) <= CpvAccess(numHeapEntries))  &&
200                  (CpvAccess(timerHeap)[child].timeVal > CpvAccess(timerHeap)[child + 1].timeVal))
201                 child++;              /* use the smaller of the two */
202               if(CpvAccess(timerHeap)[parent].timeVal <= CpvAccess(timerHeap)[child].timeVal) 
203                 break;
204               SwapHeapEntries(parent,child);
205               parent  = child;      /* go down the tree one more step */
206               child  = 2 * child;
207             }
208         }
209     } 
210
211
212 static void SwapHeapEntries(int index1, int index2)
213 {
214   HeapIndexType temp;
215   
216   temp              = CpvAccess(timerHeap)[index1];
217   CpvAccess(timerHeap)[index1] = CpvAccess(timerHeap)[index2];
218   CpvAccess(timerHeap)[index2] = temp;
219
220
221
222
223
224