Made charm++ to compile and run with Solaris 2.6.
[charm.git] / src / conv-core / convcore.c
1 /***************************************************************************
2  * RCS INFORMATION:
3  *
4  *      $RCSfile$
5  *      $Author$        $Locker$                $State$
6  *      $Revision$      $Date$
7  *
8  ***************************************************************************
9  * DESCRIPTION:
10  *
11  ***************************************************************************
12  * REVISION HISTORY:
13  *
14  ***************************************************************************/
15 static char ident[] = "@(#)$Header$";
16
17 #include <stdio.h>
18 #include "converse.h"
19 #include <errno.h>
20
21 #if CMK_WHEN_PROCESSOR_IDLE_USLEEP
22 #include <sys/types.h>
23 #include <sys/time.h>
24 #endif
25
26 #if CMK_TIMER_USE_TIMES
27 #include <sys/times.h>
28 #include <limits.h>
29 #include <unistd.h>
30 #endif
31
32 #if CMK_TIMER_USE_GETRUSAGE
33 #include <sys/time.h>
34 #include <sys/resource.h>
35 #endif
36
37
38 /*****************************************************************************
39  *
40  * Unix Stub Functions
41  *
42  ****************************************************************************/
43
44 #if CMK_STRERROR_USE_SYS_ERRLIST
45 extern char *sys_errlist[];
46 char *strerror(i) int i; { return sys_errlist[i]; }
47 #endif
48
49 #if CMK_SIGHOLD_USE_SIGMASK
50 #include <signal.h>
51 int sighold(sig) int sig;
52 { if (sigblock(sigmask(sig)) < 0) return -1;
53   else return 0; }
54 int sigrelse(sig) int sig;
55 { if (sigsetmask(sigblock(0)&(~sigmask(sig))) < 0) return -1;
56   else return 0; }
57 #endif
58
59 #define MAX_HANDLERS 512
60
61 void  *CmiGetNonLocal();
62 void   CmiNotifyIdle();
63
64 CpvDeclare(int, disable_sys_msgs);
65 CpvExtern(int,    CcdNumChecks) ;
66 CpvDeclare(void*, CsdSchedQueue);
67 CpvDeclare(int,   CsdStopFlag);
68
69
70 /*****************************************************************************
71  *
72  * Some of the modules use this in their argument parsing.
73  *
74  *****************************************************************************/
75
76 static char *DeleteArg(argv)
77   char **argv;
78 {
79   char *res = argv[0];
80   if (res==0) { CmiError("Bad arglist."); exit(1); }
81   while (*argv) { argv[0]=argv[1]; argv++; }
82   return res;
83 }
84
85
86 /**
87  * Global variable for Trace in converse (moved from charm)
88  */
89
90 CpvDeclare(int, CtrRecdTraceMsg);
91 CpvDeclare(int, CtrLogBufSize);
92
93 /*****************************************************************************
94  *
95  * Statistics: currently, the following statistics are not updated by converse.
96  *
97  *****************************************************************************/
98
99 CpvDeclare(int, CstatsMaxChareQueueLength);
100 CpvDeclare(int, CstatsMaxForChareQueueLength);
101 CpvDeclare(int, CstatsMaxFixedChareQueueLength);
102 CpvStaticDeclare(int, CstatPrintQueueStatsFlag);
103 CpvStaticDeclare(int, CstatPrintMemStatsFlag);
104
105 void CstatsInit(argv)
106 char **argv;
107 {
108   int argc;
109   char **origArgv = argv;
110
111   CpvInitialize(int, CtrRecdTraceMsg);
112   CpvInitialize(int, CtrLogBufSize);
113   CpvInitialize(int, CstatsMaxChareQueueLength);
114   CpvInitialize(int, CstatsMaxForChareQueueLength);
115   CpvInitialize(int, CstatsMaxFixedChareQueueLength);
116   CpvInitialize(int, CstatPrintQueueStatsFlag);
117   CpvInitialize(int, CstatPrintMemStatsFlag);
118
119   CpvAccess(CtrLogBufSize) = 10000;
120   CpvAccess(CstatsMaxChareQueueLength) = 0;
121   CpvAccess(CstatsMaxForChareQueueLength) = 0;
122   CpvAccess(CstatsMaxFixedChareQueueLength) = 0;
123
124   while (*argv) {
125     if (strcmp(*argv, "+mems") == 0) {
126       CpvAccess(CstatPrintMemStatsFlag)=1;
127       DeleteArg(argv);
128     } else
129     if (strcmp(*argv, "+qs") == 0) {
130       CpvAccess(CstatPrintQueueStatsFlag)=1;
131       DeleteArg(argv);
132     } else if (strcmp(*argv, "+logsize") == 0) {
133       int logsize;
134       DeleteArg(argv);
135       sscanf(*argv, "%d", &logsize);
136       CpvAccess(CtrLogBufSize) = logsize;
137       DeleteArg(argv);
138     } else
139     argv++;
140   }
141
142   argc = 0; argv=origArgv;
143   for(argc=0;argv[argc];argc++);
144   traceModuleInit(&argc, argv);
145   log_init();
146 }
147
148 int CstatMemory(i)
149 int i;
150 {
151   return 0;
152 }
153
154 int CstatPrintQueueStats()
155 {
156   return CpvAccess(CstatPrintQueueStatsFlag);
157 }
158
159 int CstatPrintMemStats()
160 {
161   return CpvAccess(CstatPrintMemStatsFlag);
162 }
163
164 /*****************************************************************************
165  *
166  * Cmi handler registration
167  *
168  *****************************************************************************/
169
170 CpvDeclare(CmiHandler*, CmiHandlerTable);
171 CpvStaticDeclare(int  , CmiHandlerCount);
172 CpvStaticDeclare(int  , CmiHandlerLocal);
173 CpvStaticDeclare(int  , CmiHandlerGlobal);
174 CpvStaticDeclare(int  , CmiHandlerMax);
175
176 void CmiNumberHandler(n, h)
177 int n; CmiHandler h;
178 {
179   CmiHandler *tab;
180   int         max = CpvAccess(CmiHandlerMax);
181
182   tab = CpvAccess(CmiHandlerTable);
183   if (n >= max) {
184     int newmax = ((n<<1)+10);
185     int bytes = max*sizeof(CmiHandler);
186     int newbytes = newmax*sizeof(CmiHandler);
187     CmiHandler *new = (CmiHandler*)CmiAlloc(newbytes);
188     memcpy(new, tab, bytes);
189     memset(((char *)new)+bytes, 0, (newbytes-bytes));
190     free(tab); tab=new;
191     CpvAccess(CmiHandlerTable) = tab;
192     CpvAccess(CmiHandlerMax) = newmax;
193   }
194   tab[n] = h;
195 }
196
197 int CmiRegisterHandler(h)
198 CmiHandler h;
199 {
200   int Count = CpvAccess(CmiHandlerCount);
201   CmiNumberHandler(Count, h);
202   CpvAccess(CmiHandlerCount) = Count+3;
203   return Count;
204 }
205
206 int CmiRegisterHandlerLocal(h)
207 CmiHandler h;
208 {
209   int Local = CpvAccess(CmiHandlerLocal);
210   CmiNumberHandler(Local, h);
211   CpvAccess(CmiHandlerLocal) = Local+3;
212   return Local;
213 }
214
215 int CmiRegisterHandlerGlobal(h)
216 CmiHandler h;
217 {
218   int Global = CpvAccess(CmiHandlerGlobal);
219   if (CmiMyPe()!=0) 
220     CmiError("CmiRegisterHandlerGlobal must only be called on PE 0.\n");
221   CmiNumberHandler(Global, h);
222   CpvAccess(CmiHandlerGlobal) = Global+3;
223   return Global;
224 }
225
226 static void CmiHandlerInit()
227 {
228   CpvInitialize(CmiHandler *, CmiHandlerTable);
229   CpvInitialize(int         , CmiHandlerCount);
230   CpvInitialize(int         , CmiHandlerLocal);
231   CpvInitialize(int         , CmiHandlerGlobal);
232   CpvInitialize(int         , CmiHandlerMax);
233   CpvAccess(CmiHandlerCount)  = 0;
234   CpvAccess(CmiHandlerLocal)  = 1;
235   CpvAccess(CmiHandlerGlobal) = 2;
236   CpvAccess(CmiHandlerMax) = 100;
237   CpvAccess(CmiHandlerTable) = (CmiHandler *)malloc(100*sizeof(CmiHandler)) ;
238 }
239
240
241 /******************************************************************************
242  *
243  * CmiTimer
244  *
245  * Here are two possible implementations of CmiTimer.  Some machines don't
246  * select either, and define the timer in machine.c instead.
247  *
248  *****************************************************************************/
249
250 #if CMK_TIMER_USE_TIMES
251
252 static double  clocktick;
253 static int     inittime_wallclock;
254 static int     inittime_virtual;
255
256 void CmiTimerInit()
257 {
258   struct tms temp;
259   inittime_wallclock = times(&temp);
260   inittime_virtual = temp.tms_utime + temp.tms_stime;
261   clocktick = 1.0 / (sysconf(_SC_CLK_TCK));
262 }
263
264 double CmiWallTimer()
265 {
266   struct tms temp;
267   double currenttime;
268   int now;
269
270   now = times(&temp);
271   currenttime = (now - inittime_wallclock) * clocktick;
272   return (currenttime);
273 }
274
275 double CmiCpuTimer()
276 {
277   struct tms temp;
278   double currenttime;
279   int now;
280
281   times(&temp);
282   now = temp.tms_stime + temp.tms_utime;
283   currenttime = (now - inittime_virtual) * clocktick;
284   return (currenttime);
285 }
286
287 double CmiTimer()
288 {
289   return CmiCpuTimer();
290 }
291
292 #endif
293
294 #if CMK_TIMER_USE_GETRUSAGE
295
296 static double inittime_wallclock;
297 static double inittime_virtual;
298
299 void CmiTimerInit()
300 {
301   struct timeval tv;
302   struct rusage ru;
303   gettimeofday(&tv,0);
304   inittime_wallclock = (tv.tv_sec * 1.0) + (tv.tv_usec*0.000001);
305   getrusage(0, &ru); 
306   inittime_virtual =
307     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
308     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
309 }
310
311 double CmiCpuTimer()
312 {
313   struct rusage ru;
314   double currenttime;
315
316   getrusage(0, &ru);
317   currenttime =
318     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
319     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
320   return currenttime - inittime_virtual;
321 }
322
323 double CmiWallTimer()
324 {
325   struct timeval tv;
326   double currenttime;
327
328   gettimeofday(&tv,0);
329   currenttime = (tv.tv_sec * 1.0) + (tv.tv_usec * 0.000001);
330   return currenttime - inittime_wallclock;
331 }
332
333 double CmiTimer()
334 {
335   return CmiCpuTimer();
336 }
337
338 #endif
339
340
341 /******************************************************************************
342  *
343  * CmiEnableAsyncIO
344  *
345  * The net and tcp versions use a bunch of unix processes talking to each
346  * other via file descriptors.  We need for a signal SIGIO to be generated
347  * each time a message arrives, making it possible to write a signal
348  * handler to handle the messages.  The vast majority of unixes can,
349  * in fact, do this.  However, there isn't any standard for how this is
350  * supposed to be done, so each version of UNIX has a different set of
351  * calls to turn this signal on.  So, there is like one version here for
352  * every major brand of UNIX.
353  *
354  *****************************************************************************/
355
356 #if CMK_ASYNC_USE_FIOASYNC_AND_FIOSETOWN
357 #include <sys/filio.h>
358 void CmiEnableAsyncIO(fd)
359 int fd;
360 {
361   int pid = getpid();
362   int async = 1;
363   if ( ioctl(fd, FIOSETOWN, &pid) < 0  ) {
364     CmiError("setting socket owner: %s\n", strerror(errno)) ;
365     exit(1);
366   }
367   if ( ioctl(fd, FIOASYNC, &async) < 0 ) {
368     CmiError("setting socket async: %s\n", strerror(errno)) ;
369     exit(1);
370   }
371 }
372 #endif
373
374 #if CMK_ASYNC_USE_FIOASYNC_AND_SIOCSPGRP
375 #include <sys/filio.h>
376 void CmiEnableAsyncIO(fd)
377 int fd;
378 {
379   int pid = -getpid();
380   int async = 1;
381   if ( ioctl(fd, SIOCSPGRP, &pid) < 0  ) {
382     CmiError("setting socket owner: %s\n", strerror(errno)) ;
383     exit(1);
384   }
385   if ( ioctl(fd, FIOASYNC, &async) < 0 ) {
386     CmiError("setting socket async: %s\n", strerror(errno)) ;
387     exit(1);
388   }
389 }
390 #endif
391
392 #if CMK_ASYNC_USE_FIOSSAIOSTAT_AND_FIOSSAIOOWN
393 #include <sys/ioctl.h>
394 void CmiEnableAsyncIO(fd)
395 int fd;
396 {
397   int pid = getpid();
398   int async = 1;
399   if ( ioctl(fd, FIOSSAIOOWN, &pid) < 0  ) {
400     CmiError("setting socket owner: %s\n", strerror(errno)) ;
401     exit(1);
402   }
403   if ( ioctl(fd, FIOSSAIOSTAT, &async) < 0 ) {
404     CmiError("setting socket async: %s\n", strerror(errno)) ;
405     exit(1);
406   }
407 }
408 #endif
409
410 #if CMK_ASYNC_USE_F_SETFL_AND_F_SETOWN
411 #include <fcntl.h>
412 void CmiEnableAsyncIO(fd)
413 int fd;
414 {
415   if ( fcntl(fd, F_SETOWN, getpid()) < 0 ) {
416     CmiError("setting socket owner: %s\n", strerror(errno)) ;
417     exit(1);
418   }
419   if ( fcntl(fd, F_SETFL, FASYNC) < 0 ) {
420     CmiError("setting socket async: %s\n", strerror(errno)) ;
421     exit(1);
422   }
423 }
424 #endif
425
426 #if CMK_SIGNAL_USE_SIGACTION
427 #include <signal.h>
428 void CmiSignal(sig1, sig2, sig3, handler)
429 int sig1, sig2, sig3;
430 void (*handler)();
431 {
432   struct sigaction in, out ;
433   in.sa_handler = handler;
434   sigemptyset(&in.sa_mask);
435   if (sig1) sigaddset(&in.sa_mask, sig1);
436   if (sig2) sigaddset(&in.sa_mask, sig2);
437   if (sig3) sigaddset(&in.sa_mask, sig3);
438   in.sa_flags = 0;
439   if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
440   if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
441   if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
442 }
443 #endif
444
445 #if CMK_SIGNAL_USE_SIGACTION_WITH_RESTART
446 #include <signal.h>
447 void CmiSignal(sig1, sig2, sig3, handler)
448 int sig1, sig2, sig3;
449 void (*handler)();
450 {
451   struct sigaction in, out ;
452   in.sa_handler = handler;
453   sigemptyset(&in.sa_mask);
454   if (sig1) sigaddset(&in.sa_mask, sig1);
455   if (sig2) sigaddset(&in.sa_mask, sig2);
456   if (sig3) sigaddset(&in.sa_mask, sig3);
457   in.sa_flags = SA_RESTART;
458   if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
459   if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
460   if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
461 }
462 #endif
463
464
465 /*****************************************************************************
466  *
467  * The following is the CsdScheduler function.  A common
468  * implementation is provided below.  The machine layer can provide an
469  * alternate implementation if it so desires.
470  *
471  * void CmiDeliversInit()
472  *
473  *      - CmiInit promises to call this before calling CmiDeliverMsgs
474  *        or any of the other functions in this section.
475  *
476  * int CmiDeliverMsgs(int maxmsgs)
477  *
478  *      - CmiDeliverMsgs will retrieve up to maxmsgs that were transmitted
479  *        with the Cmi, and will invoke their handlers.  It does not wait
480  *        if no message is unavailable.  Instead, it returns the quantity
481  *        (maxmsgs-delivered), where delivered is the number of messages it
482  *        delivered.
483  *
484  * void CmiDeliverSpecificMsg(int handlerno)
485  *
486  *      - Waits for a message with the specified handler to show up, then
487  *        invokes the message's handler.  Note that unlike CmiDeliverMsgs,
488  *        This function _does_ wait.
489  *
490  * void CmiGrabBuffer(void **bufptrptr)
491  *
492  *      - When CmiDeliverMsgs or CmiDeliverSpecificMsgs calls a handler,
493  *        the handler receives a pointer to a buffer containing the message.
494  *        The buffer does not belong to the handler, eg, the handler may not
495  *        free the buffer.  Instead, the buffer will be automatically reused
496  *        or freed as soon as the handler returns.  If the handler wishes to
497  *        keep a copy of the data after the handler returns, it may do so by
498  *        calling CmiGrabBuffer and passing it a pointer to a variable which
499  *        in turn contains a pointer to the system buffer.  The variable will
500  *        be updated to contain a pointer to a handler-owned buffer containing
501  *        the same data as before.  The handler then has the responsibility of
502  *        making sure the buffer eventually gets freed.  Example:
503  *
504  * void myhandler(void *msg)
505  * {
506  *    CmiGrabBuffer(&msg);      // Claim ownership of the message buffer
507  *    ... rest of handler ...
508  *    CmiFree(msg);             // I have the right to free it or
509  *                              // keep it, as I wish.
510  * }
511  *
512  *
513  * For this common implementation to work, the machine layer must provide the
514  * following:
515  *
516  * void *CmiGetNonLocal()
517  *
518  *      - returns a message just retrieved from some other PE, not from
519  *        local.  If no such message exists, returns 0.
520  *
521  * CpvExtern(FIFO_Queue, CmiLocalQueue);
522  *
523  *      - a FIFO queue containing all messages from the local processor.
524  *
525  *****************************************************************************/
526
527 CpvDeclare(CmiHandler, CsdNotifyIdle);
528 CpvDeclare(CmiHandler, CsdNotifyBusy);
529 CpvDeclare(int, CsdStopNotifyFlag);
530 CpvStaticDeclare(int, CsdIdleDetectedFlag);
531
532 void CsdEndIdle()
533 {
534   if(CpvAccess(CsdIdleDetectedFlag)) {
535     CpvAccess(CsdIdleDetectedFlag) = 0;
536     if(!CpvAccess(CsdStopNotifyFlag)) {
537       (CpvAccess(CsdNotifyBusy))();
538       trace_end_idle();
539     }
540   }
541 }
542
543 void CsdBeginIdle()
544 {
545   if (!CpvAccess(CsdIdleDetectedFlag)) {
546     CpvAccess(CsdIdleDetectedFlag) = 1;
547     if(!CpvAccess(CsdStopNotifyFlag)) {
548       (CpvAccess(CsdNotifyIdle))();
549       trace_begin_idle();
550     }
551   }
552
553   CmiNotifyIdle();
554   CcdRaiseCondition(CcdPROCESSORIDLE) ;
555 }
556   
557 #if CMK_CMIDELIVERS_USE_COMMON_CODE
558
559 CpvExtern(void*, CmiLocalQueue);
560 CtvStaticDeclare(int, CmiBufferGrabbed);
561
562 void CmiGrabBuffer(void **bufptrptr)
563 {
564   CtvAccess(CmiBufferGrabbed) = 1;
565 }
566
567 void CmiHandleMessage(void *msg)
568 {
569   CtvAccess(CmiBufferGrabbed) = 0;
570   (CmiGetHandlerFunction(msg))(msg);
571   if (!CtvAccess(CmiBufferGrabbed)) CmiFree(msg);
572 }
573
574 void CmiDeliversInit()
575 {
576   CtvInitialize(int, CmiBufferGrabbed);
577   CtvAccess(CmiBufferGrabbed) = 0;
578 }
579
580 int CmiDeliverMsgs(int maxmsgs)
581 {
582   return CsdScheduler(maxmsgs);
583 }
584
585 int CsdScheduler(int maxmsgs)
586 {
587   int *msg;
588   void *localqueue = CpvAccess(CmiLocalQueue);
589   int cycle = CpvAccess(CsdStopFlag);
590   
591   if(maxmsgs == 0) {
592     while(1) {
593       msg = CmiGetNonLocal();
594       if (msg==0) FIFO_DeQueue(localqueue, &msg);
595       if (msg==0) CqsDequeue(CpvAccess(CsdSchedQueue),&msg);
596       if (msg) {
597         CmiHandleMessage(msg);
598         maxmsgs--;
599         if (CpvAccess(CsdStopFlag) != cycle) return maxmsgs;
600       } else {
601         return maxmsgs;
602       }
603     }
604   }
605   while (1) {
606     msg = CmiGetNonLocal();
607     if (msg==0) FIFO_DeQueue(localqueue, &msg);
608     if (msg==0) CqsDequeue(CpvAccess(CsdSchedQueue),&msg);
609     if (msg) {
610       CsdEndIdle();
611       CmiHandleMessage(msg);
612       maxmsgs--; if (maxmsgs==0) return maxmsgs;
613       if (CpvAccess(CsdStopFlag) != cycle) return maxmsgs;
614     } else {
615       CsdBeginIdle();
616       if (CpvAccess(CsdStopFlag) != cycle) {
617         CsdEndIdle();
618         return maxmsgs;
619       }
620     }
621     if (!CpvAccess(disable_sys_msgs))
622       if (CpvAccess(CcdNumChecks) > 0)
623         CcdCallBacks();
624   }
625 }
626
627 void CmiDeliverSpecificMsg(handler)
628 int handler;
629 {
630   int *msg, *t; int side;
631   void *localqueue = CpvAccess(CmiLocalQueue);
632  
633   side = 0;
634   while (1) {
635     side ^= 1;
636     if (side) msg = CmiGetNonLocal();
637     else      FIFO_DeQueue(localqueue, &msg);
638     if (msg) {
639       if (CmiGetHandler(msg)==handler) {
640         CsdEndIdle();
641         CmiHandleMessage(msg);
642         return;
643       } else {
644         FIFO_EnQueue(localqueue, msg);
645       }
646     }
647   }
648 }
649  
650 #endif /* CMK_CMIDELIVERS_USE_COMMON_CODE */
651
652 /***************************************************************************
653  *
654  * Standin Schedulers.
655  *
656  * We use the following strategy to make sure somebody's always running
657  * the scheduler (CsdScheduler).  Initially, we assume the main thread
658  * is responsible for this.  If the main thread blocks, we create a
659  * "standin scheduler" thread to replace it.  If the standin scheduler
660  * blocks, we create another standin scheduler to replace that one,
661  * ad infinitum.  Collectively, the main thread and all the standin
662  * schedulers are called "scheduling threads".
663  *
664  * Suppose the main thread is blocked waiting for data, and a standin
665  * scheduler is running instead.  Suppose, then, that the data shows
666  * up and the main thread is CthAwakened.  This causes a token to be
667  * pushed into the queue.  When the standin pulls the token from the
668  * queue and handles it, the standin goes to sleep, and control shifts
669  * back to the main thread.  In this way, unnecessary standins are put
670  * back to sleep.  These sleeping standins are stored on the
671  * CthSleepingStandins list.
672  *
673  ***************************************************************************/
674
675 CpvStaticDeclare(CthThread, CthMainThread);
676 CpvStaticDeclare(CthThread, CthSchedulingThread);
677 CpvStaticDeclare(CthThread, CthSleepingStandins);
678 CpvStaticDeclare(int      , CthResumeNormalThreadIdx);
679 CpvStaticDeclare(int      , CthResumeSchedulingThreadIdx);
680
681 /** addition for tracing */
682 CpvExtern(CthThread, cThread);
683 /* end addition */
684
685 static void CthStandinCode()
686 {
687   while (1) CsdScheduler(0);
688 }
689
690 static CthThread CthSuspendNormalThread()
691 {
692   return CpvAccess(CthSchedulingThread);
693 }
694
695 static void CthEnqueueSchedulingThread(CthThread t);
696 static CthThread CthSuspendSchedulingThread();
697
698 static CthThread CthSuspendSchedulingThread()
699 {
700   CthThread succ = CpvAccess(CthSleepingStandins);
701   CthThread me = CthSelf();
702
703   if (succ) {
704     CpvAccess(CthSleepingStandins) = CthGetNext(succ);
705   } else {
706     succ = CthCreate(CthStandinCode, 0, 256000);
707     CthSetStrategy(succ,
708                    CthEnqueueSchedulingThread,
709                    CthSuspendSchedulingThread);
710   }
711   
712   CpvAccess(CthSchedulingThread) = succ;
713   return succ;
714 }
715
716 static void CthResumeNormalThread(CthThread t)
717 {
718   CmiGrabBuffer(&t);
719   /** addition for tracing */
720   CpvAccess(cThread) = t;
721   trace_begin_execute(0);
722   /* end addition */
723   CthResume(t);
724 }
725
726 static void CthResumeSchedulingThread(CthThread t)
727 {
728   CthThread me = CthSelf();
729   CmiGrabBuffer(&t);
730   if (me == CpvAccess(CthMainThread)) {
731     CthEnqueueSchedulingThread(me);
732   } else {
733     CthSetNext(me, CpvAccess(CthSleepingStandins));
734     CpvAccess(CthSleepingStandins) = me;
735   }
736   CpvAccess(CthSchedulingThread) = t;
737   CthResume(t);
738 }
739
740 static void CthEnqueueNormalThread(CthThread t)
741 {
742   CmiSetHandler(t, CpvAccess(CthResumeNormalThreadIdx));
743   CsdEnqueueLifo(t);
744 }
745
746 static void CthEnqueueSchedulingThread(CthThread t)
747 {
748   CmiSetHandler(t, CpvAccess(CthResumeSchedulingThreadIdx));
749   CsdEnqueueLifo(t);
750 }
751
752 void CthSetStrategyDefault(CthThread t)
753 {
754   CthSetStrategy(t,
755                  CthEnqueueNormalThread,
756                  CthSuspendNormalThread);
757 }
758
759 void CthSchedInit()
760 {
761   CpvInitialize(CthThread, CthMainThread);
762   CpvInitialize(CthThread, CthSchedulingThread);
763   CpvInitialize(CthThread, CthSleepingStandins);
764   CpvInitialize(int      , CthResumeNormalThreadIdx);
765   CpvInitialize(int      , CthResumeSchedulingThreadIdx);
766
767   CpvAccess(CthMainThread) = CthSelf();
768   CpvAccess(CthSchedulingThread) = CthSelf();
769   CpvAccess(CthSleepingStandins) = 0;
770   CpvAccess(CthResumeNormalThreadIdx) =
771     CmiRegisterHandler(CthResumeNormalThread);
772   CpvAccess(CthResumeSchedulingThreadIdx) =
773     CmiRegisterHandler(CthResumeSchedulingThread);
774   CthSetStrategy(CthSelf(),
775                  CthEnqueueSchedulingThread,
776                  CthSuspendSchedulingThread);
777 }
778
779 void CsdInit(argv)
780   char **argv;
781 {
782   void *CqsCreate();
783
784   CpvInitialize(int,   disable_sys_msgs);
785   CpvInitialize(void*, CsdSchedQueue);
786   CpvInitialize(int,   CsdStopFlag);
787   CpvInitialize(int,   CsdStopNotifyFlag);
788   CpvInitialize(int,   CsdIdleDetectedFlag);
789   CpvInitialize(CmiHandler,   CsdNotifyIdle);
790   CpvInitialize(CmiHandler,   CsdNotifyBusy);
791   
792   CpvAccess(disable_sys_msgs) = 0;
793   CpvAccess(CsdSchedQueue) = CqsCreate();
794   CpvAccess(CsdStopFlag)  = 0;
795   CpvAccess(CsdStopNotifyFlag) = 1;
796   CpvAccess(CsdIdleDetectedFlag) = 0;
797 }
798
799
800 /*****************************************************************************
801  *
802  * Vector Send
803  *
804  ****************************************************************************/
805
806 #if CMK_VECTOR_SEND_USES_COMMON_CODE
807
808 void CmiSyncVectorSend(destPE, n, sizes, msgs)
809 int destPE, n;
810 int *sizes;
811 char **msgs;
812 {
813   int i, total;
814   char *mesg, *tmp;
815   
816   for(i=0,total=0;i<n;i++) total += sizes[i];
817   mesg = (char *) CmiAlloc(total);
818   for(i=0,tmp=mesg;i<n;i++) {
819     memcpy(tmp, msgs[i],sizes[i]);
820     tmp += sizes[i];
821   }
822   CmiSyncSendAndFree(destPE, total, mesg);
823 }
824
825 CmiCommHandle CmiAsyncVectorSend(destPE, n, sizes, msgs)
826 int destPE, n;
827 int *sizes;
828 char **msgs;
829 {
830   CmiSyncVectorSend(destPE,n,sizes,msgs);
831   return NULL;
832 }
833
834 void CmiSyncVectorSendAndFree(destPE, n, sizes, msgs)
835 int destPE, n;
836 int *sizes;
837 char **msgs;
838 {
839   int i;
840
841   CmiSyncVectorSend(destPE,n,sizes,msgs);
842   for(i=0;i<n;i++) CmiFree(msgs[i]);
843   CmiFree(sizes);
844   CmiFree(msgs);
845 }
846
847 #endif
848
849 /*****************************************************************************
850  *
851  * Converse Initialization
852  *
853  *****************************************************************************/
854
855 void ConverseCommonInit(char **argv)
856 {
857   CstatsInit(argv);
858   CcdModuleInit(argv);
859   CmiHandlerInit();
860   CmiMemoryInit(argv);
861   CmiDeliversInit();
862   CsdInit(argv);
863   CthSchedInit();
864   CldModuleInit();
865 }
866
867 void ConverseCommonExit(void)
868 {
869   close_log();
870 }