charmdebug: Use CkArrayIndex instead of CkArrayIndexStruct
[charm.git] / src / ck-core / debug-charm.C
1 /*****************************************************************************
2  * A few useful built-in CPD and CCS handlers.
3  *****************************************************************************/
4
5 #include "converse.h"
6
7 #include <errno.h>
8 #include <string.h>
9 #include <sys/stat.h>           // for chmod
10
11 #include "ckhashtable.h"
12 #include "conv-ccs.h"
13 #include "debug-charm.h"
14 #include "sockRoutines.h"
15 #include "charm.h"
16 #include "middle.h"
17 #include "cklists.h"
18 #include "register.h"
19 //#include "queueing.h"
20 #include <unistd.h>
21
22 #if CMK_BLUEGENE_CHARM
23 #include "blue_impl.h"
24 #endif
25
26
27 #if CMK_CHARMDEBUG && CMK_CCS_AVAILABLE && !defined(_WIN32)
28
29 #include "ck.h"
30
31 CkpvDeclare(int, skipBreakpoint); /* This is a counter of how many breakpoints we should skip */
32 CkpvDeclare(DebugEntryTable, _debugEntryTable);
33 CpdPersistentChecker persistentCheckerUselessClass;
34
35 void CpdFinishInitialization() {
36   CkpvInitialize(int, skipBreakpoint);
37   CkpvAccess(skipBreakpoint) = 0;
38   CkpvInitialize(DebugEntryTable, _debugEntryTable);
39   CkpvAccess(_debugEntryTable).resize(_entryTable.size());
40 }
41
42 extern "C" void resetAllCRC();
43 extern "C" void checkAllCRC(int report);
44
45 typedef struct DebugRecursiveEntry {
46   int previousChareID;
47   int alreadyUserCode;
48   char *memoryBackup;
49   void *obj;
50   void *msg;
51 } DebugRecursiveEntry;
52
53 CkQ<DebugRecursiveEntry> _debugData;
54
55 void *CpdGetCurrentObject() { return _debugData.peek().obj; }
56 void *CpdGetCurrentMsg() { return _debugData.peek().msg; }
57
58 extern int cpdInSystem;
59 extern "C" int CpdInUserCode() {return cpdInSystem==0 && _debugData.length()>0 && _debugData.peek().alreadyUserCode==1;}
60
61 // Function called right before an entry method
62 void CpdBeforeEp(int ep, void *obj, void *msg) {
63 #ifndef CMK_OPTIMIZE
64   if (CpvAccess(cmiArgDebugFlag)) {
65     DebugRecursiveEntry entry;
66     entry.previousChareID = setMemoryChareIDFromPtr(obj);
67     entry.alreadyUserCode = _entryTable[ep]->inCharm ? 0 : 1;
68     entry.memoryBackup = NULL;
69     entry.obj = obj;
70     if (msg != NULL) {
71       entry.msg = msg;
72       CmiReference(UsrToEnv(msg));
73     }
74     else entry.msg = NULL;
75     _debugData.push(entry);
76     setMemoryStatus(entry.alreadyUserCode);
77     //if (CkpvAccess(_debugEntryTable)[ep].isBreakpoint) printf("CpdBeforeEp breakpointed %d\n",ep);
78     memoryBackup = &_debugData.peek().memoryBackup;
79     if (!_entryTable[ep]->inCharm) {
80       CpdResetMemory();
81       CpdSystemExit();
82     }
83     CkVec<DebugPersistentCheck> &preExecutes = CkpvAccess(_debugEntryTable)[ep].preProcess;
84     for (int i=0; i<preExecutes.size(); ++i) {
85       preExecutes[i].object->cpdCheck(preExecutes[i].msg);
86     }
87   }
88 #endif
89 }
90
91 // Function called right after an entry method
92 void CpdAfterEp(int ep) {
93 #ifndef CMK_OPTIMIZE
94   if (CpvAccess(cmiArgDebugFlag)) {
95     DebugRecursiveEntry entry = _debugData.peek();
96     CkVec<DebugPersistentCheck> &postExecutes = CkpvAccess(_debugEntryTable)[ep].postProcess;
97     for (int i=0; i<postExecutes.size(); ++i) {
98       postExecutes[i].object->cpdCheck(postExecutes[i].msg);
99     }
100     memoryBackup = &entry.memoryBackup;
101     if (!_entryTable[ep]->inCharm) {
102       CpdSystemEnter();
103       CpdCheckMemory();
104     }
105     if (entry.msg != NULL) CmiFree(UsrToEnv(entry.msg));
106     setMemoryChareID(entry.previousChareID);
107     setMemoryStatus(entry.alreadyUserCode);
108     _debugData.deq();
109   }
110 #endif
111 }
112
113 /************ Array Element CPD Lists ****************/
114
115 /**
116   Count array elements going by until they reach this
117   range (lo to hi), then start passing them to dest.
118 */
119 template <class T>
120 class CkArrayElementRangeIterator : public CkLocIterator {
121 private:
122    T *dest;
123    CkArray *mgr;
124    int cur,lo,hi;
125 public:
126    CkArrayElementRangeIterator(T *dest_,int l,int h)
127         :dest(dest_),mgr(0),cur(0),lo(l),hi(h) {}
128
129   /** Called to iterate only on a specific array manager.
130       Returs the number of objects it iterate on.
131   */
132   int iterate(int start, CkArray *m) {
133     cur = start;
134     mgr = m;
135     mgr->getLocMgr()->iterate(*this);
136     cur -= start;
137     return cur;
138   }
139
140    /** Call add for every in-range array element on this processor */
141    void iterate(void)
142    { /* Walk the groupTable for arrays (FIXME: get rid of _groupIDTable) */
143      int numGroups=CkpvAccess(_groupIDTable)->size();
144      for(int i=0;i<numGroups;i++) {
145         IrrGroup *obj = CkpvAccess(_groupTable)->find((*CkpvAccess(_groupIDTable))[i]).getObj();
146         if (obj->isArrMgr())
147         { /* This is an array manager: examine its array elements */
148           mgr=(CkArray *)obj;
149           mgr->getLocMgr()->iterate(*this);
150         }
151      }
152    }
153
154    // Called by location manager's iterate function
155    virtual void addLocation (CkLocation &loc)
156    {
157      if (cur>=lo && cur<hi)
158      { /* This element is in our range-- look it up */
159        dest->add(cur,mgr->lookup(loc.getIndex()),mgr->getGroupID().idx);
160      }
161      cur++;
162    }
163
164    // Return the number of total array elements seen so far.
165    int getCount(void) {return cur;}
166 };
167
168 /**
169   Count charm++ objects going by until they reach this
170   range (lo to hi), then start passing them to dest.
171 */
172 template <class T>
173 class CkObjectRangeIterator {
174 private:
175    T *dest;
176    int cur,lo,hi;
177 public:
178    CkObjectRangeIterator(T *dest_,int l,int h)
179         :dest(dest_),cur(0),lo(l),hi(h) {}
180
181    /** Call add for every in-range array element on this processor */
182    void iterate(void)
183    { /* Walk the groupTable for arrays (FIXME: get rid of _groupIDTable) */
184      int numGroups=CkpvAccess(_groupIDTable)->size();
185      for(int i=0;i<numGroups;i++) {
186        CkGroupID groupID = (*CkpvAccess(_groupIDTable))[i];
187         IrrGroup *obj = CkpvAccess(_groupTable)->find(groupID).getObj();
188         /*if (obj->isArrMgr())
189         { / * This is an array manager: examine its array elements * /
190           CkArray *mgr=(CkArray *)obj;
191           CkArrayElementRangeIterator<T> ait(dest,lo,hi);
192           ait.iterate(cur, mgr);
193           cur+=ait.getCount();
194         } else {*/
195           dest->add(cur,obj,groupID.idx);
196           cur++;
197         //}
198      }
199    }
200
201    // Return the number of total array elements seen so far.
202    int getCount(void) {return cur;}
203 };
204
205 class ignoreAdd {
206 public: void add(int cur,Chare *elt,int group) {}
207 };
208
209 /** Examine all the objects on the server returning the name */
210 class CpdList_objectNames : public CpdListAccessor {
211   PUP::er *pp; // Only used while inside pup routine.
212   int curGroup;
213 public:
214   virtual const char * getPath(void) const {return "charm/objectNames";}
215   virtual size_t getLength(void) const {
216     CkObjectRangeIterator<ignoreAdd> it(0,0,0);
217     it.iterate();
218     return it.getCount();
219   }
220   virtual void pup(PUP::er &p, CpdListItemsRequest &req) {
221     pp=&p;
222     CkObjectRangeIterator<CpdList_objectNames> it(this,req.lo,req.hi);
223     it.iterate(); // calls "add" for in-range elements
224   }
225   void add(int cur, Chare *obj, int group) {
226     PUP::er &p=*pp;
227     beginItem(p,cur);
228     p.comment("id");
229     char *n = (char*)malloc(30);
230     int s=obj->ckDebugChareID(n, 30);
231     CkAssert(s > 0);
232     p(n,s);
233     free(n);
234     PUPn(group);
235     p.comment("name");
236     n=obj->ckDebugChareName();
237     p(n,strlen(n));
238     free(n);
239   }
240 };
241
242 /** Examine a single object identified by the id passed in the request and
243     return its type and memory data */
244 class CpdList_object : public CpdListAccessor {
245   PUP::er *pp; //Only used while inside pup routine.
246   CpdListItemsRequest *reqq; // Only used while inside pup routine.
247 public:
248   virtual const char * getPath(void) const {return "charm/object";}
249   virtual size_t getLength(void) const {
250     CkObjectRangeIterator<ignoreAdd> it(0,0,0);
251     it.iterate();
252     return it.getCount();
253   }
254   virtual void pup(PUP::er &p, CpdListItemsRequest &req) {
255     pp=&p;
256     reqq=&req;
257     CkObjectRangeIterator<CpdList_object> it(this,req.lo,req.hi);
258     it.iterate(); // calls "add" for in-range elements;
259   }
260   void add(int cur, Chare *obj, int group) {
261     PUP::er &p=*pp;
262     CpdListItemsRequest &req=*reqq;
263     char *n = (char *)malloc(30);
264     int s=obj->ckDebugChareID(n, 30);
265     CkAssert(s > 0);
266     if (req.extraLen == s && memcmp(req.extra, n, s) == 0) {
267       // the object match, found!
268       beginItem(p,cur);
269       int type = obj->ckGetChareType();
270       p.comment("type");
271       const char *t = _chareTable[type]->name;
272       p((char*)t,strlen(t));
273       p.comment("value");
274       int size = _chareTable[type]->size;
275       p((char*)obj,size);
276     }
277   }
278 };
279
280 /** Coarse: examine array element names */
281 class CpdList_arrayElementNames : public CpdListAccessor {
282   PUP::er *pp; // Only used while inside pup routine.
283 public:
284   virtual const char * getPath(void) const {return "charm/arrayElementNames";}
285   virtual size_t getLength(void) const {
286     CkArrayElementRangeIterator<ignoreAdd> it(0,0,0);
287     it.iterate();
288     return it.getCount();
289   }
290   virtual void pup(PUP::er &p, CpdListItemsRequest &req) {
291     pp=&p;
292     CkArrayElementRangeIterator<CpdList_arrayElementNames> it(this,req.lo,req.hi);
293     it.iterate(); // calls "add" for in-range elements
294   }
295   void add(int cur,Chare *e,int group)
296   { // Just grab the name and nothing else:
297     ArrayElement *elt = (ArrayElement*)e;
298          PUP::er &p=*pp;
299          beginItem(p,cur);
300          p.comment("name");
301          char *n=elt->ckDebugChareName();
302          p(n,strlen(n));
303          free(n);
304   }
305 };
306
307 /** Detailed: examine array element data */
308 class CpdList_arrayElements : public CpdListAccessor {
309   PUP::er *pp; // Only used while inside pup routine.
310 public:
311   virtual const char * getPath(void) const {return "charm/arrayElements";}
312   virtual size_t getLength(void) const {
313     CkArrayElementRangeIterator<ignoreAdd> it(0,0,0);
314     it.iterate();
315     return it.getCount();
316   }
317   virtual void pup(PUP::er &p, CpdListItemsRequest &req) {
318     pp=&p;
319     CkArrayElementRangeIterator<CpdList_arrayElements> it(this,req.lo,req.hi);
320     it.iterate(); // calls "add" for in-range elements
321   }
322   void add(int cur, Chare *e, int group)
323   { // Pup the element data
324     ArrayElement *elt = (ArrayElement*)e;
325     PUP::er &p=*pp;
326     beginItem(p,cur);
327     //elt->ckDebugPup(p);
328     // Now ignore any pupper, just copy all the memory as raw data
329     p.comment("name");
330     char *n=elt->ckDebugChareName();
331     p(n,strlen(n));
332     free(n);
333     int type = elt->ckGetChareType();
334     p.comment("type");
335     const char *t = _chareTable[type]->name;
336     p((char*)t,strlen(t));
337     p.comment("value");
338     int size = _chareTable[type]->size;
339     p((char*)elt,size);
340   }
341 };
342
343 #ifndef __CYGWIN__
344 #include <rpc/rpc.h>
345 #endif
346
347 size_t hostInfoLength(void *) {return 1;}
348
349 void hostInfo(void *itemIter, pup_er pp, CpdListItemsRequest *req) {
350   PUP::er &p = *(PUP::er *)pp;
351   struct sockaddr_in addr;
352   CpdListBeginItem(pp, 0);
353 #if CMK_HAS_GET_MYADDRESS
354   get_myaddress(&addr);
355 #else
356   CmiAbort("hostInfo: get_myaddress does not work on this machine");
357 #endif
358   char *address = (char*)&addr.sin_addr.s_addr;
359   PUPv(address, 4);
360   int pid = getpid();
361   PUPn(pid);
362 }
363
364 /************ Message CPD Lists ****************/
365 CkpvExtern(void *,debugQueue);
366
367 // Interpret data in a message in a user-friendly way.
368 //  Ignores most of the envelope fields used by CkPupMessage,
369 //  and instead concentrates on user data
370 void CpdPupMessage(PUP::er &p, void *msg)
371 {
372   envelope *env=UsrToEnv(msg);
373   //int wasPacked=env->isPacked();
374   int size=env->getTotalsize();
375   int prioBits=env->getPriobits();
376   int from=env->getSrcPe();
377   PUPn(from);
378   //PUPn(wasPacked);
379   PUPn(prioBits);
380   int userSize=size-sizeof(envelope)-sizeof(int)*CkPriobitsToInts(prioBits);
381   PUPn(userSize);
382   int msgType = env->getMsgIdx();
383   PUPn(msgType);
384   int envType = env->getMsgtype();
385   PUPn(envType);
386
387   //p.synchronize(PUP::sync_last_system);
388
389   int ep=CkMessageToEpIdx(msg);
390   PUPn(ep);
391
392   // Pup the information specific to this envelope type
393   if (envType == ForArrayEltMsg || envType == ArrayEltInitMsg) {
394     int arrID = env->getsetArrayMgr().idx;
395     PUPn(arrID);
396     CkArrayIndex &idx = env->getsetArrayIndex();
397     int nInts = idx.nInts;
398     int dimension = idx.dimension;
399     PUPn(nInts);
400     PUPn(dimension);
401     p.comment("index");
402     if (dimension >=4 && dimension <=6) {
403       p((short int *)idx.index, dimension);
404     } else {
405       p(idx.index, nInts);
406     }
407   } else if (envType == BocInitMsg || envType == NodeBocInitMsg ||
408              envType == ForNodeBocMsg || envType == ForBocMsg) {
409     int groupID = env->getGroupNum().idx;
410     PUPn(groupID);
411   } else if (envType == NewVChareMsg || envType == ForVidMsg || envType == FillVidMsg) {
412     p.comment("ptr");
413     void *ptr = env->getVidPtr();
414     pup_pointer(&p, &ptr);
415   } else if (envType == ForChareMsg) {
416     p.comment("ptr");
417     void *ptr = env->getObjPtr();
418     pup_pointer(&p, &ptr);
419   }
420   
421   /* user data */
422   p.comment("data");
423   p.synchronize(PUP::sync_begin_object);
424   if (_entryTable[ep]->messagePup!=NULL)
425     _entryTable[ep]->messagePup(p,msg);
426   else
427     CkMessage::ckDebugPup(p,msg);
428   p.synchronize(PUP::sync_end_object);
429 }
430
431 struct ConditionalList {
432   int count;
433   int deliver;
434   int msgs[1];
435 };
436 CkpvStaticDeclare(void *, lastBreakPointMsg);
437 CpvExtern(void*, conditionalQueue);
438 ConditionalList * conditionalShm = NULL;
439
440 //Cpd Lists for local and scheduler queues
441 class CpdList_localQ : public CpdListAccessor {
442
443 public:
444   CpdList_localQ() {}
445   virtual const char * getPath(void) const {return "converse/localqueue";}
446   virtual size_t getLength(void) const {
447     int x = CdsFifo_Length((CdsFifo)(CkpvAccess(debugQueue)));
448     //CmiPrintf("*******Returning fifo length %d*********\n", x);
449     //return CdsFifo_Length((CdsFifo)(CpvAccess(CmiLocalQueue)));
450     if (CkpvAccess(lastBreakPointMsg) != NULL) x++;
451     return x;
452   }
453   virtual void pup(PUP::er &p, CpdListItemsRequest &req) {
454     int length;
455     void ** messages;
456     int curObj=0;
457     void *msg;
458
459     length = CdsFifo_Length((CdsFifo)(CpvAccess(conditionalQueue)));
460     messages = CdsFifo_Enumerate(CpvAccess(conditionalQueue));
461     for (curObj=-length; curObj<0; curObj++) {
462       void *msg = messages[length+curObj];
463       pupSingleMessage(p, curObj-1, msg);
464     }
465     delete[] messages;
466     
467     curObj = 0;
468     length = CdsFifo_Length((CdsFifo)(CkpvAccess(debugQueue)));
469     messages = CdsFifo_Enumerate(CkpvAccess(debugQueue));
470     
471     if (CkpvAccess(lastBreakPointMsg) != NULL) {
472       beginItem(p, -1);
473       envelope *env=(envelope *)UsrToEnv(CkpvAccess(lastBreakPointMsg));
474       p.comment("name");
475       char *type=(char*)"Breakpoint";
476       p(type,strlen(type));
477       p.comment("charmMsg");
478       p.synchronize(PUP::sync_begin_object);
479       CkUnpackMessage(&env);
480       CpdPupMessage(p, EnvToUsr(env));
481       p.synchronize(PUP::sync_end_object);
482     }
483
484     for(curObj=req.lo; curObj<req.hi; curObj++)
485       if ((curObj>=0) && (curObj<length))
486       {
487         void *msg=messages[curObj]; /* converse message */
488         pupSingleMessage(p, curObj, msg);
489       }
490     delete[] messages;
491
492   }
493
494   void pupSingleMessage(PUP::er &p, int curObj, void *msg) {
495     beginItem(p,curObj);
496     int isCharm=0;
497     const char *type="Converse";
498     p.comment("name");
499     char name[128];
500     if (msg == (void*)-1) {
501       type="Sentinel";
502       p((char*)type, strlen(type));
503       return;
504     }
505 #if ! CMK_BLUEGENE_CHARM
506     if (CmiGetHandler(msg)==_charmHandlerIdx) {isCharm=1; type="Local Charm";}
507     if (CmiGetXHandler(msg)==_charmHandlerIdx) {isCharm=1; type="Network Charm";}
508 #else
509     isCharm=1; type="BG";
510 #endif
511     if (curObj < 0) type="Conditional";
512     sprintf(name,"%s %d: %s (%d)","Message",curObj,type,CmiGetHandler(msg));
513     p(name, strlen(name));
514
515     if (isCharm)
516     { /* charm message */
517       p.comment("charmMsg");
518       p.synchronize(PUP::sync_begin_object);
519       envelope *env=(envelope *)msg;
520       CkUnpackMessage(&env);
521       //messages[curObj]=env;
522       CpdPupMessage(p, EnvToUsr(env));
523       //CkPupMessage(p, &messages[curObj], 0);
524       p.synchronize(PUP::sync_end_object);
525     }
526   }
527 };
528
529 class CpdList_message : public CpdListAccessor {
530   virtual const char * getPath(void) const {return "converse/message";}
531   virtual size_t getLength(void) const {return 1;}
532   virtual void pup(PUP::er &p, CpdListItemsRequest &req) {
533     envelope *env = (envelope*)(((unsigned int)req.lo) + (((unsigned long)req.hi)<<32)+sizeof(CmiChunkHeader));
534     beginItem(p, 0);
535     const char *type="Converse";
536     p.comment("name");
537     char name[128];
538     if (CmiGetHandler(env)==_charmHandlerIdx) {type="Local Charm";}
539     if (CmiGetXHandler(env)==_charmHandlerIdx) {type="Network Charm";}
540     sprintf(name,"%s 0: %s (%d)","Message",type,CmiGetHandler(env));
541     p(name, strlen(name));
542     p.comment("charmMsg");
543     p.synchronize(PUP::sync_begin_object);
544     CpdPupMessage(p, EnvToUsr(env));
545     p.synchronize(PUP::sync_end_object);
546   }
547 };
548
549 static void CpdDeliverMessageInt(int msgNum) {
550   void *m;
551   void *debugQ=CkpvAccess(debugQueue);
552   CdsFifo_Enqueue(debugQ, (void*)(-1)); // Enqueue a guard
553   for (int i=0; i<msgNum; ++i) CdsFifo_Enqueue(debugQ, CdsFifo_Dequeue(debugQ));
554   CkpvAccess(skipBreakpoint) = 1;
555   char *queuedMsg = (char *)CdsFifo_Dequeue(debugQ);
556   if (_conditionalDelivery==1) conditionalShm->msgs[conditionalShm->count++] = msgNum;
557   if (_conditionalDelivery) {
558     CmiReference(queuedMsg);
559     CdsFifo_Enqueue(CpvAccess(conditionalQueue), queuedMsg);
560   }  
561 #if CMK_BLUEGENE_CHARM
562   stopVTimer();
563   BgProcessMessageDefault(cta(threadinfo), queuedMsg);
564   startVTimer();
565 #else
566   CmiHandleMessage(queuedMsg);
567 #endif
568   CkpvAccess(skipBreakpoint) = 0;
569   while ((m=CdsFifo_Dequeue(debugQ)) != (void*)(-1)) CdsFifo_Enqueue(debugQ, m);  
570 }
571
572 void CpdDeliverMessage(char * msg) {
573   int msgNum;
574   sscanf(msg+CmiMsgHeaderSizeBytes, "%d", &msgNum);
575   //CmiPrintf("received deliver request %d\n",msgNum);
576   CpdDeliverMessageInt(msgNum);
577 }
578
579 void *CpdGetNextMessageConditional(CsdSchedulerState_t *s) {
580   int len;
581   void *msg;
582   if ((msg=CdsFifo_Dequeue(s->localQ)) != NULL) return msg;
583   CqsDequeue((Queue_struct*)s->schedQ,(void **)&msg);
584   if (msg!=NULL) return msg;
585   read(conditionalPipe[0], &len, 4);
586   msg = CmiAlloc(len);
587   read(conditionalPipe[0], msg, len);
588   return msg;
589 }
590
591 #include <sys/wait.h>
592 #include <sys/ipc.h>
593 #include <sys/shm.h>
594
595 extern "C" void CpdDeliverSingleMessage ();
596
597 static pid_t CpdConditional_SetupComm() {
598   int pipefd[2][2];
599   pipe(pipefd[0]); // parent to child
600   pipe(pipefd[1]); // child to parent
601   
602   if (conditionalShm == NULL) {
603     struct shmid_ds dummy;
604     int shmemid = shmget(IPC_PRIVATE, 1024*1024, IPC_CREAT | 0666);
605     conditionalShm = (ConditionalList*)shmat(shmemid, NULL, 0);
606     conditionalShm->count = 0;
607     conditionalShm->deliver = 0;
608     shmctl(shmemid, IPC_RMID, &dummy);
609   }
610   
611   pid_t pid = fork();
612   if (pid > 0) {
613     int bytes;
614     CmiPrintf("parent %d\n",pid);
615     close(pipefd[0][0]);
616     close(pipefd[1][1]);
617     conditionalPipe[0] = pipefd[1][0];
618     conditionalPipe[1] = pipefd[0][1];
619     //CpdConditionalDeliveryScheduler(pipefd[1][0], pipefd[0][1]);
620     read(conditionalPipe[0], &bytes, 4);
621     char *buf = (char*)malloc(bytes);
622     read(conditionalPipe[0], buf, bytes);
623     CcsSendReply(bytes,buf);
624     free(buf);
625     return pid;
626   }
627
628   //int volatile tmp=1;
629   //while (tmp);
630   printf("child\n");
631   _conditionalDelivery = 1;
632   close(pipefd[0][1]);
633   close(pipefd[1][0]);
634   conditionalPipe[0] = pipefd[0][0];
635   conditionalPipe[1] = pipefd[1][1];
636   CpdGetNextMessage = CpdGetNextMessageConditional;
637   return 0;
638 }
639
640 void CpdEndConditionalDelivery(char *msg) {
641   int msgNum;
642   void *m;
643   sscanf(msg+CmiMsgHeaderSizeBytes, "%d", &msgNum);
644   printf("%d messages:\n",conditionalShm->count);
645   for (int i=0; i<conditionalShm->count; ++i)
646     printf("message delivered %d\n",conditionalShm->msgs[i]);
647   conditionalShm->count = msgNum;
648   shmdt((char*)conditionalShm);
649   _exit(0);
650 }
651
652 extern "C" void CpdEndConditionalDeliver_master() {
653   close(conditionalPipe[0]);
654   conditionalPipe[0] = 0;
655   close(conditionalPipe[1]);
656   conditionalPipe[1] = 0;
657   wait(NULL);
658   int i;
659   // Check if we have to deliver unconditionally some messages
660   if (conditionalShm->deliver > 0) {
661     // Deliver the requested number of messages
662     for (i=0; i < conditionalShm->deliver; ++i) {
663       int msgNum = conditionalShm->msgs[i];
664       if (msgNum == -1) CpdDeliverSingleMessage();
665       else CpdDeliverMessageInt(msgNum);
666     }
667     // Move back the remaining messages accordingly
668     for (i=conditionalShm->deliver; i < conditionalShm->count; ++i) {
669       conditionalShm->msgs[i-conditionalShm->deliver] = conditionalShm->msgs[i];
670     }
671     conditionalShm->count -= conditionalShm->deliver;
672     conditionalShm->deliver = 0;
673     CmiMachineProgressImpl();
674   }
675   CkAssert(conditionalShm->count >= 0);
676   if (conditionalShm->count == 0) {
677     CcsSendReply(0,NULL);
678     shmdt((char*)conditionalShm);
679     conditionalShm = NULL;
680     CkPrintf("Conditional delivery on %d concluded; normal mode resumed\n",CkMyPe());
681   } else {
682     if (CpdConditional_SetupComm()==0) {
683       // We are in the child, deliver again the messages
684       _conditionalDelivery = 2;
685       printf("new child: redelivering %d messages\n",conditionalShm->count);
686       for (int i=0; i<conditionalShm->count; ++i) {
687         int msgNum = conditionalShm->msgs[i];
688         if (msgNum == -1) CpdDeliverSingleMessage();
689         else CpdDeliverMessageInt(msgNum);
690       }
691       _conditionalDelivery = 1;
692       CcsSendReply(0, NULL);
693     }
694   }
695 }
696
697 void CpdDeliverMessageConditionally(char * msg) {
698   int msgNum;
699   void *m;
700   sscanf(msg+CmiMsgHeaderSizeBytes, "%d", &msgNum);
701   //CmiPrintf("received deliver request %d\n",msgNum);
702
703   if (CpdConditional_SetupComm()==0) {
704     if (msgNum == -1) CpdDeliverSingleMessage();
705     else CpdDeliverMessageInt(msgNum);
706   }
707 }
708
709 void CpdCommitConditionalDelivery(char * msg) {
710   int msgNum;
711   sscanf(msg+CmiMsgHeaderSizeBytes, "%d", &msgNum);\
712   conditionalShm->deliver = msgNum;
713   shmdt((char*)conditionalShm);
714   _exit(0);
715 }
716
717 class CpdList_msgStack : public CpdListAccessor {
718   virtual const char * getPath(void) const {return "charm/messageStack";}
719   virtual size_t getLength(void) const {
720     return _debugData.length();
721   }
722   virtual void pup(PUP::er &p, CpdListItemsRequest &req) {
723     for (int i=0; i<_debugData.length(); ++i) {
724       beginItem(p, i);
725       void *obj = _debugData[i].obj;
726       p.comment("obj");
727       pup_pointer(&p, &obj);
728       void *msg = _debugData[i].msg;
729       p.comment("msg");
730       pup_pointer(&p, &msg);
731     }
732   }
733 };
734
735 /****************** Breakpoints and other debug support **************/
736
737 typedef CkHashtableTslow<int,EntryInfo *> CpdBpFuncTable_t;
738
739 extern void CpdFreeze(void);
740 extern void CpdUnFreeze(void);
741 extern int  CpdIsFrozen(void);
742
743 CpvStaticDeclare(int, _debugMsg);
744 CpvStaticDeclare(int, _debugChare);
745
746 CpvStaticDeclare(CpdBpFuncTable_t *, breakPointEntryTable);
747
748 //CpvStaticDeclare(void *, lastBreakPointMsg);
749 CkpvStaticDeclare(void *, lastBreakPointObject);
750 CkpvStaticDeclare(int, lastBreakPointIndex);
751
752 void CpdBreakPointInit()
753 {
754   CkpvInitialize(void *, lastBreakPointMsg);
755   CkpvInitialize(void *, lastBreakPointObject);
756   CkpvInitialize(int, lastBreakPointIndex);
757   CpvInitialize(int, _debugMsg);
758   CpvInitialize(int, _debugChare);
759   CpvInitialize(CpdBpFuncTable_t *, breakPointEntryTable);
760   CkpvAccess(lastBreakPointMsg) = NULL;
761   CkpvAccess(lastBreakPointObject) = NULL;
762   CkpvAccess(lastBreakPointIndex) = 0;
763   CpvAccess(_debugMsg) = CkRegisterMsg("debug_msg",0,0,0,0);
764   CpvAccess(_debugChare) = CkRegisterChare("debug_Chare",0,TypeChare);
765   CkRegisterChareInCharm(CpvAccess(_debugChare));
766   CpvAccess(breakPointEntryTable) = new CpdBpFuncTable_t(10,0.5,CkHashFunction_int,CkHashCompare_int );
767 }
768
769 static void _call_freeze_on_break_point(void * msg, void * object)
770 {
771       //Save breakpoint entry point index. This is retrieved from msg.
772       //So that the appropriate EntryInfo can be later retrieved from the hash table
773       //of break point function entries, on continue.
774
775   // If the counter "skipBreakpoint" is not zero we actually do not freeze and deliver the regular message
776   EntryInfo * breakPointEntryInfo = CpvAccess(breakPointEntryTable)->get(CkMessageToEpIdx(msg));
777   if (CkpvAccess(skipBreakpoint) > 0 || CkpvAccess(_debugEntryTable)[CkMessageToEpIdx(msg)].isBreakpoint==CmiFalse) {
778     CkAssert(breakPointEntryInfo != NULL);
779     breakPointEntryInfo->call(msg, object);
780     if (CkpvAccess(skipBreakpoint) > 0) CkpvAccess(skipBreakpoint) --;
781   } else {
782       CkpvAccess(lastBreakPointMsg) = msg;
783       CkpvAccess(lastBreakPointObject) = object;
784       CkpvAccess(lastBreakPointIndex) = CkMessageToEpIdx(msg);
785       CpdNotify(CPD_BREAKPOINT,breakPointEntryInfo->name);
786       CpdFreeze();
787 #if CMK_BLUEGENE_CHARM
788       stopVTimer();
789       ((workThreadInfo*)cta(threadinfo))->scheduler(-1);
790 #endif
791   }
792 }
793
794 //ccs handler when pressed the "next" command: deliver only a single message without unfreezing
795 extern "C"
796 void CpdDeliverSingleMessage () {
797   if (!CpdIsFrozen()) return; /* Do something only if we are in freeze mode */
798   if ( (CkpvAccess(lastBreakPointMsg) != NULL) && (CkpvAccess(lastBreakPointObject) != NULL) ) {
799     EntryInfo * breakPointEntryInfo = CpvAccess(breakPointEntryTable)->get(CkpvAccess(lastBreakPointIndex));
800     if (breakPointEntryInfo != NULL) {
801       if (_conditionalDelivery) {
802         if (_conditionalDelivery==1) conditionalShm->msgs[conditionalShm->count++] = -1;
803         void *env = UsrToEnv(CkpvAccess(lastBreakPointMsg));
804         CmiReference(env);
805         CdsFifo_Enqueue(CpvAccess(conditionalQueue),env);
806       }
807       breakPointEntryInfo->call(CkpvAccess(lastBreakPointMsg), CkpvAccess(lastBreakPointObject));
808     }
809     CkpvAccess(lastBreakPointMsg) = NULL;
810     CkpvAccess(lastBreakPointObject) = NULL;
811 #if CMK_BLUEGENE_CHARM
812     ((workThreadInfo*)cta(threadinfo))->stopScheduler();
813 #endif
814   }
815   else {
816     // we were not stopped at a breakpoint, then deliver the first message in the debug queue
817     if (!CdsFifo_Empty(CkpvAccess(debugQueue))) {
818       CkpvAccess(skipBreakpoint) = 1;
819       char *queuedMsg = (char *)CdsFifo_Dequeue(CkpvAccess(debugQueue));
820       if (_conditionalDelivery) {
821         if (_conditionalDelivery==1) conditionalShm->msgs[conditionalShm->count++] = 0;
822         CmiReference(queuedMsg);
823         CdsFifo_Enqueue(CpvAccess(conditionalQueue),queuedMsg);
824       }
825 #if CMK_BLUEGENE_CHARM
826       stopVTimer();
827       BgProcessMessageDefault(cta(threadinfo), queuedMsg);
828       startVTimer();
829 #else
830       CmiHandleMessage(queuedMsg);
831 #endif
832       CkpvAccess(skipBreakpoint) = 0;
833     }
834   }
835 }
836
837 //ccs handler when continue from a break point
838 extern "C"
839 void CpdContinueFromBreakPoint ()
840 {
841     CpdUnFreeze();
842     if ( (CkpvAccess(lastBreakPointMsg) != NULL) && (CkpvAccess(lastBreakPointObject) != NULL) )
843     {
844         EntryInfo * breakPointEntryInfo = CpvAccess(breakPointEntryTable)->get(CkpvAccess(lastBreakPointIndex));
845         if (breakPointEntryInfo != NULL) {
846            breakPointEntryInfo->call(CkpvAccess(lastBreakPointMsg), CkpvAccess(lastBreakPointObject));
847 #if CMK_BLUEGENE_CHARM
848            ((workThreadInfo*)cta(threadinfo))->stopScheduler();
849 #endif
850         } else {
851           // This means that the breakpoint got deleted in the meanwhile
852           
853         }
854     }
855     CkpvAccess(lastBreakPointMsg) = NULL;
856     CkpvAccess(lastBreakPointObject) = NULL;
857 }
858
859 //ccs handler to set a breakpoint with entry function name msg
860 void CpdSetBreakPoint (char *msg)
861 {
862   char functionName[128];
863   int tableSize, tableIdx = 0;
864   int reply = 0;
865   sscanf(msg+CmiReservedHeaderSize, "%s", functionName);
866   if (strlen(functionName) > 0)
867   {
868     tableSize = _entryTable.size();
869     // Replace entry in entry table with _call_freeze_on_break_point
870     tableIdx = atoi(functionName);
871     if (tableIdx >= 0 && tableIdx < tableSize) {
872       if (! CkpvAccess(_debugEntryTable)[tableIdx].isBreakpoint) {
873            EntryInfo * breakPointEntryInfo = (EntryInfo *)CpvAccess(breakPointEntryTable)->get(tableIdx);
874            if (breakPointEntryInfo == 0) {
875              breakPointEntryInfo = new EntryInfo(_entryTable[tableIdx]->name, _entryTable[tableIdx]->call, 1, 0 );
876              //CmiPrintf("Breakpoint is set for function %s with an epIdx = %ld\n", _entryTable[tableIdx]->name, tableIdx);
877              CpvAccess(breakPointEntryTable)->put(tableIdx) = breakPointEntryInfo;
878              _entryTable[tableIdx]->name = "debug_breakpoint_ep";
879              _entryTable[tableIdx]->call = (CkCallFnPtr)_call_freeze_on_break_point;
880            } else {
881              if (breakPointEntryInfo->msgIdx == 0) {
882                // Reset the breakpoint info
883                _entryTable[tableIdx]->name = "debug_breakpoint_ep";
884                _entryTable[tableIdx]->call = (CkCallFnPtr)_call_freeze_on_break_point;
885              }
886              breakPointEntryInfo->msgIdx ++;
887              //CkAssert(breakPointEntryInfo->name == _entryTable[tableIdx]->name);
888              //CkAssert(breakPointEntryInfo->call == _entryTable[tableIdx]->call);
889              //CkAssert(breakPointEntryInfo->msgIdx == _entryTable[tableIdx]->msgIdx);
890              //CkAssert(breakPointEntryInfo->chareIdx == _entryTable[tableIdx]->chareIdx);
891            }
892            CkpvAccess(_debugEntryTable)[tableIdx].isBreakpoint = CmiTrue;
893            reply = ~0;
894       }
895     }
896
897   }
898   CcsSendReply(sizeof(int), (void*)&reply);
899
900 }
901
902 void CpdQuitDebug()
903 {
904   CpdContinueFromBreakPoint();
905   CkExit();
906 }
907
908 void CpdRemoveBreakPoint (char *msg)
909 {
910   char functionName[128];
911   int reply = 0;
912   sscanf(msg+CmiReservedHeaderSize, "%s", functionName);
913   if (strlen(functionName) > 0) {
914     int idx = atoi(functionName);
915     if (idx >= 0 && idx < _entryTable.size()) {
916       if (CkpvAccess(_debugEntryTable)[idx].isBreakpoint) {
917         EntryInfo * breakPointEntryInfo = CpvAccess(breakPointEntryTable)->get(idx);
918         if (breakPointEntryInfo != NULL) {
919           if (--breakPointEntryInfo->msgIdx == 0) {
920             // If we are the last to delete the breakpoint, then restore the original name and call function pointer
921             _entryTable[idx]->name =  breakPointEntryInfo->name;
922             _entryTable[idx]->call = (CkCallFnPtr)breakPointEntryInfo->call;
923           }
924           reply = ~0 ;
925           CkpvAccess(_debugEntryTable)[idx].isBreakpoint = CmiFalse;
926           //CmiPrintf("Breakpoint is removed for function %s with epIdx %ld\n", _entryTable[idx]->name, idx);
927           //CkpvAccess(breakPointEntryTable)->remove(idx);
928         }
929       }
930     }
931   }
932   CcsSendReply(sizeof(int), (void*)&reply);
933 }
934
935 void CpdRemoveAllBreakPoints ()
936 {
937   //all breakpoints removed
938   void *objPointer;
939   void *keyPointer;
940   int reply = 1;
941   CkHashtableIterator *it = CpvAccess(breakPointEntryTable)->iterator();
942   while(NULL!=(objPointer = it->next(&keyPointer)))
943   {
944     EntryInfo * breakPointEntryInfo = *(EntryInfo **)objPointer;
945     int idx = *(int *)keyPointer;
946     if (--breakPointEntryInfo->msgIdx == 0) {
947       // If we are the last to delete the breakpoint, then restore the original name and call function pointer
948       _entryTable[idx]->name =  breakPointEntryInfo->name;
949       _entryTable[idx]->call = (CkCallFnPtr)breakPointEntryInfo->call;
950     }
951     CkpvAccess(_debugEntryTable)[idx].isBreakpoint = CmiFalse;
952   }
953   CcsSendReply(sizeof(int), (void*)&reply);
954 }
955
956 extern "C" int CpdIsCharmDebugMessage(void *msg) {
957   envelope *env = (envelope*)msg;
958   // Later should use "isDebug" value, but for now just bypass all intrinsic EPs
959   return CmiGetHandler(msg) != _charmHandlerIdx || env->getMsgtype() == ForVidMsg ||
960          env->getMsgtype() == FillVidMsg || _entryTable[env->getEpIdx()]->inCharm;
961 }
962
963 #if CMK_BLUEGENE_CHARM
964 CpvExtern(int, _bgCcsHandlerIdx);
965 extern "C" int CpdIsBgCharmDebugMessage(void *msg) {
966   envelope *env = (envelope*)msg;
967   if (CmiBgMsgFlag(msg) == BG_CLONE) {
968     env=*(envelope**)(((char*)msg)+CmiBlueGeneMsgHeaderSizeBytes);
969   }
970   if  ((((CmiBlueGeneMsgHeader*)env)->hID) == CpvAccess(_bgCcsHandlerIdx)) return 1;
971     // make sure it indeed is a charm message
972   if (CmiBgMsgHandle(env) == _charmHandlerIdx) {
973     return env->getMsgtype() == ForVidMsg || env->getMsgtype() == FillVidMsg ||
974          _entryTable[env->getEpIdx()]->inCharm;
975   }
976   return 1;
977 }
978 #endif
979
980 CpvExtern(char *, displayArgument);
981
982 void CpdStartGdb(void)
983 {
984 #if !defined(_WIN32) || defined(__CYGWIN__)
985   FILE *f;
986   char gdbScript[200];
987   int pid;
988   if (CpvAccess(displayArgument) != NULL)
989   {
990      /*CmiPrintf("MY NODE IS %d  and process id is %d\n", CmiMyPe(), getpid());*/
991      sprintf(gdbScript, "/tmp/cpdstartgdb.%d.%d", getpid(), CmiMyPe());
992      f = fopen(gdbScript, "w");
993      fprintf(f,"#!/bin/sh\n");
994      fprintf(f,"cat > /tmp/start_gdb.$$ << END_OF_SCRIPT\n");
995      fprintf(f,"shell /bin/rm -f /tmp/start_gdb.$$\n");
996      //fprintf(f,"handle SIGPIPE nostop noprint\n");
997      fprintf(f,"handle SIGWINCH nostop noprint\n");
998      fprintf(f,"handle SIGWAITING nostop noprint\n");
999      fprintf(f, "attach %d\n", getpid());
1000      fprintf(f,"END_OF_SCRIPT\n");
1001      fprintf(f, "DISPLAY='%s';export DISPLAY\n",CpvAccess(displayArgument));
1002      fprintf(f,"/usr/X11R6/bin/xterm ");
1003      fprintf(f," -title 'Node %d ' ",CmiMyPe());
1004      fprintf(f," -e /usr/bin/gdb -x /tmp/start_gdb.$$ \n");
1005      fprintf(f, "exit 0\n");
1006      fclose(f);
1007      if( -1 == chmod(gdbScript, 0755))
1008      {
1009         CmiPrintf("ERROR> chmod on script failed!\n");
1010         return;
1011      }
1012      pid = fork();
1013      if (pid < 0)
1014         { perror("ERROR> forking to run debugger script\n"); exit(1); }
1015      if (pid == 0)
1016      {
1017          //CmiPrintf("In child process to start script %s\n", gdbScript);
1018  if (-1 == execvp(gdbScript, NULL))
1019             CmiPrintf ("Error> Could not Execute Debugger Script: %s\n",strerror
1020 (errno));
1021
1022       }
1023     }
1024 #endif
1025 }
1026
1027 extern "C" {
1028   size_t cpd_memory_length(void*);
1029   void cpd_memory_pup(void*,void*,CpdListItemsRequest*);
1030   void cpd_memory_leak(void*,void*,CpdListItemsRequest*);
1031   size_t cpd_memory_getLength(void*);
1032   void cpd_memory_get(void*,void*,CpdListItemsRequest*);
1033 }
1034
1035
1036 void CpdCharmInit()
1037 {
1038   CpdListRegister(new CpdListAccessor_c("memory/list",cpd_memory_length,0,cpd_memory_pup,0));
1039   CpdListRegister(new CpdListAccessor_c("memory/data",cpd_memory_getLength,0,cpd_memory_get,0,false));
1040
1041   //CpdBreakPointInit();
1042   CcsRegisterHandler("debug/charm/bp/set",(CmiHandler)CpdSetBreakPoint);
1043   CcsSetMergeFn("debug/charm/bp/set",CcsMerge_logical_and);
1044   CcsRegisterHandler("debug/charm/bp/remove",(CmiHandler)CpdRemoveBreakPoint);
1045   CcsSetMergeFn("debug/charm/bp/remove",CcsMerge_logical_and);
1046   CcsRegisterHandler("debug/charm/bp/removeall",(CmiHandler)CpdRemoveAllBreakPoints);
1047   CcsSetMergeFn("debug/charm/bp/removeall",CmiReduceMergeFn_random);
1048   CcsRegisterHandler("debug/charm/continue",(CmiHandler)CpdContinueFromBreakPoint);
1049   CcsSetMergeFn("debug/charm/continue",CmiReduceMergeFn_random);
1050   CcsRegisterHandler("debug/charm/next",(CmiHandler)CpdDeliverSingleMessage);
1051   CcsSetMergeFn("debug/charm/next",CmiReduceMergeFn_random);
1052   CcsRegisterHandler("debug/converse/quit",(CmiHandler)CpdQuitDebug);
1053   CcsSetMergeFn("debug/converse/quit",CmiReduceMergeFn_random);
1054   CcsRegisterHandler("debug/converse/startgdb",(CmiHandler)CpdStartGdb);
1055   CpdListRegister(new CpdListAccessor_c("hostinfo",hostInfoLength,0,hostInfo,0));
1056   CpdListRegister(new CpdList_localQ());
1057   CcsRegisterHandler("debug/charm/deliver",(CmiHandler)CpdDeliverMessage);
1058   CcsRegisterHandler("debug/provisional/deliver",(CmiHandler)CpdDeliverMessageConditionally);
1059   CcsRegisterHandler("debug/provisional/rollback",(CmiHandler)CpdEndConditionalDelivery);
1060   CcsRegisterHandler("debug/provisional/commit",(CmiHandler)CpdCommitConditionalDelivery);
1061   CpdListRegister(new CpdList_arrayElementNames());
1062   CpdListRegister(new CpdList_arrayElements());
1063   CpdListRegister(new CpdList_objectNames());
1064   CpdListRegister(new CpdList_object());
1065   CpdListRegister(new CpdList_message());
1066   CpdListRegister(new CpdList_msgStack());
1067   CpdGetNextMessage = CsdNextMessage;
1068   CpdIsDebugMessage = CpdIsCharmDebugMessage;
1069 #if CMK_BLUEGENE_CHARM
1070   CpdIsDebugMessage = CpdIsBgCharmDebugMessage;
1071 #endif
1072 }
1073
1074 #if CMK_BLUEGENE_CHARM
1075 CpvExtern(int, _bgCcsHandlerIdx);
1076 CpvExtern(int, _bgCcsAck);
1077 extern "C" void req_fw_handler(char*);
1078 CkpvExtern(void *, debugQueue);
1079 CkpvExtern(int, freezeModeFlag);
1080 #include "blue_impl.h"
1081 extern void BgProcessMessageFreezeMode(threadInfo *, char *);
1082
1083 void CpdBgInit()
1084 {
1085         // Register the BG handler for CCS. Notice that this is put into a variable shared by
1086         // the whole real processor. This because converse needs to find it. We check that all
1087         // virtual processors register the same index for this handler.
1088         int bgCcsHandlerIdx = CkRegisterHandler((CmiHandler)req_fw_handler);
1089         if (CpvAccess(_bgCcsHandlerIdx) == 0) CpvAccess(_bgCcsHandlerIdx) = bgCcsHandlerIdx;
1090         CkAssert(CpvAccess(_bgCcsHandlerIdx)==bgCcsHandlerIdx);
1091         CpvAccess(_bgCcsAck) ++;
1092         CcsReleaseMessages();
1093         
1094         CkpvInitialize(int, freezeModeFlag);
1095         CkpvAccess(freezeModeFlag) = 0;
1096
1097         CkpvInitialize(void *, debugQueue);
1098         CkpvAccess(debugQueue) = CdsFifo_Create();
1099         
1100         BgProcessMessage = BgProcessMessageFreezeMode;
1101 }
1102 #endif
1103
1104 #else
1105
1106 void CpdBreakPointInit() {}
1107 void CpdCharmInit() {}
1108 #if CMK_BLUEGENE_CHARM
1109 void CpdBgInit() {}
1110 #endif
1111
1112 void CpdFinishInitialization() {}
1113
1114 void *CpdGetCurrentObject() {return NULL;}
1115 void *CpdGetCurrentMsg() {return NULL;}
1116 extern "C" void CpdEndConditionalDeliver_master() {}
1117
1118 void CpdBeforeEp(int ep, void *obj, void *msg) {}
1119 void CpdAfterEp(int ep) {}
1120
1121 #endif /*CMK_CCS_AVAILABLE*/
1122