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