use test result for kill() to guard the code
[charm.git] / src / conv-ccs / ccs-builtins.C
1 /*****************************************************************************
2  * A few useful built-in CCS handlers.
3  *****************************************************************************/
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <errno.h>
8 #include <string.h>
9
10 #include "converse.h"
11 #include "ckhashtable.h"
12 #include "pup.h"
13 #include "pup_toNetwork.h"
14 #include "debug-charm.h"
15 #include "conv-ccs.h"
16 #include "sockRoutines.h"
17 #include "queueing.h"
18 #include "ccs-builtins.h"
19
20 #ifdef __MINGW_H
21 #include "process.h"
22 #endif
23
24 #if CMK_CCS_AVAILABLE
25
26 /**********************************************
27   "ccs_getinfo"-- takes no data
28     Return the number of parallel nodes, and
29       the number of processors per node as an array
30       of 4-byte big-endian ints.
31 */
32
33 static void ccs_getinfo(char *msg)
34 {
35   int nNode=CmiNumNodes();
36   int len=(1+nNode)*sizeof(ChMessageInt_t);
37   ChMessageInt_t *table=(ChMessageInt_t *)malloc(len);
38   int n;
39   table[0]=ChMessageInt_new(nNode);
40   for (n=0;n<nNode;n++)
41     table[1+n]=ChMessageInt_new(CmiNodeSize(n));
42   CcsSendReply(len,(const char *)table);
43   free(table);
44   CmiFree(msg);
45 }
46
47 /**********************************************
48   "ccs_killport"-- takes one 4-byte big-endian port number
49     Register a "client kill port".  When this program exits,
50     it will connect to this TCP port and write "die\n\0" it.
51 */
52
53 typedef struct killPortStruct{
54   skt_ip_t ip;
55   unsigned int port;
56   struct killPortStruct *next;
57 } killPortStruct;
58 /*Only 1 kill list per node-- no Cpv needed*/
59 static killPortStruct *killList=NULL;
60
61 static void ccs_killport(char *msg)
62 {
63   killPortStruct *oldList=killList;
64   int port=ChMessageInt(*(ChMessageInt_t *)(msg+CmiMsgHeaderSizeBytes));
65   skt_ip_t ip;
66   unsigned int connPort;
67   CcsCallerId(&ip,&connPort);
68   killList=(killPortStruct *)malloc(sizeof(killPortStruct));
69   killList->ip=ip;
70   killList->port=port;
71   killList->next=oldList;
72   CmiFree(msg);
73 }
74 /*Send any registered clients kill messages before we exit*/
75 static int noMoreErrors(int c,const char *m) {return -1;}
76 extern "C" void CcsImpl_kill(void)
77 {
78   skt_set_abort(noMoreErrors);
79   while (killList!=NULL)
80   {
81     SOCKET fd=skt_connect(killList->ip,killList->port,20);
82     if (fd!=INVALID_SOCKET) {
83       skt_sendN(fd,"die\n",strlen("die\n")+1);
84       skt_close(fd);
85     }
86     killList=killList->next;
87   }
88 }
89
90 /**********************************************
91   "ccs_killpe"-- kills the executing processor
92     Used for fault-tolerance testing: terminate the processor.
93 */
94
95 #include <signal.h>
96
97 static void ccs_killpe(char *msg) {
98 #if CMK_HAS_KILL
99   kill(getpid(), 9);
100 #else
101   CmiAbort("ccs_killpe() not supported!");
102 #endif
103 }
104
105 /*************************************************
106 List interface:
107    This lets different parts of a Charm++ program register 
108 "list retrieval functions", which expose some aspect of a
109 running program.  Example lists include: all readonly globals, 
110 messages waiting in a queue, or all extant array elements.
111
112   "ccs_list_len" (4-byte character count, null-terminated ASCII string)
113 Return the number of items currently in the list at the given path.
114
115   "ccs_list_items.bin" (4-byte start, 4-byte end+1,4-byte extra
116 data count n, n-byte extra data, 4-byte character count c, c-byte
117 ASCII request string [without NULL terminator])
118 Return the given items (from start to end) of the given queue, 
119 formatted as raw network binary data.
120
121   "ccs_list_items.fmt" [parameters as for .bin]
122 Return the given items, formatted as tagged network binary data.
123
124   "ccs_list_items.txt" [parameters as for .bin]
125 Return the given items, formatted as ASCII text.
126 */
127
128 static void CpdListBoundsCheck(CpdListAccessor *l,int &lo,int &hi)
129 {
130   if (l->checkBoundary()) {
131     int len=l->getLength();
132     if (lo<0) lo=0;
133     if (hi>len) hi=len;
134   }
135 }
136
137 typedef CkHashtableTslow<const char *,CpdListAccessor *> CpdListTable_t;
138 CpvStaticDeclare(CpdListTable_t *,cpdListTable);
139
140 /**
141   Return the list at this (null-terminated ASCII) path.
142 */
143 static CpdListAccessor *CpdListLookup(const char *path)
144 {
145   CpdListAccessor *acc=CpvAccess(cpdListTable)->get(path);
146   if (acc==NULL) {
147     CmiError("CpdListAccessor> Unrecognized list path '%s'\n",path);
148     return NULL;
149   }
150   return acc;
151 }
152
153 /**
154   Return a CpdListAccessor, given a network string containing the 
155   list path.  A network string is a big-endian 32-bit "length" 
156   field, followed by a null-terminated ASCII string of that length.
157 */
158 static CpdListAccessor *CpdListLookup(const ChMessageInt_t *lenAndPath)
159 {
160   static const int CpdListMaxLen=80;
161   int len=ChMessageInt(lenAndPath[0]);
162   const char *path=(const char *)(lenAndPath+1);
163   char pathBuf[CpdListMaxLen+1]; //Temporary null-termination buffer
164   if ((len<0) || (len>CpdListMaxLen)) {
165     CmiError("CpdListAccessor> Invalid list path length %d!\n",len);
166     return NULL; //Character count is invalid
167   }
168   strncpy(pathBuf,path,len);
169   pathBuf[len]=0; //Ensure string is null-terminated
170   return CpdListLookup(pathBuf);
171 }
172
173 //CCS External access routines:
174
175 //Get the length of the given list:
176 static void CpdList_ccs_list_len(char *msg)
177 {
178   const ChMessageInt_t *req=(const ChMessageInt_t *)(msg+CmiMsgHeaderSizeBytes);
179   CpdListAccessor *acc=CpdListLookup(req);
180   if (acc!=NULL) {
181     ChMessageInt_t reply=ChMessageInt_new(acc->getLength());
182     CcsSendReply(sizeof(reply),(void *)&reply);
183   }
184   CmiFree(msg);
185 }
186
187 //Read a list contents request header:
188 //  first item to send, 4-byte network integer
189 //  last item+1 to send, 4-byte network integer
190 //  extra data length, 4-byte network integer
191 //  extra data, list-defined bytes
192 //  list path length, 4-byte network integer (character count)
193 //  list path name, null-terminated ASCII
194 static CpdListAccessor *CpdListHeader_ccs_list_items(char *msg,
195              CpdListItemsRequest &h)
196 {
197   int msgLen=CmiSize((void *)msg)-CmiMsgHeaderSizeBytes;
198   CpdListAccessor *ret=NULL;
199   const ChMessageInt_t *req=(const ChMessageInt_t *)(msg+CmiMsgHeaderSizeBytes);
200   h.lo=ChMessageInt(req[0]); // first item to send
201   h.hi=ChMessageInt(req[1]); // last item to send+1
202   h.extraLen=ChMessageInt(req[2]); // extra data length
203   if (h.extraLen>=0 
204   && ((int)(3*sizeof(ChMessageInt_t)+h.extraLen))<msgLen) {
205     h.extra=(void *)(req+3);  // extra data
206     ret=CpdListLookup((ChMessageInt_t *)(h.extraLen+(char *)h.extra));
207     if (ret!=NULL) CpdListBoundsCheck(ret,h.lo,h.hi);
208   }
209   return ret;
210 }
211
212
213 // Pup this cpd list's items under this request.
214 static void pupCpd(PUP::er &p, CpdListAccessor *acc, CpdListItemsRequest &req)
215 {
216       p.syncComment(PUP::sync_begin_array,"CpdList");
217       acc->pup(p,req);
218       p.syncComment(PUP::sync_end_array);
219 }
220
221 static void CpdList_ccs_list_items_txt(char *msg)
222 {
223   CpdListItemsRequest req;
224   CpdListAccessor *acc=CpdListHeader_ccs_list_items(msg,req);
225   if(acc == NULL) CmiPrintf("ccs-builtins> Null Accessor--bad list name (txt)\n");
226   if (acc!=NULL) {
227     int bufLen;
228     { 
229       PUP::sizerText p; pupCpd(p,acc,req); bufLen=p.size(); 
230     }
231     char *buf=new char[bufLen];
232     { 
233       PUP::toText p(buf); pupCpd(p,acc,req);
234       if (p.size()!=bufLen)
235         CmiError("ERROR! Sizing/packing length mismatch for %s list pup function!\n",
236                 acc->getPath());
237     }
238     CcsSendReply(bufLen,(void *)buf);
239     delete[] buf;
240   }
241   CmiFree(msg);
242 }
243
244 static void CpdList_ccs_list_items_set(char *msg)
245 {
246   CpdListItemsRequest req;
247   CpdListAccessor *acc=CpdListHeader_ccs_list_items(msg,req);
248   if(acc == NULL) CmiPrintf("ccs-builtins> Null Accessor--bad list name (set)\n");
249   else {
250     PUP_toNetwork_unpack p(req.extra);
251     pupCpd(p,acc,req);
252     if (p.size()!=req.extraLen)
253         CmiPrintf("Size mismatch during ccs_list_items.set: client sent %d bytes, but %d bytes used!\n",
254                 req.extraLen,p.size());
255   }
256   CmiFree(msg);
257 }
258
259 /** gather information about the machine we're currently running on */
260 void CpdMachineArchitecture(char *msg) {
261   char reply[6]; // where we store our reply
262   // decide if we are 32 bit (1) or 64 bit (2)
263   reply[0] = 0;
264   if (sizeof(char*) == 4) reply[0] = 1;
265   else if (sizeof(char*) == 8) reply[0] = 2;
266   // decide if we are little endian (1) or big endian (2)
267   reply[1] = 0;
268   int value = 1;
269   char firstByte = *((char*)&value);
270   if (firstByte == 1) reply[1] = 1;
271   else reply[1] = 2;
272   // get the size of an "int"
273   reply[2] = sizeof(int);
274   // get the size of an "long"
275   reply[3] = sizeof(long);
276   // get the size of an "long long"
277   reply[4] = sizeof(long long);
278   // get the size of an "bool"
279   reply[5] = sizeof(bool);
280   CcsSendReply(6, (void*)reply);
281   CmiFree(msg);
282 }
283
284 static void CpdList_ccs_list_items_fmt(char *msg)
285 {
286   CpdListItemsRequest req;
287   CpdListAccessor *acc=CpdListHeader_ccs_list_items(msg,req);
288   if (acc!=NULL) {
289     int bufLen;
290     { 
291       PUP_toNetwork_sizer ps;
292       PUP_fmt p(ps); 
293       pupCpd(p,acc,req);
294       bufLen=ps.size(); 
295     }
296     char *buf=new char[bufLen];
297     { 
298       PUP_toNetwork_pack pp(buf); 
299       PUP_fmt p(pp);
300       pupCpd(p,acc,req);
301       if (pp.size()!=bufLen)
302         CmiError("ERROR! Sizing/packing length mismatch for %s list pup function (%d sizing, %d packing)\n",
303                 acc->getPath(),bufLen,pp.size());
304     }
305     CcsSendReply(bufLen,(void *)buf);
306     delete[] buf;
307   }
308   CmiFree(msg);
309 }
310
311
312
313
314 //Introspection object-- extract a list of CpdLists!
315 class CpdList_introspect : public CpdListAccessor {
316   CpdListTable_t *tab;
317 public:
318   CpdList_introspect(CpdListTable_t *tab_) :tab(tab_) { }
319   virtual const char *getPath(void) const { return "converse/lists";}
320   virtual size_t getLength(void) const {
321     size_t len=0;
322     CkHashtableIterator *it=tab->iterator();
323     while (NULL!=it->next()) len++;
324     delete it;
325     return len;
326   }
327   virtual void pup(PUP::er &p,CpdListItemsRequest &req) {
328     CkHashtableIterator *it=tab->iterator();
329     void *objp;
330     int curObj=0;
331     while (NULL!=(objp=it->next())) {
332       if (curObj>=req.lo && curObj<req.hi) {
333         CpdListAccessor *acc=*(CpdListAccessor **)objp;
334         char *pathName=(char *)acc->getPath();
335         beginItem(p,curObj);
336         p.comment("name");
337         p(pathName,strlen(pathName));
338       }
339       curObj++;
340     }
341   }
342 };
343
344
345
346
347 #endif /*CMK_CCS_AVAILABLE*/
348 /*We have to include these virtual functions, even when CCS is
349 disabled, to avoid bizarre link-time errors.*/
350
351 CpdListAccessor::~CpdListAccessor() { }
352 CpdSimpleListAccessor::~CpdSimpleListAccessor() { }
353 const char *CpdSimpleListAccessor::getPath(void) const {return path;}
354 size_t CpdSimpleListAccessor::getLength(void) const {return length;}
355 void CpdSimpleListAccessor::pup(PUP::er &p,CpdListItemsRequest &req) 
356 {
357         for (int i=req.lo;i<req.hi;i++) {
358                 beginItem(p,i);
359                 (*pfn)(p,i);
360         }
361 }
362
363 static void CpdListBeginItem_impl(PUP::er &p,int itemNo)
364 {
365         p.syncComment(PUP::sync_item);
366 }
367
368 extern "C" void CpdListBeginItem(pup_er p,int itemNo)
369 {
370   CpdListBeginItem_impl(*(PUP::er *)p,itemNo);
371 }
372
373 void CpdListAccessor::beginItem(PUP::er &p,int itemNo)
374 {
375   CpdListBeginItem_impl(p,itemNo);
376 }
377
378 // C++ and C client API
379 void CpdListRegister(CpdListAccessor *acc)
380 #if CMK_CCS_AVAILABLE
381 {
382   CpvAccess(cpdListTable)->put(acc->getPath())=acc;
383 }
384 #else
385 { }
386 #endif
387
388 extern "C" void CpdListRegister_c(const char *path,
389             CpdListLengthFn_c len,void *lenParam,
390             CpdListItemsFn_c items,void *itemsParam,int checkBoundary)
391 #if CMK_CCS_AVAILABLE
392 {
393   CpdListRegister(new CpdListAccessor_c(path,
394              len,lenParam,items,itemsParam,checkBoundary!=0?true:false));
395 }
396 #else
397 { }
398 #endif
399
400 #if CMK_CCS_AVAILABLE
401
402
403 // Initialization       
404
405 static void CpdListInit(void) {
406   CpvInitialize(CpdListTable_t *,cpdListTable);
407   CpvAccess(cpdListTable)=new CpdListTable_t(31,0.5,
408               CkHashFunction_string,CkHashCompare_string);
409   CpdListRegister(new CpdList_introspect(CpvAccess(cpdListTable)));
410
411   CcsRegisterHandler("ccs_list_len",(CmiHandler)CpdList_ccs_list_len);
412   CcsRegisterHandler("ccs_list_items.txt",(CmiHandler)CpdList_ccs_list_items_txt);
413   CcsRegisterHandler("ccs_list_items.fmt",(CmiHandler)CpdList_ccs_list_items_fmt);
414   CcsRegisterHandler("ccs_list_items.set",(CmiHandler)CpdList_ccs_list_items_set);
415   CcsRegisterHandler("ccs_machine_architecture",(CmiHandler)CpdMachineArchitecture);
416 }
417
418 #if CMK_WEB_MODE
419 /******************************************************
420 Web performance monitoring interface:
421         Clients will register for performance data with 
422 processor 0 by calling the "perf_monitor" CCS request.  
423 Every WEB_INTERVAL (few seconds), this code
424 calls all registered web performance functions on all processors.  
425 The resulting integers are sent back to the client as a 
426 CCS reply.  
427
428 The current reply format is ASCII and rather nasty:
429 it's the string "perf" followed by space-separated list
430 of the performance functions for each processor.  By default,
431 only two performance functions are registered: the current 
432 processor utilization, in percent; and the current queue length.
433
434 The actual call sequence is:
435 CCS Client->CWebHandler->...  (processor 0)
436   ...->CWeb_Collect->... (all processors)
437 ...->CWeb_Reduce->CWeb_Deliver (processor 0 again)
438 */
439
440 #if 0
441 #  define WEBDEBUG(x) CmiPrintf x
442 #else
443 #  define WEBDEBUG(x) /*empty*/
444 #endif
445
446 #define WEB_INTERVAL 1000 /*Time, in milliseconds, between performance snapshots*/
447 #define MAXFNS 20 /*Largest number of performance functions to expect*/
448
449 typedef struct {
450         char hdr[CmiMsgHeaderSizeBytes];
451         int fromPE;/*Source processor*/
452         int perfData[MAXFNS];/*Performance numbers*/
453 } CWeb_CollectedData;
454
455 /*This needs to be made into a list of registered clients*/
456 static int hasApplet=0;
457 static CcsDelayedReply appletReply;
458
459 typedef int (*CWebFunction)(void);
460 static CWebFunction CWebPerformanceFunctionArray[MAXFNS];
461 static int CWebNoOfFns;
462 static int CWeb_ReduceIndex;
463 static int CWeb_CollectIndex;
464
465 /*Deliver the reduced web performance data to the waiting client:
466 */
467 static int collectedCount;
468 static CWeb_CollectedData **collectedValues;
469
470 static void CWeb_Deliver(void)
471 {
472   int i,j;
473
474   if (hasApplet) {
475     WEBDEBUG(("CWeb_Deliver to applet\n"));
476     /*Send the performance data off to the applet*/
477     char *reply=(char *)malloc(6+14*CmiNumPes()*CWebNoOfFns);
478     sprintf(reply,"perf");
479   
480     for(i=0; i<CmiNumPes(); i++){
481       for (j=0;j<CWebNoOfFns;j++)
482       {
483         char buf[20];
484         sprintf(buf," %d",collectedValues[i]->perfData[j]);
485         strcat(reply,buf);
486       }
487     }
488     CcsSendDelayedReply(appletReply,strlen(reply) + 1, reply);
489     free(reply);
490     hasApplet=0;
491   }
492   else
493     WEBDEBUG(("CWeb_Deliver (NO APPLET)\n"));
494   
495   /* Free saved performance data */
496   for(i = 0; i < CmiNumPes(); i++){
497     CmiFree(collectedValues[i]);
498     collectedValues[i] = 0;
499   }
500   collectedCount = 0;
501 }
502
503 /*On PE 0, this handler accumulates all the performace data
504 */
505 static void CWeb_Reduce(void *msg){
506   CWeb_CollectedData *cur,*prev;
507   int src;
508   if(CmiMyPe() != 0){
509     CmiAbort("CWeb performance data sent to wrong processor...\n");
510   }
511   WEBDEBUG(("CWeb_Reduce"));
512   cur=(CWeb_CollectedData *)msg;
513   src=cur->fromPE;
514   prev = collectedValues[src]; /* Previous value, ideally 0 */
515   collectedValues[src] = cur;
516   if(prev == 0) collectedCount++;
517   else CmiFree(prev); /*<- caused by out-of-order perf. data delivery*/
518
519   if(collectedCount == CmiNumPes()){
520     CWeb_Deliver();
521   }
522 }
523
524 /*On each PE, this handler collects the performance data
525 and sends it to PE 0.
526 */
527 static void CWeb_Collect(void)
528 {
529   CWeb_CollectedData *msg;
530   int i;
531
532   WEBDEBUG(("CWeb_Collect on %d\n",CmiMyPe()));
533   msg = (CWeb_CollectedData *)CmiAlloc(sizeof(CWeb_CollectedData));
534   msg->fromPE = CmiMyPe();
535   
536   /* Evaluate each performance function*/
537   for(i = 0; i < CWebNoOfFns; i++)
538     msg->perfData[i] = CWebPerformanceFunctionArray[i] ();
539
540   /* Send result off to node 0 */  
541   CmiSetHandler(msg, CWeb_ReduceIndex);
542   CmiSyncSendAndFree(0, sizeof(CWeb_CollectedData), msg);
543
544   /* Re-call this function after a delay */
545   CcdCallFnAfter((CcdVoidFn)CWeb_Collect, 0, WEB_INTERVAL);
546 }
547
548 extern "C" void CWebPerformanceRegisterFunction(CWebFunction fn)
549 {
550   if (CmiMyRank()!=0) return; /* Should only register from rank 0 */
551   if (CWebNoOfFns>=MAXFNS) CmiAbort("Registered too many CWebPerformance functions!");
552   CWebPerformanceFunctionArray[CWebNoOfFns] = fn;
553   CWebNoOfFns++;
554 }
555
556 /*This is called on PE 0 by clients that wish
557 to receive performance data.
558 */
559 static void CWebHandler(void){
560   if(CcsIsRemoteRequest()) {
561     static int startedCollection=0;
562     
563     WEBDEBUG(("CWebHandler request on %d\n",CmiMyPe()));    
564     hasApplet=1;
565     appletReply=CcsDelayReply();
566     
567     if(startedCollection == 0){
568       WEBDEBUG(("Starting data collection on every processor\n"));    
569       int i;
570       startedCollection=1;
571       collectedCount=0;
572       collectedValues = (CWeb_CollectedData **)malloc(sizeof(void *) * CmiNumPes());
573       for(i = 0; i < CmiNumPes(); i++)
574         collectedValues[i] = 0;
575       
576       /*Start collecting data on each processor*/
577       for(i = 0; i < CmiNumPes(); i++){
578         char *msg = (char *)CmiAlloc(CmiMsgHeaderSizeBytes);
579         CmiSetHandler(msg, CWeb_CollectIndex);
580         CmiSyncSendAndFree(i, CmiMsgHeaderSizeBytes,msg);
581       }
582     }
583   }
584 }
585
586 /** This "usage" section keeps track of percent of wall clock time
587 spent actually processing messages on each processor.   
588 It's a simple performance measure collected by the CWeb framework.
589 **/
590 struct CWebModeStats {
591 public:
592         double beginTime; ///< Start of last collection interval
593         double startTime; ///< Start of last busy time
594         double usedTime; ///< Total busy time in last collection interval
595         int PROCESSING; ///< If 1, processor is busy
596 };
597 CpvStaticDeclare(CWebModeStats *,cwebStats);
598
599 /* Called to begin a collection interval
600 */
601 static void usageReset(CWebModeStats *stats,double curWallTime)
602 {
603    stats->beginTime=curWallTime;
604    stats->usedTime = 0.;
605 }
606
607 /* Called when processor becomes busy
608 */
609 static void usageStart(CWebModeStats *stats,double curWallTime)
610 {
611    stats->startTime  = curWallTime;
612    stats->PROCESSING = 1;
613 }
614
615 /* Called when processor becomes idle
616 */
617 static void usageStop(CWebModeStats *stats,double curWallTime)
618 {
619    stats->usedTime   += curWallTime - stats->startTime;
620    stats->PROCESSING = 0;
621 }
622
623 /* Call this when the program is started
624  -> Whenever traceModuleInit would be called
625  -> -> see conv-core/convcore.c
626 */
627 static void initUsage()
628 {
629    CpvInitialize(CWebModeStats *, cwebStats);
630    CWebModeStats *stats=new CWebModeStats;
631    CpvAccess(cwebStats)=stats;
632    usageReset(stats,CmiWallTimer());
633    usageStart(stats,CmiWallTimer());
634    CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_BUSY,(CcdVoidFn)usageStart,stats);
635    CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE,(CcdVoidFn)usageStop,stats);    
636 }
637
638 static int getUsage(void)
639 {
640    int usage = 0;
641    double time      = CmiWallTimer();
642    CWebModeStats *stats=CpvAccess(cwebStats);
643    double totalTime = time - stats->beginTime;
644
645    if(stats->PROCESSING)
646    { /* Lock in current CPU usage */
647       usageStop(stats,time); usageStart(stats,time);
648    }
649    if(totalTime > 0.)
650       usage = (int)(0.5 + 100 *stats->usedTime/totalTime);
651    usageReset(stats,time);
652
653    return usage;
654 }
655
656 static int getSchedQlen(void)
657 {
658   return(CqsLength((Queue)CpvAccess(CsdSchedQueue)));
659 }
660
661 #endif /*CMK_WEB_MODE*/
662
663 #if ! CMK_WEB_MODE
664 static void CWeb_Invalid(void)
665 {
666   CmiAbort("Invalid web mode handler invoked!\n");
667 }
668 #endif
669
670 void CWebInit(void)
671 {
672 #if CMK_WEB_MODE
673   CcsRegisterHandler("perf_monitor", (CmiHandler)CWebHandler);
674   
675   CWeb_CollectIndex=CmiRegisterHandler((CmiHandler)CWeb_Collect);
676   CWeb_ReduceIndex=CmiRegisterHandler((CmiHandler)CWeb_Reduce);
677   
678   initUsage();
679   CWebPerformanceRegisterFunction(getUsage);
680   CWebPerformanceRegisterFunction(getSchedQlen);
681 #else
682   /* always maintain the consistent CmiHandler table */
683   /* which is good for heterogeneous clusters */
684   CmiRegisterHandler((CmiHandler)CWeb_Invalid);
685   CmiRegisterHandler((CmiHandler)CWeb_Invalid);
686 #endif
687 }
688
689
690 extern "C" void CcsBuiltinsInit(char **argv)
691 {
692   CcsRegisterHandler("ccs_getinfo",(CmiHandler)ccs_getinfo);
693   CcsRegisterHandler("ccs_killport",(CmiHandler)ccs_killport);
694   CcsRegisterHandler("ccs_killpe",(CmiHandler)ccs_killpe);
695   CWebInit();
696   CpdListInit();
697 }
698
699
700 #endif /*CMK_CCS_AVAILABLE*/
701
702 void PUP_fmt::fieldHeader(typeCode_t typeCode,int nItems) {
703     // Compute and write intro byte:
704     lengthLen_t ll;
705     if (nItems==1) ll=lengthLen_single;
706     else if (nItems<256) ll=lengthLen_byte;
707     else ll=lengthLen_int;
708     // CmiPrintf("Intro byte: l=%d t=%d\n",(int)ll,(int)typeCode);
709     byte intro=(((int)ll)<<4)+(int)typeCode;
710     p(intro);
711     // Compute and write length:
712     switch(ll) {
713     case lengthLen_single: break; // Single item
714     case lengthLen_byte: {
715         byte l=nItems;
716         p(l);
717         } break;
718     case lengthLen_int: {
719         p(nItems); 
720         } break; 
721     };
722 }
723
724 void PUP_fmt::comment(const char *message) {
725         int nItems=strlen(message);
726         fieldHeader(typeCode_comment,nItems);
727         p((char *)message,nItems);
728 }
729 void PUP_fmt::synchronize(unsigned int m) {
730         fieldHeader(typeCode_sync,1);
731         p(m);
732 }
733 void PUP_fmt::bytes(void *ptr,int n,size_t itemSize,PUP::dataType t) {
734         switch(t) {
735         case PUP::Tchar:
736         case PUP::Tuchar:
737         case PUP::Tbyte:
738                 fieldHeader(typeCode_byte,n);
739                 p.bytes(ptr,n,itemSize,t);
740                 break;
741         case PUP::Tshort: case PUP::Tint:
742         case PUP::Tushort: case PUP::Tuint:
743         case PUP::Tbool:
744                 fieldHeader(typeCode_int,n);
745                 p.bytes(ptr,n,itemSize,t);
746                 break;
747         // treat "long" and "pointer" as 8-bytes, in conformity with pup_toNetwork.C
748         case PUP::Tlong: case PUP::Tlonglong:
749         case PUP::Tulong: case PUP::Tulonglong:
750                 fieldHeader(typeCode_long,n);
751                 p.bytes(ptr,n,itemSize,t);
752                 break;
753         case PUP::Tfloat:
754                 fieldHeader(typeCode_float,n);
755                 p.bytes(ptr,n,itemSize,t);
756                 break;
757         case PUP::Tdouble: case PUP::Tlongdouble:
758                 fieldHeader(typeCode_double,n);
759                 p.bytes(ptr,n,itemSize,t);
760                 break;
761     case PUP::Tpointer:
762         fieldHeader(typeCode_pointer,n);
763         p.bytes(ptr,n,itemSize,t);
764         break;
765         default: CmiAbort("Unrecognized type code in PUP_fmt::bytes");
766         };
767 }
768
769