7a65890f65aa2428bc9896bb475b4b4741b8c24b
[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()
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   while (1) {
592     msg = CmiGetNonLocal();
593     if (msg==0) FIFO_DeQueue(localqueue, &msg);
594     if (msg==0) CqsDequeue(CpvAccess(CsdSchedQueue),&msg);
595     if (msg) {
596       CsdEndIdle();
597       CmiHandleMessage(msg);
598       maxmsgs--; if (maxmsgs==0) return maxmsgs;
599       if (CpvAccess(CsdStopFlag) != cycle) return maxmsgs;
600     } else {
601       CsdBeginIdle();
602       if (CpvAccess(CsdStopFlag) != cycle) {
603         CsdEndIdle();
604         return maxmsgs;
605       }
606     }
607     if (!CpvAccess(disable_sys_msgs))
608       if (CpvAccess(CcdNumChecks) > 0)
609         CcdCallBacks();
610   }
611 }
612
613 void CmiDeliverSpecificMsg(handler)
614 int handler;
615 {
616   int *msg, *t; int side;
617   void *localqueue = CpvAccess(CmiLocalQueue);
618  
619   side = 0;
620   while (1) {
621     side ^= 1;
622     if (side) msg = CmiGetNonLocal();
623     else      FIFO_DeQueue(localqueue, &msg);
624     if (msg) {
625       if (CmiGetHandler(msg)==handler) {
626         CsdEndIdle();
627         CmiHandleMessage(msg);
628         return;
629       } else {
630         FIFO_EnQueue(localqueue, msg);
631       }
632     }
633   }
634 }
635  
636 #endif /* CMK_CMIDELIVERS_USE_COMMON_CODE */
637
638 /***************************************************************************
639  *
640  * Standin Schedulers.
641  *
642  * We use the following strategy to make sure somebody's always running
643  * the scheduler (CsdScheduler).  Initially, we assume the main thread
644  * is responsible for this.  If the main thread blocks, we create a
645  * "standin scheduler" thread to replace it.  If the standin scheduler
646  * blocks, we create another standin scheduler to replace that one,
647  * ad infinitum.  Collectively, the main thread and all the standin
648  * schedulers are called "scheduling threads".
649  *
650  * Suppose the main thread is blocked waiting for data, and a standin
651  * scheduler is running instead.  Suppose, then, that the data shows
652  * up and the main thread is CthAwakened.  This causes a token to be
653  * pushed into the queue.  When the standin pulls the token from the
654  * queue and handles it, the standin goes to sleep, and control shifts
655  * back to the main thread.  In this way, unnecessary standins are put
656  * back to sleep.  These sleeping standins are stored on the
657  * CthSleepingStandins list.
658  *
659  ***************************************************************************/
660
661 CpvStaticDeclare(CthThread, CthMainThread);
662 CpvStaticDeclare(CthThread, CthSchedulingThread);
663 CpvStaticDeclare(CthThread, CthSleepingStandins);
664 CpvStaticDeclare(int      , CthResumeNormalThreadIdx);
665 CpvStaticDeclare(int      , CthResumeSchedulingThreadIdx);
666
667 /** addition for tracing */
668 CpvExtern(CthThread, cThread);
669 /* end addition */
670
671 static void CthStandinCode()
672 {
673   while (1) CsdScheduler(0);
674 }
675
676 static CthThread CthSuspendNormalThread()
677 {
678   return CpvAccess(CthSchedulingThread);
679 }
680
681 static void CthEnqueueSchedulingThread(CthThread t);
682 static CthThread CthSuspendSchedulingThread();
683
684 static CthThread CthSuspendSchedulingThread()
685 {
686   CthThread succ = CpvAccess(CthSleepingStandins);
687   CthThread me = CthSelf();
688
689   if (succ) {
690     CpvAccess(CthSleepingStandins) = CthGetNext(succ);
691   } else {
692     succ = CthCreate(CthStandinCode, 0, 256000);
693     CthSetStrategy(succ,
694                    CthEnqueueSchedulingThread,
695                    CthSuspendSchedulingThread);
696   }
697   
698   CpvAccess(CthSchedulingThread) = succ;
699   return succ;
700 }
701
702 static void CthResumeNormalThread(CthThread t)
703 {
704   CmiGrabBuffer(&t);
705   /** addition for tracing */
706   CpvAccess(cThread) = t;
707   trace_begin_execute(0);
708   /* end addition */
709   CthResume(t);
710 }
711
712 static void CthResumeSchedulingThread(CthThread t)
713 {
714   CthThread me = CthSelf();
715   CmiGrabBuffer(&t);
716   if (me == CpvAccess(CthMainThread)) {
717     CthEnqueueSchedulingThread(me);
718   } else {
719     CthSetNext(me, CpvAccess(CthSleepingStandins));
720     CpvAccess(CthSleepingStandins) = me;
721   }
722   CpvAccess(CthSchedulingThread) = t;
723   CthResume(t);
724 }
725
726 static void CthEnqueueNormalThread(CthThread t)
727 {
728   CmiSetHandler(t, CpvAccess(CthResumeNormalThreadIdx));
729   CsdEnqueueLifo(t);
730 }
731
732 static void CthEnqueueSchedulingThread(CthThread t)
733 {
734   CmiSetHandler(t, CpvAccess(CthResumeSchedulingThreadIdx));
735   CsdEnqueueLifo(t);
736 }
737
738 void CthSetStrategyDefault(CthThread t)
739 {
740   CthSetStrategy(t,
741                  CthEnqueueNormalThread,
742                  CthSuspendNormalThread);
743 }
744
745 void CthSchedInit()
746 {
747   CpvInitialize(CthThread, CthMainThread);
748   CpvInitialize(CthThread, CthSchedulingThread);
749   CpvInitialize(CthThread, CthSleepingStandins);
750   CpvInitialize(int      , CthResumeNormalThreadIdx);
751   CpvInitialize(int      , CthResumeSchedulingThreadIdx);
752
753   CpvAccess(CthMainThread) = CthSelf();
754   CpvAccess(CthSchedulingThread) = CthSelf();
755   CpvAccess(CthSleepingStandins) = 0;
756   CpvAccess(CthResumeNormalThreadIdx) =
757     CmiRegisterHandler(CthResumeNormalThread);
758   CpvAccess(CthResumeSchedulingThreadIdx) =
759     CmiRegisterHandler(CthResumeSchedulingThread);
760   CthSetStrategy(CthSelf(),
761                  CthEnqueueSchedulingThread,
762                  CthSuspendSchedulingThread);
763 }
764
765 void CsdInit(argv)
766   char **argv;
767 {
768   void *CqsCreate();
769
770   CpvInitialize(int,   disable_sys_msgs);
771   CpvInitialize(void*, CsdSchedQueue);
772   CpvInitialize(int,   CsdStopFlag);
773   CpvInitialize(int,   CsdStopNotifyFlag);
774   CpvInitialize(int,   CsdIdleDetectedFlag);
775   CpvInitialize(CmiHandler,   CsdNotifyIdle);
776   CpvInitialize(CmiHandler,   CsdNotifyBusy);
777   
778   CpvAccess(disable_sys_msgs) = 0;
779   CpvAccess(CsdSchedQueue) = CqsCreate();
780   CpvAccess(CsdStopFlag)  = 0;
781   CpvAccess(CsdStopNotifyFlag) = 1;
782   CpvAccess(CsdIdleDetectedFlag) = 0;
783 }
784
785
786 /*****************************************************************************
787  *
788  * Vector Send
789  *
790  ****************************************************************************/
791
792 #if CMK_VECTOR_SEND_USES_COMMON_CODE
793
794 void CmiSyncVectorSend(destPE, n, sizes, msgs)
795 int destPE, n;
796 int *sizes;
797 char **msgs;
798 {
799   int i, total;
800   char *mesg, *tmp;
801   
802   for(i=0,total=0;i<n;i++) total += sizes[i];
803   mesg = (char *) CmiAlloc(total);
804   for(i=0,tmp=mesg;i<n;i++) {
805     memcpy(tmp, msgs[i],sizes[i]);
806     tmp += sizes[i];
807   }
808   CmiSyncSendAndFree(destPE, total, mesg);
809 }
810
811 CmiCommHandle CmiAsyncVectorSend(destPE, n, sizes, msgs)
812 int destPE, n;
813 int *sizes;
814 char **msgs;
815 {
816   CmiSyncVectorSend(destPE,n,sizes,msgs);
817   return NULL;
818 }
819
820 void CmiSyncVectorSendAndFree(destPE, n, sizes, msgs)
821 int destPE, n;
822 int *sizes;
823 char **msgs;
824 {
825   int i;
826
827   CmiSyncVectorSend(destPE,n,sizes,msgs);
828   for(i=0;i<n;i++) CmiFree(msgs[i]);
829   CmiFree(sizes);
830   CmiFree(msgs);
831 }
832
833 #endif
834
835 /*****************************************************************************
836  *
837  * Converse Initialization
838  *
839  *****************************************************************************/
840
841 void ConverseCommonInit(char **argv)
842 {
843   CstatsInit(argv);
844   CcdModuleInit(argv);
845   CmiHandlerInit();
846   CmiMemoryInit(argv);
847   CmiDeliversInit();
848   CsdInit(argv);
849   CthSchedInit();
850   CldModuleInit();
851 }
852
853 void ConverseCommonExit(void)
854 {
855   close_log();
856 }