4b495e581454d1a9517274b2ac8cc05756fb8c26
[charm.git] / src / arch / uth / machine.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  * $Log$
15  * Revision 1.27  1997-07-30 19:58:09  jyelon
16  * *** empty log message ***
17  *
18  * Revision 1.26  1997/07/30 17:31:13  jyelon
19  * *** empty log message ***
20  *
21  * Revision 1.25  1997/07/29 16:09:47  milind
22  * Added CmiNodeLock macros and functions to the machine layer for all except
23  * solaris SMP.
24  *
25  * Revision 1.24  1997/04/25 20:48:12  jyelon
26  * Corrected CmiNotifyIdle
27  *
28  * Revision 1.23  1997/04/24 22:37:02  jyelon
29  * Added CmiNotifyIdle
30  *
31  * Revision 1.22  1997/03/21 19:23:57  milind
32  * removed the alignment bug in Common.uth/machine.c
33  *
34  * Revision 1.21  1997/03/19 04:31:36  jyelon
35  * Redesigned ConverseInit
36  *
37  * Revision 1.20  1997/02/13 09:31:39  jyelon
38  * Updated for new main/ConverseInit structure.
39  *
40  * Revision 1.19  1997/01/17 15:49:57  jyelon
41  * Minor adjustments to deal with recent changes to Common code.
42  *
43  * Revision 1.18  1996/11/20 06:46:54  jyelon
44  * Repaired rob's HP/C++ mods.
45  *
46  * Revision 1.17  1996/11/08 22:22:53  brunner
47  * Put _main in for HP-UX CC compilation.  It is ignored according to the
48  * CMK_USE_HP_MAIN_FIX flag.
49  *
50  * Revision 1.16  1996/07/19 17:07:37  jyelon
51  * *** empty log message ***
52  *
53  * Revision 1.15  1996/07/15 20:59:22  jyelon
54  * Moved much timer, signal, etc code into common.
55  *
56  * Revision 1.14  1996/07/02 21:25:22  jyelon
57  * *** empty log message ***
58  *
59  * Revision 1.13  1996/02/10 18:57:29  sanjeev
60  * fixed bugs in CmiGetNodeNeighbours, CmiNeighboursIndex
61  *
62  * Revision 1.12  1996/02/10 18:54:24  sanjeev
63  * fixed bug in CmiNumNeighbours
64  *
65  * Revision 1.11  1995/11/07 23:20:32  jyelon
66  * removed neighbour_init residue.
67  *
68  * Revision 1.10  1995/11/07  18:24:53  jyelon
69  * Corrected a bug in GetNodeNeighbours
70  *
71  * Revision 1.9  1995/11/07  18:16:45  jyelon
72  * Corrected 'neighbour' functions (they now make a hypercube).
73  *
74  * Revision 1.8  1995/10/27  21:45:35  jyelon
75  * Changed CmiNumPe --> CmiNumPes
76  *
77  * Revision 1.7  1995/10/18  22:22:53  jyelon
78  * I forget.
79  *
80  * Revision 1.6  1995/10/13  22:36:29  jyelon
81  * changed exit() --> exit(1)
82  *
83  * Revision 1.5  1995/10/13  22:34:42  jyelon
84  * added CmiNext to CmiCallMain.
85  *
86  * Revision 1.4  1995/10/13  20:05:13  jyelon
87  * *** empty log message ***
88  *
89  * Revision 1.3  1995/10/10  06:10:58  jyelon
90  * removed program_name
91  *
92  * Revision 1.2  1995/09/30  15:44:59  jyelon
93  * fixed a bug.
94  *
95  * Revision 1.1  1995/09/30  15:00:00  jyelon
96  * Initial revision
97  *
98  * Revision 2.5  1995/09/29  09:50:07  jyelon
99  * CmiGet-->CmiDeliver, added protos, etc.
100  *
101  * Revision 2.4  1995/09/20  15:56:29  gursoy
102  * made the arg of CmiFree and CmiSize void*
103  *
104  * Revision 2.3  1995/09/07  22:33:07  gursoy
105  * now the processor specific variables in machine files also accessed thru macros (because macros modifies the var names)
106  *
107  * Revision 2.2  1995/07/26  19:04:11  gursoy
108  * fixed some timer-system-include-file related problems
109  *
110  * Revision 2.1  1995/07/11  16:53:57  gursoy
111  * added CsdStopCount
112  *
113  * Revision 2.0  1995/07/05  23:37:59  gursoy
114  * *** empty log message ***
115  *
116  *
117  *
118  ***************************************************************************/
119 static char ident[] = "@(#)$Header$";
120
121 #include <stdio.h>
122 #include <math.h>
123 #include "converse.h"
124
125 static char *DeleteArg(argv)
126   char **argv;
127 {
128   char *res = argv[0];
129   if (res==0) { CmiError("Bad arglist."); exit(1); }
130   while (*argv) { argv[0]=argv[1]; argv++; }
131   return res;
132 }
133
134 /*****************************************************************************
135  *
136  * Memory management.
137  * 
138  ****************************************************************************/
139
140 void *CmiAlloc(size)
141 int size;
142 {
143 char *res;
144 res =(char *)malloc(size+8);
145 if (res==0) printf("Memory allocation failed.");
146 ((int *)res)[0]=size;
147 return (void *)(res+8);
148 }
149
150 int CmiSize(blk)
151 void *blk;
152 {
153 return ((int *)(((char *)blk)-8))[0];
154 }
155
156 void CmiFree(blk)
157 void *blk;
158 {
159 free( ((char *)blk)-8);
160 }
161
162 /*****************************************************************************
163  *
164  * Module variables
165  * 
166  ****************************************************************************/
167
168 typedef void *Fifo;
169
170 int        Cmi_mype;
171 int        Cmi_myrank;
172 int        Cmi_numpes;
173 int        Cmi_nodesize;
174 int        Cmi_stacksize = 64000;
175 char     **CmiArgv;
176 CmiStartFn CmiStart;
177 int        CmiUsched;
178 CthThread *CmiThreads;
179 Fifo      *CmiQueues;
180 int       *CmiBarred;
181 int        CmiNumBarred=0;
182
183 Fifo FIFO_Create();
184 CpvDeclare(Fifo, CmiLocalQueue);
185
186 /******************************************************************************
187  *
188  * Load-Balancer needs
189  *
190  * These neighbour functions impose a (possibly incomplete)
191  * hypercube on the machine.
192  *
193  *****************************************************************************/
194
195
196 long CmiNumNeighbours(node)
197 int node;
198 {
199   int bit, count=0;
200   bit = 1;
201   while (1) {
202     int neighbour = node ^ bit;
203     if (neighbour < CmiNumPes()) count++;
204     bit = bit<<1; 
205     if (bit > CmiNumPes()) break;
206   }
207   return count;
208 }
209
210 int CmiGetNodeNeighbours(node, neighbours)
211 int node, *neighbours;
212 {
213   int bit, count=0;
214   bit = 1;
215   while (1) {
216     int neighbour = node ^ bit;
217     if (neighbour < CmiNumPes()) neighbours[count++] = neighbour;
218     bit = bit<<1; 
219     if (bit > CmiNumPes()) break;
220   }
221   return count;
222 }
223  
224 int CmiNeighboursIndex(node, nbr)
225 int node, nbr;
226 {
227   int bit, count=0;
228   bit = 1;
229   while (1) {
230     int neighbour = node ^ bit;
231     if (neighbour < CmiNumPes()) { if (nbr==neighbour) return count; count++; }
232     bit = bit<<=1; 
233     if (bit > CmiNumPes()) break;
234   }
235   return(-1);
236 }
237
238
239 /*****************************************************************************
240  *
241  * Comm handles are nonexistent in uth version
242  *
243  *****************************************************************************/
244
245 int CmiAsyncMsgSent(c)
246 CmiCommHandle c ;
247 {
248   return 1;
249 }
250
251 void CmiReleaseCommHandle(c)
252 CmiCommHandle c ;
253 {
254 }
255
256 /********************* CONTEXT-SWITCHING FUNCTIONS ******************/
257
258 static void CmiNext()
259 {
260   CthThread t; int index; int orig;
261   index = (CmiMyPe()+1) % CmiNumPes();
262   orig = index;
263   while (1) {
264     t = CmiThreads[index];
265     if ((t)&&(!CmiBarred[index])) break;
266     index = (index+1) % CmiNumPes();
267     if (index == orig) exit(0);
268   }
269   Cmi_mype = index;
270   CthResume(t);
271 }
272
273 void CmiExit()
274 {
275   CmiThreads[CmiMyPe()] = 0;
276   CmiFree(CthSelf());
277   CmiNext();
278 }
279
280 void CmiYield()
281 {
282   CmiThreads[CmiMyPe()] = CthSelf();
283   CmiNext();
284 }
285
286 void CmiNodeBarrier()
287 {
288   int i;
289   CmiNumBarred++;
290   CmiBarred[CmiMyPe()] = 1;
291   if (CmiNumBarred == CmiNumPes()) {
292     for (i=0; i<CmiNumPes(); i++) CmiBarred[i]=0;
293     CmiNumBarred=0;
294   }
295   CmiYield();
296 }
297
298 CmiNodeLock CmiCreateLock()
299 {
300   return (CmiNodeLock)malloc(sizeof(int));
301 }
302
303 void CmiLock(CmiNodeLock lk)
304 {
305   while (*lk) CmiYield();
306   *lk = 1;
307 }
308
309 void CmiUnlock(CmiNodeLock lk)
310 {
311   if (*lk==0) {
312     CmiError("CmiNodeLock not locked, can't unlock.");
313     exit(1);
314   }
315   *lk = 0;
316 }
317
318 int CmiTryLock(CmiNodeLock lk)
319 {
320   if (*lk==0) { *lk=1; return 0; }
321   return -1;
322 }
323
324 void CmiDestroyLock(CmiNodeLock lk)
325 {
326   free(lk);
327 }
328
329
330 /*****************************************************************************
331  *
332  * The following are the CmiDeliverXXX functions.
333  *
334  * void CmiDeliversInit()
335  *
336  *      - CmiInit promises to call this before calling CmiDeliverMsgs
337  *        or any of the other functions in this section.
338  *
339  * int CmiDeliverMsgs(int maxmsgs)
340  *
341  *      - CmiDeliverMsgs will retrieve up to maxmsgs that were transmitted
342  *        with the Cmi, and will invoke their handlers.  It does not wait
343  *        if no message is unavailable.  Instead, it returns the quantity
344  *        (maxmsgs-delivered), where delivered is the number of messages it
345  *        delivered.
346  *
347  * void CmiDeliverSpecificMsg(int handlerno)
348  *
349  *      - Waits for a message with the specified handler to show up, then
350  *        invokes the message's handler.  Note that unlike CmiDeliverMsgs,
351  *        This function _does_ wait.
352  *
353  * void CmiGrabBuffer(void **bufptrptr)
354  *
355  *      - When CmiDeliverMsgs or CmiDeliverSpecificMsgs calls a handler,
356  *        the handler receives a pointer to a buffer containing the message.
357  *        The buffer does not belong to the handler, eg, the handler may not
358  *        free the buffer.  Instead, the buffer will be automatically reused
359  *        or freed as soon as the handler returns.  If the handler wishes to
360  *        keep a copy of the data after the handler returns, it may do so by
361  *        calling CmiGrabBuffer and passing it a pointer to a variable which
362  *        in turn contains a pointer to the system buffer.  The variable will
363  *        be updated to contain a pointer to a handler-owned buffer containing
364  *        the same data as before.  The handler then has the responsibility of
365  *        making sure the buffer eventually gets freed.  Example:
366  *
367  * void myhandler(void *msg)
368  * {
369  *    CmiGrabBuffer(&msg);      // Claim ownership of the message buffer
370  *    ... rest of handler ...
371  *    CmiFree(msg);             // I have the right to free it or
372  *                              // keep it, as I wish.
373  * }
374  *
375  *
376  * For this common implementation to work, the machine layer must provide the
377  * following:
378  *
379  * void *CmiGetNonLocal()
380  *
381  *      - returns a message just retrieved from some other PE, not from
382  *        local.  If no such message exists, returns 0.
383  *
384  * CpvExtern(FIFO_Queue, CmiLocalQueue);
385  *
386  *      - a FIFO queue containing all messages from the local processor.
387  *
388  *****************************************************************************/
389
390 CpvStaticDeclare(int, CmiBufferGrabbed);
391 CpvExtern(void*, CmiLocalQueue);
392
393 void CmiDeliversInit()
394 {
395   CpvInitialize(int, CmiBufferGrabbed);
396   CpvAccess(CmiBufferGrabbed) = 0;
397 }
398
399 void CmiGrabBuffer()
400 {
401   CpvAccess(CmiBufferGrabbed) = 1;
402 }
403
404 int CmiDeliverMsgs(maxmsgs)
405 int maxmsgs;
406 {
407   void *msg;
408   
409   while (1) {
410     CmiYield();
411     FIFO_DeQueue(CpvAccess(CmiLocalQueue), &msg);
412     if (msg==0) break;
413     CpvAccess(CmiBufferGrabbed)=0;
414     (CmiGetHandlerFunction(msg))(msg);
415     if (!CpvAccess(CmiBufferGrabbed)) CmiFree(msg);
416     maxmsgs--; if (maxmsgs==0) break;
417   }
418   return maxmsgs;
419 }
420
421 /*
422  * CmiDeliverSpecificMsg(lang)
423  *
424  * - waits till a message with the specified handler is received,
425  *   then delivers it.
426  *
427  */
428
429 void CmiDeliverSpecificMsg(handler)
430 int handler;
431 {
432   void *tmpqueue = FIFO_Create(); int *msg, *msg1;
433   
434   while (1) {
435     FIFO_DeQueue(CpvAccess(CmiLocalQueue), &msg);
436     if (msg == 0) { CmiYield(); continue; }
437     if (CmiGetHandler(msg)==handler) break;
438     FIFO_EnQueue(tmpqueue, msg);
439   }
440   while (1) {
441     FIFO_DeQueue(tmpqueue, &msg1);
442     if (msg1==0) break;
443     FIFO_EnQueue(CpvAccess(CmiLocalQueue), msg1);
444   }
445   FIFO_Destroy(tmpqueue);
446   CpvAccess(CmiBufferGrabbed)=0;
447   (CmiGetHandlerFunction(msg))(msg);
448   if (!CpvAccess(CmiBufferGrabbed)) CmiFree(msg);
449 }
450
451 void CmiNotifyIdle()
452 {
453 #if CMK_WHEN_PROCESSOR_IDLE_USLEEP
454   tv.tv_sec=0; tv.tv_usec=5000;
455   select(0,0,0,0,&tv);
456 #endif
457 }
458  
459 /********************* MESSAGE SEND FUNCTIONS ******************/
460
461 void CmiSyncSendFn(destPE, size, msg)
462 int destPE;
463 int size;
464 char * msg;
465 {
466   char *buf = (char *)CmiAlloc(size);
467   memcpy(buf,msg,size);
468   FIFO_EnQueue(CmiQueues[destPE],buf);
469 }
470
471 CmiCommHandle CmiAsyncSendFn(destPE, size, msg) 
472 int destPE;
473 int size;
474 char * msg;
475 {
476   char *buf = (char *)CmiAlloc(size);
477   memcpy(buf,msg,size);
478   FIFO_EnQueue(CmiQueues[destPE],buf);
479 }
480
481 void CmiFreeSendFn(destPE, size, msg)
482 int destPE;
483 int size;
484 char * msg;
485 {
486   FIFO_EnQueue(CmiQueues[destPE], msg);
487 }
488
489 void CmiSyncBroadcastFn(size, msg)
490 int size;
491 char * msg;
492 {
493   int i;
494   for(i=0; i<CmiNumPes(); i++)
495     if (i != CmiMyPe()) CmiSyncSendFn(i,size,msg);
496 }
497
498 CmiCommHandle CmiAsyncBroadcastFn(size, msg)
499 int size;
500 char * msg;
501 {
502   CmiSyncBroadcastFn(size, msg);
503   return 0;
504 }
505
506 void CmiFreeBroadcastFn(size, msg)
507 int size;
508 char * msg;
509 {
510   CmiSyncBroadcastFn(size, msg);
511   CmiFree(msg);
512 }
513
514 void CmiSyncBroadcastAllFn(size, msg)
515 int size;
516 char * msg;
517 {
518   int i;
519   for(i=0; i<CmiNumPes(); i++)
520     CmiSyncSendFn(i,size,msg);
521 }
522
523 CmiCommHandle CmiAsyncBroadcastAllFn(size, msg)
524 int size;
525 char * msg;
526 {
527   CmiSyncBroadcastAllFn(size,msg);
528   return 0 ;
529 }
530
531 void CmiFreeBroadcastAllFn(size, msg)
532 int size;
533 char * msg;
534 {
535   int i;
536   for(i=0; i<CmiNumPes(); i++)
537     if (i!=CmiMyPe()) CmiSyncSendFn(i,size,msg);
538   FIFO_EnQueue(CpvAccess(CmiLocalQueue),msg);
539 }
540
541
542
543 /************************** SETUP ***********************************/
544
545 static void CmiParseArgs(argv)
546 char **argv;
547 {
548   char **argp;
549   
550   for (argp=argv; *argp; ) {
551     if ((strcmp(*argp,"++stacksize")==0)&&(argp[1])) {
552       DeleteArg(argp);
553       Cmi_stacksize = atoi(*argp);
554       DeleteArg(argp);
555     } else if ((strcmp(*argp,"+p")==0)&&(argp[1])) {
556       Cmi_numpes = atoi(argp[1]);
557       argp+=2;
558     } else if (sscanf(*argp, "+p%d", &CmiNumPes()) == 1) {
559       argp+=1;
560     } else argp++;
561   }
562   
563   if (CmiNumPes()<1) {
564     printf("Error: must specify number of processors to simulate with +pXXX\n",CmiNumPes());
565     exit(1);
566   }
567 }
568
569 void CmiInitPE()
570 {
571   CpvAccess(CmiLocalQueue) = CmiQueues[CmiMyPe()];
572   CmiSpanTreeInit();
573   CmiTimerInit();
574   ConverseCommonInit(CmiArgv);
575 }
576
577 void CmiCallMain()
578 {
579   int argc; char **argv;
580   for (argc=0; CmiArgv[argc]; argc++);
581   argv = (char **)CmiAlloc((argc+1)*sizeof(char *));
582   memcpy(argv, CmiArgv, (argc+1)*sizeof(char *));
583   CmiInitPE();
584   CmiStart(argc, argv);
585   if (CmiUsched==0) CsdScheduler(-1);
586   CmiThreads[CmiMyPe()] = 0;
587   CmiNext();
588 }
589
590 void ConverseExit()
591 {
592   CmiThreads[CmiMyPe()] = 0;
593   CmiNext();
594 }
595
596 void ConverseInit(argc,argv,fn,usched,initret)
597 int argc;
598 char *argv[];
599 CmiStartFn fn;
600 int usched, initret;
601 {
602   CthThread t; int stacksize, i;
603   
604 #if CMK_USE_HP_MAIN_FIX
605 #if FOR_CPLUS
606   _main(argc,argv);
607 #endif
608 #endif
609   
610   CmiArgv = argv;
611   CmiStart = fn;
612   CmiUsched = usched;
613   CmiParseArgs(argv);
614   CthInit(argv);
615   CpvInitialize(void*, CmiLocalQueue);
616   CmiThreads = (CthThread *)CmiAlloc(CmiNumPes()*sizeof(CthThread));
617   CmiBarred  = (int       *)CmiAlloc(CmiNumPes()*sizeof(int));
618   CmiQueues  = (Fifo      *)CmiAlloc(CmiNumPes()*sizeof(Fifo));
619   
620   /* Create threads for all PE except PE 0 */
621   for(i=0; i<CmiNumPes(); i++) {
622     t = (i==0) ? CthSelf() : CthCreate(CmiCallMain, 0, Cmi_stacksize);
623     CmiThreads[i] = t;
624     CmiBarred[i] = 0;
625     CmiQueues[i] = FIFO_Create();
626   }
627   Cmi_mype = 0;
628   CmiInitPE();
629   if (initret==0) {
630     fn(argc, argv);
631     if (usched==0) CsdScheduler(-1);
632     ConverseExit();
633   }
634 }
635