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