Fixed CpdIsBdCharmDebugMessage with Gengbin
[charm.git] / src / conv-ccs / conv-ccs.c
1 /*****************************************************************************
2  * $Source$
3  * $Author$
4  * $Date$
5  * $Revision$
6  *****************************************************************************/
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <errno.h>
11 #include <string.h>
12
13 #include "converse.h"
14 #include "conv-ccs.h"
15 #include "ccs-server.h"
16 #include "sockRoutines.h"
17 #include "queueing.h"
18
19 #if CMK_CCS_AVAILABLE
20
21 /*****************************************************************************
22  *
23  * Converse Client-Server Functions
24  *
25  *****************************************************************************/
26  
27 static void initHandlerRec(CcsHandlerRec *c,const char *name) {
28   if (strlen(name)>=CCS_MAXHANDLER) 
29         CmiAbort("CCS handler names cannot exceed 32 characters");
30   c->name=strdup(name);
31   c->fn=NULL;
32   c->fnOld=NULL;
33   c->userPtr=NULL;
34   c->mergeFn=NULL;
35   c->nCalls=0;
36 }
37
38 static void callHandlerRec(CcsHandlerRec *c,int reqLen,const void *reqData) {
39         c->nCalls++;
40         if (c->fnOld) 
41         { /* Backward compatability version:
42             Pack user data into a converse message (cripes! why bother?);
43             user will delete the message. 
44           */
45                 char *cmsg = (char *) CmiAlloc(CmiReservedHeaderSize+reqLen);
46                 memcpy(cmsg+CmiReservedHeaderSize, reqData, reqLen);
47                 (c->fnOld)(cmsg);
48         }
49         else { /* Pass read-only copy of data straight to user */
50                 (c->fn)(c->userPtr, reqLen, reqData);
51         }
52 }
53
54 /*Table maps handler name to CcsHandler object*/
55 CpvDeclare(CcsHandlerTable, ccsTab);
56
57 CpvStaticDeclare(CcsImplHeader*,ccsReq);/*Identifies CCS requestor (client)*/
58
59 void CcsRegisterHandler(const char *name, CmiHandler fn) {
60   CcsHandlerRec cp;
61   initHandlerRec(&cp,name);
62   cp.fnOld=fn;
63   *(CcsHandlerRec *)CkHashtablePut(CpvAccess(ccsTab),(void *)&cp.name)=cp;
64 }
65 void CcsRegisterHandlerFn(const char *name, CcsHandlerFn fn, void *ptr) {
66   CcsHandlerRec cp;
67   initHandlerRec(&cp,name);
68   cp.fn=fn;
69   cp.userPtr=ptr;
70   *(CcsHandlerRec *)CkHashtablePut(CpvAccess(ccsTab),(void *)&cp.name)=cp;
71 }
72 CcsHandlerRec *CcsGetHandler(const char *name) {
73   return CkHashtableGet(CpvAccess(ccsTab),(void *)&name);
74 }
75 void CcsSetMergeFn(const char *name, CmiReduceMergeFn newMerge) {
76   CcsHandlerRec *rec=(CcsHandlerRec *)CkHashtableGet(CpvAccess(ccsTab),(void *)&name);
77   if (rec==NULL) {
78     CmiAbort("CCS: Unknown CCS handler name.\n");
79   }
80   rec->mergeFn=newMerge;
81   rec->redID=CmiGetGlobalReduction();
82 }
83
84 void * CcsMerge_concat(int *size,void *local,void **remote,int n) {
85   CcsImplHeader *hdr;
86   int total = *size;
87   void *reply;
88   char *ptr;
89   int i;
90   for (i=0; i<n; ++i) {
91     hdr = (CcsImplHeader*)(((char*)remote[i])+CmiReservedHeaderSize);
92     total += ChMessageInt(hdr->len);
93   }
94   reply = CmiAlloc(total);
95   memcpy(reply, local, *size);
96   ((CcsImplHeader*)(((char*)reply)+CmiReservedHeaderSize))->len = ChMessageInt_new(total-CmiReservedHeaderSize-sizeof(CcsImplHeader));
97   CmiFree(local);
98   ptr = ((char*)reply)+*size;
99   for (i=0; i<n; ++i) {
100     int len = ChMessageInt(((CcsImplHeader*)(((char*)remote[i])+CmiReservedHeaderSize))->len);
101     memcpy(ptr, ((char*)remote[i])+CmiReservedHeaderSize+sizeof(CcsImplHeader), len);
102     ptr += len;
103   }
104   *size = total;
105   return reply;
106 }
107
108 #define SIMPLE_REDUCTION(name, dataType, loop) \
109 void * CcsMerge_##name(int *size,void *local,void **remote,int n) { \
110   int i, m; \
111   CcsImplHeader *hdrLocal = (CcsImplHeader*)(((char*)local)+CmiReservedHeaderSize); \
112   int lenLocal = ChMessageInt(hdrLocal->len); \
113   int nElem = lenLocal / sizeof(dataType); \
114   dataType *ret = (dataType *) (hdrLocal+1); \
115   CcsImplHeader *hdr; \
116   for (m=0; m<n; ++m) { \
117     int len; \
118     dataType *value; \
119     hdr = (CcsImplHeader*)(((char*)remote[m])+CmiReservedHeaderSize); \
120     len = ChMessageInt(hdr->len); \
121     value = (dataType *)(hdr+1); \
122     CmiAssert(lenLocal == len); \
123     for (i=0; i<nElem; ++i) loop; \
124   } \
125   return local; \
126 }
127
128 SIMPLE_REDUCTION(logical_and, int, ret[i]=(ret[i]&&value[i])?1:0)
129 SIMPLE_REDUCTION(logical_or, int, ret[i]=(ret[i]||value[i])?1:0)
130 SIMPLE_REDUCTION(bitvec_and, int, ret[i]&=value[i])
131 SIMPLE_REDUCTION(bitvec_or, int, ret[i]|=value[i])
132
133 /*Use this macro for reductions that have the same type for all inputs */
134 #define SIMPLE_POLYMORPH_REDUCTION(nameBase,loop) \
135   SIMPLE_REDUCTION(nameBase##_int, int, loop) \
136   SIMPLE_REDUCTION(nameBase##_float, float, loop) \
137   SIMPLE_REDUCTION(nameBase##_double, double, loop)
138
139 SIMPLE_POLYMORPH_REDUCTION(sum, ret[i]+=value[i])
140 SIMPLE_POLYMORPH_REDUCTION(product, ret[i]*=value[i])
141 SIMPLE_POLYMORPH_REDUCTION(max, if (ret[i]<value[i]) ret[i]=value[i])
142 SIMPLE_POLYMORPH_REDUCTION(min, if (ret[i]>value[i]) ret[i]=value[i])
143
144 #undef SIMPLE_REDUCTION
145 #undef SIMPLE_POLYMORPH_REDUCTION
146
147 int CcsEnabled(void)
148 {
149   return 1;
150 }
151
152 int CcsIsRemoteRequest(void)
153 {
154   return CpvAccess(ccsReq)!=NULL;
155 }
156
157 void CcsCallerId(skt_ip_t *pip, unsigned int *pport)
158 {
159   *pip = CpvAccess(ccsReq)->attr.ip;
160   *pport = ChMessageInt(CpvAccess(ccsReq)->attr.port);
161 }
162
163 int rep_fw_handler_idx;
164
165 CcsDelayedReply CcsDelayReply(void)
166 {
167   CcsDelayedReply ret;
168   int len = sizeof(CcsImplHeader);
169   if (ChMessageInt(CpvAccess(ccsReq)->pe) < -1)
170     len += ChMessageInt(CpvAccess(ccsReq)->pe) * sizeof(int);
171   ret.hdr = (CcsImplHeader*)malloc(len);
172   memcpy(ret.hdr, CpvAccess(ccsReq), len);
173   CpvAccess(ccsReq)=NULL;
174   return ret;
175 }
176
177 void CcsSendReply(int replyLen, const void *replyData)
178 {
179   if (CpvAccess(ccsReq)==NULL)
180     CmiAbort("CcsSendReply: reply already sent!\n");
181   CpvAccess(ccsReq)->len = ChMessageInt_new(1);
182   CcsReply(CpvAccess(ccsReq),replyLen,replyData);
183   CpvAccess(ccsReq) = NULL;
184 }
185
186 void CcsSendDelayedReply(CcsDelayedReply d,int replyLen, const void *replyData)
187 {
188   CcsImplHeader *h = d.hdr;
189   h->len=ChMessageInt_new(1);
190   CcsReply(h,replyLen,replyData);
191   free(h);
192 }
193
194 void CcsNoReply()
195 {
196   if (CpvAccess(ccsReq)==NULL) return;
197   CpvAccess(ccsReq)->len = ChMessageInt_new(0);
198   CcsReply(CpvAccess(ccsReq),0,NULL);
199   CpvAccess(ccsReq) = NULL;
200 }
201
202 void CcsNoDelayedReply(CcsDelayedReply d)
203 {
204   CcsImplHeader *h = d.hdr;
205   h->len = ChMessageInt_new(0);
206   CcsReply(h,0,NULL);
207   free(h);
208 }
209
210
211 /**********************************
212 _CCS Implementation Routines:
213   These do the request forwarding and
214 delivery.
215 ***********************************/
216
217 /*CCS Bottleneck:
218   Deliver the given message data to the given
219 CCS handler.
220 */
221 void CcsHandleRequest(CcsImplHeader *hdr,const char *reqData)
222 {
223   char *cmsg;
224   int reqLen=ChMessageInt(hdr->len);
225 /*Look up handler's converse ID*/
226   char *handlerStr=hdr->handler;
227   CcsHandlerRec *fn=(CcsHandlerRec *)CkHashtableGet(CpvAccess(ccsTab),(void *)&handlerStr);
228   if (fn==NULL) {
229     CmiPrintf("CCS: Unknown CCS handler name '%s' requested. Ignoring...\n",
230               hdr->handler);
231     CpvAccess(ccsReq)=hdr;
232     CcsSendReply(0,NULL); /*Send an empty reply to the possibly waiting client*/
233     return;
234  /*   CmiAbort("CCS: Unknown CCS handler name.\n");*/
235   }
236
237 /* Call the handler */
238   CpvAccess(ccsReq)=hdr;
239   callHandlerRec(fn,reqLen,reqData);
240   
241 /*Check if a reply was sent*/
242   if (CpvAccess(ccsReq)!=NULL)
243     CcsSendReply(0,NULL);/*Send an empty reply if not*/
244 }
245
246 #if ! NODE_0_IS_CONVHOST || CMK_BLUEGENE_CHARM
247 /* The followings are necessary to prevent CCS requests to be processed before
248  * CCS has been initialized. Really it matters only when NODE_0_IS_CONVHOST=0, but
249  * it doesn't hurt having it in the other case as well */
250 static char **bufferedMessages = NULL;
251 static int CcsNumBufferedMsgs = 0;
252 #define CCS_MAX_NUM_BUFFERED_MSGS  100
253
254 void CcsBufferMessage(char *msg) {
255   CmiPrintf("Buffering CCS message\n");
256   CmiAssert(CcsNumBufferedMsgs < CCS_MAX_NUM_BUFFERED_MSGS);
257   if (CcsNumBufferedMsgs < 0) CmiAbort("Why is a CCS message being buffered now???");
258   if (bufferedMessages == NULL) bufferedMessages = malloc(sizeof(char*)*CCS_MAX_NUM_BUFFERED_MSGS);
259   bufferedMessages[CcsNumBufferedMsgs] = msg;
260   CcsNumBufferedMsgs ++;
261 }
262 #endif
263   
264 /*Unpacks request message to call above routine*/
265 int _ccsHandlerIdx = 0;/*Converse handler index of routine req_fw_handler*/
266
267 #if CMK_BLUEGENE_CHARM
268 CpvDeclare(int, _bgCcsHandlerIdx);
269 CpvDeclare(int, _bgCcsAck);
270 /* This routine is needed when the application is built on top of the bigemulator
271  * layer of Charm. In this case, the real CCS handler must be called within a
272  * worker thread. The function of this function is to receive the CCS message in
273  * the bottom converse layer and forward it to the emulated layer. */
274 static void bg_req_fw_handler(char *msg) {
275   if (CpvAccess(_bgCcsAck) < BgNodeSize()) {
276     CcsBufferMessage(msg);
277     return;
278   }
279   //CmiPrintf("CCS scheduling message\n");
280   /* Get out of the message who is the destination pe */
281   int offset = CmiReservedHeaderSize + sizeof(CcsImplHeader);
282   CcsImplHeader *hdr = (CcsImplHeader *)(msg+CmiReservedHeaderSize);
283   int destPE = (int)ChMessageInt(hdr->pe);
284   if (destPE == -1) destPE = 0;
285   if (destPE < -1) {
286     ChMessageInt_t *pes_nbo = (ChMessageInt_t *)(msg+CmiReservedHeaderSize+sizeof(CcsImplHeader));
287     destPE = ChMessageInt(pes_nbo[0]);
288   }
289   //CmiAssert(destPE >= 0); // FixME: should cover also broadcast and multicast -> create generic function to extract destpe
290   (((CmiBlueGeneMsgHeader*)msg)->tID) = 0;
291   (((CmiBlueGeneMsgHeader*)msg)->n) = 0;
292   (((CmiBlueGeneMsgHeader*)msg)->flag) = 0;
293   (((CmiBlueGeneMsgHeader*)msg)->t) = 0;
294   (((CmiBlueGeneMsgHeader*)msg)->hID) = CpvAccess(_bgCcsHandlerIdx);
295   /* Get the right thread to deliver to (for now assume it is using CyclicMapInfo) */
296   addBgNodeInbuffer(msg, destPE/CmiNumPes());
297   //CmiPrintf("message CCS added %d to %d\n",((CmiBlueGeneMsgHeader*)msg)->hID, ((CmiBlueGeneMsgHeader*)msg)->tID);
298 }
299 #define req_fw_handler bg_req_fw_handler
300 #endif
301 extern void req_fw_handler(char *msg);
302
303 void CcsReleaseMessages() {
304 #if ! NODE_0_IS_CONVHOST || CMK_BLUEGENE_CHARM
305 #if CMK_BLUEGENE_CHARM
306   if (CpvAccess(_bgCcsAck) == 0 || CpvAccess(_bgCcsAck) < BgNodeSize()) return;
307 #endif
308   if (CcsNumBufferedMsgs > 0) {
309     int i;
310     //CmiPrintf("CCS: %d messages released\n",CcsNumBufferedMsgs);
311     for (i=0; i<CcsNumBufferedMsgs; ++i) {
312       CmiSetHandler(bufferedMessages[i], _ccsHandlerIdx);
313       CsdEnqueue(bufferedMessages[i]);
314     }
315     free(bufferedMessages);
316     bufferedMessages = NULL;
317     CcsNumBufferedMsgs = -1;
318   }
319 #endif
320 }
321
322 /*Convert CCS header & message data into a converse message 
323  addressed to handler*/
324 char *CcsImpl_ccs2converse(const CcsImplHeader *hdr,const void *data,int *ret_len)
325 {
326   int reqLen=ChMessageInt(hdr->len);
327   int destPE = ChMessageInt(hdr->pe);
328   int len;
329   char *msg;
330   if (destPE < -1) reqLen -= destPE*sizeof(int);
331   len=CmiReservedHeaderSize+sizeof(CcsImplHeader)+reqLen;
332   msg=(char *)CmiAlloc(len);
333   memcpy(msg+CmiReservedHeaderSize,hdr,sizeof(CcsImplHeader));
334   memcpy(msg+CmiReservedHeaderSize+sizeof(CcsImplHeader),data,reqLen);
335   if (ret_len!=NULL) *ret_len=len;
336   if (_ccsHandlerIdx != 0) {
337     CmiSetHandler(msg, _ccsHandlerIdx);
338     return msg;
339   } else {
340 #if NODE_0_IS_CONVHOST
341     CmiAbort("Why do we need to buffer messages when node 0 is Convhost?");
342 #else
343     CcsBufferMessage(msg);
344     return NULL;
345 #endif
346   }
347 }
348
349 /*Receives reply messages passed up from
350 converse to node 0.*/
351 static void rep_fw_handler(char *msg)
352 {
353   int len;
354   char *r=msg+CmiReservedHeaderSize;
355   CcsImplHeader *hdr=(CcsImplHeader *)r; 
356   r+=sizeof(CcsImplHeader);
357   len=ChMessageInt(hdr->len);
358   CcsImpl_reply(hdr,len,r);
359   CmiFree(msg);
360 }
361
362 #if NODE_0_IS_CONVHOST
363 /************** NODE_0_IS_CONVHOST ***********
364 Non net- versions of charm++ are run without a 
365 (real) conv-host program.  This is fine, except 
366 CCS clients connect via conv-host; so for CCS
367 on non-net- versions of charm++, node 0 carries
368 out the CCS forwarding normally done in conv-host.
369
370 CCS works by listening to a TCP connection on a 
371 port-- the Ccs server socket.  A typical communcation
372 pattern is:
373
374 1.) Random program (CCS client) from the net
375 connects to the CCS server socket and sends
376 a CCS request.
377
378 2.) Node 0 forwards the request to the proper
379 PE as a regular converse message (built in CcsImpl_netReq)
380 for CcsHandleRequest.
381
382 3.) CcsHandleRequest looks up the user's pre-registered
383 CCS handler, and passes the user's handler the request data.
384
385 4.) The user's handler calls CcsSendReply with some
386 reply data; OR finishes without calling CcsSendReply,
387 in which case CcsHandleRequest does it.
388
389 5.) CcsSendReply forwards the reply back to node 0,
390 which sends the reply back to the original requestor,
391 on the (still-open) request socket.
392  */
393
394 /**
395 Send a Ccs reply back to the requestor, down the given socket.
396 Since there is no conv-host, node 0 does all the CCS 
397 communication-- this means all requests come to node 0
398 and are forwarded out; all replies are forwarded back to node 0.
399
400 Note: on Net- versions, CcsImpl_reply is implemented in machine.c
401 */
402 void CcsImpl_reply(CcsImplHeader *rep,int repLen,const void *repData)
403 {
404   const int repPE=0;
405   rep->len=ChMessageInt_new(repLen);
406   if (CmiMyPe()==repPE) {
407     /*Actually deliver reply data*/
408     CcsServer_sendReply(rep,repLen,repData);
409   } else {
410     /*Forward data & socket # to the replyPE*/
411     int len=CmiReservedHeaderSize+
412            sizeof(CcsImplHeader)+repLen;
413     char *msg=CmiAlloc(len);
414     char *r=msg+CmiReservedHeaderSize;
415     *(CcsImplHeader *)r=*rep; r+=sizeof(CcsImplHeader);
416     memcpy(r,repData,repLen);
417     CmiSetHandler(msg,rep_fw_handler_idx);
418     CmiSyncSendAndFree(repPE,len,msg);
419   }
420 }
421
422 /*No request will be sent through this socket.
423 Closes it.
424 */
425 /*void CcsImpl_noReply(CcsImplHeader *hdr)
426 {
427   int fd=ChMessageInt(hdr->replyFd);
428   skt_close(fd);
429 }*/
430
431 /**
432  * This is the entrance point of a CCS request into the server.
433  * It is executed only on proc 0, and it forwards the request to the appropriate PE.
434  */
435 void CcsImpl_netRequest(CcsImplHeader *hdr,const void *reqData)
436 {
437   char *msg;
438   int len,repPE=ChMessageInt(hdr->pe);
439   if (repPE<=-CmiNumPes() || repPE>=CmiNumPes()) {
440 #if ! CMK_BLUEGENE_CHARM
441     /*Treat out of bound values as errors. Helps detecting bugs*/
442     if (repPE==-CmiNumPes()) CmiPrintf("Invalid processor index in CCS request: are you trying to do a broadcast instead?");
443     else CmiPrintf("Invalid processor index in CCS request.");
444     CpvAccess(ccsReq)=hdr;
445     CcsSendReply(0,NULL); /*Send an empty reply to the possibly waiting client*/
446     return;
447 #endif
448   }
449
450   msg=CcsImpl_ccs2converse(hdr,reqData,&len);
451   if (repPE >= 0) {
452     /* The following %CmiNumPes() follows the assumption that in BigSim the mapping is round-robin */
453     //CmiPrintf("CCS message received for %d\n",repPE);
454     CmiSyncSendAndFree(repPE%CmiNumPes(),len,msg);
455   } else if (repPE == -1) {
456     /* Broadcast to all processors */
457     //CmiPrintf("CCS broadcast received\n");
458     CmiSyncSendAndFree(0,len,msg);
459   } else {
460     /* Multicast to -repPE processors, specified right at the beginning of reqData (as a list of pes) */
461     int firstPE = ChMessageInt(*(ChMessageInt_t*)reqData);
462     /* The following %CmiNumPes() follows the assumption that in BigSim the mapping is round-robin */
463     //CmiPrintf("CCS multicast received\n");
464     CmiSyncSendAndFree(firstPE%CmiNumPes(),len,msg);
465   }
466 }
467
468 /*
469 We have to run a CCS server socket here on
470 node 0.  To keep the speed impact minimal,
471 we only probe for new connections (with CcsServerCheck)
472 occasionally.  
473  */
474 #include <signal.h>
475 #include "ccs-server.c" /*Include implementation here in this case*/
476 #include "ccs-auth.c"
477
478 /*Check for ready Ccs messages:*/
479 void CcsServerCheck(void)
480 {
481   while (1==skt_select1(CcsServer_fd(),0)) {
482     CcsImplHeader hdr;
483     void *data;
484     /* printf("Got CCS connect...\n"); */
485     if (CcsServer_recvRequest(&hdr,&data))
486     {/*We got a network request*/
487       /* printf("Got CCS request...\n"); */
488       if (! check_stdio_header(&hdr)) {
489         CcsImpl_netRequest(&hdr,data);
490       }
491       free(data);
492     }
493   }
494 }
495
496 #endif /*NODE_0_IS_CONVHOST*/
497
498 int _isCcsHandlerIdx(int hIdx) {
499   if (hIdx==_ccsHandlerIdx) return 1;
500   if (hIdx==rep_fw_handler_idx) return 1;
501   return 0;
502 }
503
504 void CcsBuiltinsInit(char **argv);
505
506 CpvDeclare(int, cmiArgDebugFlag);
507 CpvDeclare(char *, displayArgument);
508 CpvDeclare(int, cpdSuspendStartup);
509
510 void CcsInit(char **argv)
511 {
512   CpvInitialize(CkHashtable_c, ccsTab);
513   CpvAccess(ccsTab) = CkCreateHashtable_string(sizeof(CcsHandlerRec),5);
514   CpvInitialize(CcsImplHeader *, ccsReq);
515   CpvAccess(ccsReq) = NULL;
516   _ccsHandlerIdx = CmiRegisterHandler((CmiHandler)req_fw_handler);
517 #if CMK_BLUEGENE_CHARM
518   CpvInitialize(int, _bgCcsHandlerIdx);
519   CpvAccess(_bgCcsHandlerIdx) = 0;
520   CpvInitialize(int, _bgCcsAck);
521   CpvAccess(_bgCcsAck) = 0;
522 #endif
523   CpvInitialize(int, cmiArgDebugFlag);
524   CpvInitialize(char *, displayArgument);
525   CpvInitialize(int, cpdSuspendStartup);
526   CpvAccess(cmiArgDebugFlag) = 0;
527   CpvAccess(displayArgument) = NULL;
528   CpvAccess(cpdSuspendStartup) = 0;
529   
530   CcsBuiltinsInit(argv);
531
532   rep_fw_handler_idx = CmiRegisterHandler((CmiHandler)rep_fw_handler);
533 #if NODE_0_IS_CONVHOST
534 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
535   print_fw_handler_idx = CmiRegisterHandler((CmiHandler)print_fw_handler);
536 #endif
537   {
538    int ccs_serverPort=0;
539    char *ccs_serverAuth=NULL;
540    
541    if (CmiGetArgFlagDesc(argv,"++server", "Create a CCS server port") | 
542       CmiGetArgIntDesc(argv,"++server-port",&ccs_serverPort, "Listen on this TCP/IP port number") |
543       CmiGetArgStringDesc(argv,"++server-auth",&ccs_serverAuth, "Use this CCS authentication file")) 
544     if (CmiMyPe()==0)
545     {/*Create and occasionally poll on a CCS server port*/
546       CcsServer_new(NULL,&ccs_serverPort,ccs_serverAuth);
547       CcdCallOnConditionKeep(CcdPERIODIC,(CcdVoidFn)CcsServerCheck,NULL);
548     }
549   }
550 #endif
551   /* if in parallel debug mode i.e ++cpd, freeze */
552   if (CmiGetArgFlagDesc(argv, "+cpd", "Used *only* in conjunction with parallel debugger"))
553   {
554      CpvAccess(cmiArgDebugFlag) = 1;
555      if (CmiGetArgStringDesc(argv, "+DebugDisplay",&(CpvAccess(displayArgument)), "X display for gdb used only in cpd mode"))
556      {
557         if (CpvAccess(displayArgument) == NULL)
558             CmiPrintf("WARNING> NULL parameter for +DebugDisplay\n***");
559      }
560      else if (CmiMyPe() == 0)
561      {
562             /* only one processor prints the warning */
563             CmiPrintf("WARNING> x term for gdb needs to be specified as +DebugDisplay by debugger\n***\n");
564      }
565
566      if (CmiGetArgFlagDesc(argv, "+DebugSuspend", "Suspend execution at beginning of program")) {
567        CpvAccess(cpdSuspendStartup) = 1;
568      }
569   }
570
571   CcsReleaseMessages();
572 }
573
574 #endif /*CMK_CCS_AVAILABLE*/
575