netlrts & verbs: remove unused CmiIdleState declaration
[charm.git] / src / arch / netlrts / machine.c
blob5c83734223468f70d8c71edee10e9aa30696d929
2 /** @file
3 * Basic NET-LRTS implementation of Converse machine layer
4 * @ingroup NET
5 */
7 /** @defgroup NET
8 * NET implementation of machine layer, ethernet in particular
9 * @ingroup Machine
11 * THE DATAGRAM STREAM
13 * Messages are sent using UDP datagrams. The sender allocates a
14 * struct for each datagram to be sent. These structs stick around
15 * until slightly after the datagram is acknowledged.
17 * Datagrams are transmitted node-to-node (as opposed to pe-to-pe).
18 * Each node has an OtherNode struct for every other node in the
19 * system. The OtherNode struct contains:
21 * send_queue (all datagram-structs not yet transmitted)
22 * send_window (all datagram-structs transmitted but not ack'd)
24 * When an acknowledgement comes in, all packets in the send-window
25 * are either marked as acknowledged or pushed back into the send
26 * queue for retransmission.
28 * THE OUTGOING MESSAGE
30 * When you send or broadcast a message, the first thing the system
31 * does is system creates an OutgoingMsg struct to represent the
32 * operation. The OutgoingMsg contains a very direct expression
33 * of what you want to do:
35 * OutgoingMsg:
37 * size --- size of message in bytes
38 * data --- pointer to the buffer containing the message
39 * src --- processor which sent the message
40 * dst --- destination processor (-1=broadcast, -2=broadcast all)
41 * freemode --- see below.
42 * refcount --- see below.
44 * The OutgoingMsg is kept around until the transmission is done, then
45 * it is garbage collected --- the refcount and freemode fields are
46 * to assist garbage collection.
48 * The freemode indicates which kind of buffer-management policy was
49 * used (sync, async, or freeing). The sync policy is handled
50 * superficially by immediately converting sync sends into freeing
51 * sends. Thus, the freemode can either be 'A' (async) or 'F'
52 * (freeing). If the freemode is 'F', then garbage collection
53 * involves freeing the data and the OutgoingMsg structure itself. If
54 * the freemode is 'A', then the only cleanup is to change the
55 * freemode to 'X', a condition which is then detectable by
56 * CmiAsyncMsgSent. In this case, the actual freeing of the
57 * OutgoingMsg is done by CmiReleaseCommHandle.
59 * When the transmission is initiated, the system computes how many
60 * datagrams need to be sent, total. This number is stored in the
61 * refcount field. Each time a datagram is delivered, the refcount
62 * is decremented, when it reaches zero, cleanup is performed. There
63 * are two exceptions to this rule. Exception 1: if the OutgoingMsg
64 * is a send (not a broadcast) and can be performed with shared
65 * memory, the entire datagram system is bypassed, the message is
66 * simply delivered and freed, not using the refcount mechanism at
67 * all. Exception 2: If the message is a broadcast, then part of the
68 * broadcast that can be done via shared memory is performed prior to
69 * initiating the datagram/refcount system.
71 * DATAGRAM FORMATS AND MESSAGE FORMATS
73 * Datagrams have this format:
75 * srcpe (16 bits) --- source processor number.
76 * magic ( 8 bits) --- magic number to make sure DG is good.
77 * dstrank ( 8 bits) --- destination processor rank.
78 * seqno (32 bits) --- packet sequence number.
79 * data (XX byte) --- user data.
81 * The only reason the srcpe is in there is because the receiver needs
82 * to know which receive window to use. The dstrank field is needed
83 * because transmission is node-to-node. Once the message is
84 * assembled by the node, it must be delivered to the appropriate PE.
85 * The dstrank field is used to encode certain special-case scenarios.
86 * If the dstrank is DGRAM_BROADCAST, the transmission is a broadcast,
87 * and should be delivered to all processors in the node. If the dstrank
88 * is DGRAM_ACKNOWLEDGE, the datagram is an acknowledgement datagram, in
89 * which case the srcpe is the number of the acknowledger, the seqno is
90 * always zero, and the user data is a list of the seqno's being
91 * acknowledged. There may be other dstrank codes for special functions.
93 * To send a message, one chops it up into datagrams and stores those
94 * datagrams in a send-queue. These outgoing datagrams aren't stored
95 * in the explicit format shown above. Instead, they are stored as
96 * ImplicitDgrams, which contain the datagram header and a pointer to
97 * the user data (which is in the user message buffer, which is in the
98 * OutgoingMsg). At transmission time these are combined together.
100 * The combination of the datagram header with the user's data is
101 * performed right in the user's message buffer. Note that the
102 * datagram header is exactly 64 bits. One simply overwrites 64 bits
103 * of the user's message with a datagram header, sends the datagram
104 * straight from the user's message buffer, then restores the user's
105 * buffer to its original state. There is a small problem with the
106 * first datagram of the message: one needs 64 bits of space to store
107 * the datagram header. To make sure this space is there, we added a
108 * 64-bit unused space to the front of the Cmi message header. In
109 * addition to this, we also add 32 bits to the Cmi message header
110 * to make room for a length-field, making it possible to identify
111 * message boundaries.
113 * CONCURRENCY CONTROL
115 * This has changed recently.
117 * EFFICIENCY NOTES
119 * The sender-side does little copying. The async and freeing send
120 * routines do no copying at all. The sync send routines copy the
121 * message, then use the freeing-send routines. The other alternative
122 * is to not copy the message, and use the async send mechanism
123 * combined with a blocking wait. Blocking wait seems like a bad
124 * idea, since it could take a VERY long time to get all those
125 * datagrams out the door.
127 * The receiver side, unfortunately, must copy. To avoid copying,
128 * it would have to receive directly into a preallocated message buffer.
129 * Unfortunately, this can't work: there's no way to know how much
130 * memory to preallocate, and there's no way to know which datagram
131 * is coming next. Thus, we receive into fixed-size (large) datagram
132 * buffers. These are then inspected, and the messages extracted from
133 * them.
135 * Note that we are allocating a large number of structs: OutgoingMsg's,
136 * ImplicitDgrams, ExplicitDgrams. By design, each of these structs
137 * is a fixed-size structure. Thus, we can do memory allocation by
138 * simply keeping a linked-list of unused structs around. The only
139 * place where expensive memory allocation is performed is in the
140 * sync routines.
142 * Since the datagrams from one node to another are fully ordered,
143 * there is slightly more ordering than is needed: in theory, the
144 * datagrams of one message don't need to be ordered relative to the
145 * datagrams of another. This was done to simplify the sequencing
146 * mechanisms: implementing a fully-ordered stream is much simpler
147 * than a partially-ordered one. It also makes it possible to
148 * modularize, layering the message transmitter on top of the
149 * datagram-sequencer. In other words, it was just easier this way.
150 * Hopefully, this won't cause serious degradation: LAN's rarely get
151 * datagrams out of order anyway.
153 * A potential efficiency problem is the lack of message-combining.
154 * One datagram could conceivably contain several messages. This
155 * might be more efficient, it's not clear how much overhead is
156 * involved in sending a short datagram. Message-combining isn't
157 * really ``integrated'' into the design of this software, but you
158 * could fudge it as follows. Whenever you pull a short datagram from
159 * the send-queue, check the next one to see if it's also a short
160 * datagram. If so, pack them together into a ``combined'' datagram.
161 * At the receive side, simply check for ``combined'' datagrams, and
162 * treat them as if they were simply two datagrams. This would
163 * require extra copying. I have no idea if this would be worthwhile.
165 *****************************************************************************/
168 * @addtogroup NET
169 * @{
172 /*****************************************************************************
174 * Include Files
176 ****************************************************************************/
178 #define _GNU_SOURCE 1
179 #include <stdarg.h> /*<- was <varargs.h>*/
181 #define CMK_USE_PRINTF_HACK 0
182 #if CMK_USE_PRINTF_HACK
183 /*HACK: turn printf into CmiPrintf, by just defining our own
184 external symbol "printf". This may be more trouble than it's worth,
185 since the only advantage is that it works properly with +syncprint.
187 This version *won't* work with fprintf(stdout,...) or C++ or Fortran I/O,
188 because they don't call printf. Has to be defined up here because we probably
189 haven't properly guessed this compiler's prototype for "printf".
191 static void InternalPrintf(const char *f, va_list l);
192 int printf(const char *fmt, ...) {
193 int nChar;
194 va_list p; va_start(p, fmt);
195 InternalPrintf(fmt,p);
196 va_end(p);
197 return 10;
199 #endif
202 #include "converse.h"
203 #include "memory-isomalloc.h"
205 #include <stdio.h>
206 #include <stdlib.h>
207 #include <ctype.h>
208 #include <fcntl.h>
209 #include <errno.h>
210 #include <setjmp.h>
211 #include <signal.h>
212 #include <string.h>
213 #include <unistd.h>
215 /* define machine debug */
216 #include "machine.h"
218 /******************* Producer-Consumer Queues ************************/
219 #include "pcqueue.h"
221 #include "machine-smp.h"
223 #include "machine-lrts.h"
224 #include "machine-common-core.c"
226 #if CMK_USE_KQUEUE
227 #include <sys/event.h>
228 int _kq = -1;
229 #endif
231 #if CMK_USE_POLL
232 #include <poll.h>
233 #endif
235 #include "conv-ccs.h"
236 #include "ccs-server.h"
237 #include "sockRoutines.h"
239 #if defined(_WIN32) && ! defined(__CYGWIN__)
240 /*For windows systems:*/
241 # include <windows.h>
242 # include <wincon.h>
243 # include <sys/types.h>
244 # include <sys/timeb.h>
245 # define fdopen _fdopen
246 # define SIGBUS -1 /*These signals don't exist in Win32*/
247 # define SIGKILL -1
248 # define SIGQUIT -1
249 /*# define SIGTERM -1*/ /* VC++ ver 8 now has SIGTERM */
251 #else /*UNIX*/
252 # include <pwd.h>
253 # include <unistd.h>
254 # include <fcntl.h>
255 # include <sys/file.h>
256 #endif
258 #if CMK_PERSISTENT_COMM
259 #include "machine-persistent.c"
260 #endif
262 #define PRINTBUFSIZE 16384
264 #ifdef __ONESIDED_IMPL
265 #ifdef __ONESIDED_NO_HARDWARE
266 int putSrcHandler;
267 int putDestHandler;
268 int getSrcHandler;
269 int getDestHandler;
270 #include "conv-onesided.c"
271 #endif
272 #endif
274 static void CommunicationServerNet(int withDelayMs, int where);
275 //static void CommunicationServer(int withDelayMs);
277 void CmiHandleImmediate();
278 extern int CmemInsideMem();
279 extern void CmemCallWhenMemAvail();
281 static unsigned int dataport=0;
282 static SOCKET dataskt;
284 extern void TokenUpdatePeriodic();
285 extern void getAvailSysMem();
287 static int Lrts_numNodes;
288 static int Lrts_myNode;
290 /****************************************************************************
292 * Handling Errors
294 * Errors should be handled by printing a message on stderr and
295 * calling exit(1). Nothing should be sent to charmrun, no attempt at
296 * communication should be made. The other processes will notice the
297 * abnormal termination and will deal with it.
299 * Rationale: if an error triggers an attempt to send a message,
300 * the attempt to send a message is likely to trigger another error,
301 * leading to an infinite loop and a process that spins instead of
302 * shutting down.
304 *****************************************************************************/
306 static int machine_initiated_shutdown=0;
307 static int already_in_signal_handler=0;
309 static void CmiDestroyLocks();
311 void MachineExit();
313 static void machine_exit(int status)
315 MACHSTATE(3," machine_exit");
316 machine_initiated_shutdown=1;
318 CmiDestroyLocks(); /* destroy locks to prevent dead locking */
319 EmergencyExit();
321 MachineExit();
322 exit(status);
325 static void charmrun_abort(const char*);
327 static void KillEveryone(const char *msg)
329 charmrun_abort(msg);
330 machine_exit(1);
333 static void KillEveryoneCode(n)
334 int n;
336 char _s[100];
337 sprintf(_s, "[%d] Fatal error #%d\n", CmiMyPe(), n);
338 charmrun_abort(_s);
339 machine_exit(1);
342 CpvExtern(int, freezeModeFlag);
344 static int Cmi_truecrash;
346 static void KillOnAllSigs(int sigNo)
348 const char *sig="unknown signal";
349 const char *suggestion="";
350 if (machine_initiated_shutdown ||
351 already_in_signal_handler)
352 machine_exit(1); /*Don't infinite loop if there's a signal during a signal handler-- just die.*/
353 already_in_signal_handler=1;
355 #if CMK_CCS_AVAILABLE
356 if (CpvAccess(cmiArgDebugFlag)) {
357 int reply = 0;
358 CpdNotify(CPD_SIGNAL,sigNo);
359 #if ! CMK_BIGSIM_CHARM
360 CcsSendReplyNoError(4,&reply);/*Send an empty reply if not*/
361 CpvAccess(freezeModeFlag) = 1;
362 CpdFreezeModeScheduler();
363 #else
364 CpdFreeze();
365 #endif
367 #endif
369 CmiDestroyLocks();
371 if (sigNo==SIGSEGV) {
372 sig="segmentation violation";
373 suggestion="Try running with '++debug', or linking with '-memory paranoid' (memory paranoid requires '+netpoll' at runtime).";
375 if (sigNo==SIGFPE) {
376 sig="floating point exception";
377 suggestion="Check for integer or floating-point division by zero.";
379 if (sigNo==SIGBUS) {
380 sig="bus error";
381 suggestion="Check for misaligned reads or writes to memory.";
383 if (sigNo==SIGILL) {
384 sig="illegal instruction";
385 suggestion="Check for calls to uninitialized function pointers.";
387 if (sigNo==SIGKILL) sig="caught signal KILL";
388 if (sigNo==SIGQUIT) sig="caught signal QUIT";
389 if (sigNo==SIGTERM) sig="caught signal TERM";
390 MACHSTATE1(5," Caught signal %s ",sig);
391 /*ifdef this part*/
392 #ifdef __FAULT__
393 if(sigNo == SIGKILL || sigNo == SIGQUIT || sigNo == SIGTERM){
394 CmiPrintf("[%d] Caught but ignoring signal\n",CmiMyPe());
395 } else
396 #endif
398 Cmi_truecrash = 0;
399 CmiAbortHelper("Caught Signal", sig, suggestion, 0, 1);
403 static void machine_atexit_check(void)
405 if (!machine_initiated_shutdown)
406 CmiAbort("unexpected call to exit by user program. Must use CkExit, not exit!");
407 #if 0 /*Wait for the user to press any key (for Win32 debugging)*/
408 fgetc(stdin);
409 #endif
412 #if !defined(_WIN32) || defined(__CYGWIN__)
413 static void HandleUserSignals(int signum)
415 int condnum = ((signum==SIGUSR1) ? CcdSIGUSR1 : CcdSIGUSR2);
416 CcdRaiseCondition(condnum);
418 #endif
420 /*****************************************************************************
422 * Utility routines for network machine interface.
424 *****************************************************************************/
427 Horrific #defines to hide the differences between select() and poll().
429 #if CMK_USE_POLL /*poll() version*/
430 # define CMK_PIPE_DECL(delayMs) \
431 struct pollfd fds[10]; \
432 int nFds_sto=0; int *nFds=&nFds_sto; \
433 int pollDelayMs=delayMs;
434 # define CMK_PIPE_SUB fds,nFds
435 # define CMK_PIPE_CALL() poll(fds, *nFds, pollDelayMs); *nFds=0
437 # define CMK_PIPE_PARAM struct pollfd *fds,int *nFds
438 # define CMK_PIPE_ADDREAD(rd_fd) \
439 do {fds[*nFds].fd=rd_fd; fds[*nFds].events=POLLIN; (*nFds)++;} while(0)
440 # define CMK_PIPE_ADDWRITE(wr_fd) \
441 do {fds[*nFds].fd=wr_fd; fds[*nFds].events=POLLOUT; (*nFds)++;} while(0)
442 # define CMK_PIPE_CHECKREAD(rd_fd) fds[(*nFds)++].revents&POLLIN
443 # define CMK_PIPE_CHECKWRITE(wr_fd) fds[(*nFds)++].revents&POLLOUT
445 #elif CMK_USE_KQUEUE /* kqueue version */
447 # define CMK_PIPE_DECL(delayMs) \
448 if (_kq == -1) _kq = kqueue(); \
449 struct kevent ke_sto; \
450 struct kevent* ke = &ke_sto; \
451 struct timespec tmo; \
452 tmo.tv_sec = 0; tmo.tv_nsec = delayMs*1e6;
453 # define CMK_PIPE_SUB ke
454 # define CMK_PIPE_CALL() kevent(_kq, NULL, 0, ke, 1, &tmo)
456 # define CMK_PIPE_PARAM struct kevent* ke
457 # define CMK_PIPE_ADDREAD(rd_fd) \
458 do { EV_SET(ke, rd_fd, EVFILT_READ, EV_ADD, 0, 10, NULL); \
459 kevent(_kq, ke, 1, NULL, 0, NULL); memset(ke, 0, sizeof(ke));} while(0)
460 # define CMK_PIPE_ADDWRITE(wr_fd) \
461 do { EV_SET(ke, wr_fd, EVFILT_WRITE, EV_ADD, 0, 10, NULL); \
462 kevent(_kq, ke, 1, NULL, 0, NULL); memset(ke, 0, sizeof(ke));} while(0)
463 # define CMK_PIPE_CHECKREAD(rd_fd) (ke->ident == rd_fd && ke->filter == EVFILT_READ)
464 # define CMK_PIPE_CHECKWRITE(wr_fd) (ke->ident == wr_fd && ke->filter == EVFILT_WRITE)
466 #else /*select() version*/
468 # define CMK_PIPE_DECL(delayMs) \
469 fd_set rfds_sto,wfds_sto;\
470 fd_set *rfds=&rfds_sto,*wfds=&wfds_sto; struct timeval tmo; \
471 FD_ZERO(rfds); FD_ZERO(wfds);tmo.tv_sec=0; tmo.tv_usec=1000*delayMs;
472 # define CMK_PIPE_SUB rfds,wfds
473 # define CMK_PIPE_CALL() select(FD_SETSIZE, rfds, wfds, NULL, &tmo)
475 # define CMK_PIPE_PARAM fd_set *rfds,fd_set *wfds
476 # define CMK_PIPE_ADDREAD(rd_fd) FD_SET(rd_fd,rfds)
477 # define CMK_PIPE_ADDWRITE(wr_fd) FD_SET(wr_fd,wfds)
478 # define CMK_PIPE_CHECKREAD(rd_fd) FD_ISSET(rd_fd,rfds)
479 # define CMK_PIPE_CHECKWRITE(wr_fd) FD_ISSET(wr_fd,wfds)
480 #endif
482 static void CMK_PIPE_CHECKERR(void) {
483 #if defined(_WIN32) && !defined(__CYGWIN__)
484 /* Win32 socket seems to randomly return inexplicable errors
485 here-- WSAEINVAL, WSAENOTSOCK-- yet everything is actually OK.
486 int err=WSAGetLastError();
487 CmiPrintf("(%d)Select returns -1; errno=%d, WSAerr=%d\n",withDelayMs,errn
488 o,err);
490 #else /*UNIX machine*/
491 if (errno!=EINTR)
492 KillEveryone("Socket error in CheckSocketsReady!\n");
493 #endif
497 static void CmiStdoutFlush(void);
498 static int CmiStdoutNeedsService(void);
499 static void CmiStdoutService(void);
500 static void CmiStdoutAdd(CMK_PIPE_PARAM);
501 static void CmiStdoutCheck(CMK_PIPE_PARAM);
504 double GetClock(void)
506 #if defined(_WIN32) && !defined(__CYGWIN__)
507 struct _timeb tv;
508 _ftime(&tv);
509 return (tv.time * 1.0 + tv.millitm * 1.0E-3);
510 #else
511 struct timeval tv; int ok;
512 ok = gettimeofday(&tv, NULL);
513 if (ok<0) { perror("gettimeofday"); KillEveryoneCode(9343112); }
514 return (tv.tv_sec * 1.0 + tv.tv_usec * 1.0E-6);
515 #endif
519 /***********************************************************************
521 * Abort function:
523 ************************************************************************/
525 static int already_aborting=0;
526 void LrtsAbort(const char *message)
528 if (already_aborting) machine_exit(1);
529 already_aborting=1;
530 MACHSTATE1(5,"CmiAbort(%s)",message);
532 /*Send off any remaining prints*/
533 CmiStdoutFlush();
535 if(Cmi_truecrash) {
536 printf("CHARM++ FATAL ERROR: %s\n", message);
537 *(int *)NULL = 0; /*Write to null, causing bus error*/
538 } else {
539 charmrun_abort(message);
540 machine_exit(1);
545 /******************************************************************************
547 * CmiEnableAsyncIO
549 * The net and tcp versions use a bunch of unix processes talking to each
550 * other via file descriptors. We need for a signal SIGIO to be generated
551 * each time a message arrives, making it possible to write a signal
552 * handler to handle the messages. The vast majority of unixes can,
553 * in fact, do this. However, there isn't any standard for how this is
554 * supposed to be done, so each version of UNIX has a different set of
555 * calls to turn this signal on. So, there is like one version here for
556 * every major brand of UNIX.
558 *****************************************************************************/
560 #if CMK_ASYNC_USE_F_SETFL_AND_F_SETOWN
561 #include <fcntl.h>
562 void CmiEnableAsyncIO(int fd)
564 if ( fcntl(fd, F_SETOWN, getpid()) < 0 ) {
565 CmiError("setting socket owner: %s\n", strerror(errno)) ;
566 exit(1);
568 if ( fcntl(fd, F_SETFL, O_ASYNC) < 0 ) {
569 CmiError("setting socket async: %s\n", strerror(errno)) ;
570 exit(1);
573 #else
574 void CmiEnableAsyncIO(int fd) { }
575 #endif
577 /* We should probably have a set of "CMK_NONBLOCK_USE_..." defines here:*/
578 #if !defined(_WIN32) || defined(__CYGWIN__)
579 void CmiEnableNonblockingIO(int fd) {
580 int on=1;
581 if (fcntl(fd,F_SETFL,O_NONBLOCK,&on)<0) {
582 CmiError("setting nonblocking IO: %s\n", strerror(errno)) ;
583 exit(1);
586 #else
587 void CmiEnableNonblockingIO(int fd) { }
588 #endif
591 /******************************************************************************
593 * Configuration Data
595 * This data is all read in from the NETSTART variable (provided by the
596 * charmrun) and from the command-line arguments. Once read in, it is never
597 * modified.
599 *****************************************************************************/
601 static skt_ip_t Cmi_self_IP;
602 static skt_ip_t Cmi_charmrun_IP; /*Address of charmrun machine*/
603 static int Cmi_charmrun_port;
604 static int Cmi_charmrun_pid;
605 static int Cmi_charmrun_fd=-1;
606 /* Magic number to be used for sanity check in messege header */
607 static int Cmi_net_magic;
609 static int Cmi_netpoll;
610 static int Cmi_asyncio;
611 static int Cmi_idlepoll;
612 static int Cmi_syncprint;
613 static int Cmi_print_stats = 0;
615 #if ! defined(_WIN32)
616 /* parse forks only used in non-smp mode */
617 static void parse_forks(void) {
618 char *forkstr;
619 int nread;
620 int forks;
621 int i,pid;
622 forkstr=getenv("CmiMyForks");
623 if(forkstr!=0) { /* charmrun */
624 nread = sscanf(forkstr,"%d",&forks);
625 for(i=1;i<=forks;i++) { /* by default forks = 0 */
626 pid=fork();
627 if(pid<0) CmiAbort("Fork returned an error");
628 if(pid==0) { /* forked process */
629 /* reset mynode,pe & exit loop */
630 Lrts_myNode+=i;
631 #if ! CMK_SMP
632 _Cmi_mype+=i;
633 #endif
634 break;
639 #endif
640 static void parse_magic(void)
642 char* nm;
643 int nread;
644 nm = getenv("NETMAGIC");
645 if (nm!=0)
646 {/*Read values set by Charmrun*/
647 nread = sscanf(nm, "%d",&Cmi_net_magic);
650 static void parse_netstart(void)
652 char *ns;
653 int nread;
654 int port;
655 ns = getenv("NETSTART");
656 if (ns!=0)
657 {/*Read values set by Charmrun*/
658 char Cmi_charmrun_name[1024];
659 nread = sscanf(ns, "%d%s%d%d%d",
660 &Lrts_myNode,
661 Cmi_charmrun_name, &Cmi_charmrun_port,
662 &Cmi_charmrun_pid, &port);
663 Cmi_charmrun_IP=skt_lookup_ip(Cmi_charmrun_name);
665 if (nread!=5) {
666 fprintf(stderr,"Error parsing NETSTART '%s'\n",ns);
667 exit(1);
669 } else
670 {/*No charmrun-- set flag values for standalone operation*/
671 Lrts_myNode=0;
672 Cmi_charmrun_IP=_skt_invalid_ip;
673 Cmi_charmrun_port=0;
674 Cmi_charmrun_pid=0;
675 dataport = -1;
676 #if CMK_USE_PXSHM
677 CmiAbort("pxshm must be run with charmrun");
678 #endif
682 static void extract_common_args(char **argv)
684 if (CmiGetArgFlagDesc(argv,"+stats","Print network statistics at shutdown"))
685 Cmi_print_stats = 1;
689 /******************************************************************************
691 * Packet Performance Logging
693 * This module is designed to give a detailed log of the packets and their
694 * acknowledgements, for performance tuning. It can be disabled.
696 *****************************************************************************/
698 #define LOGGING 0
700 #if LOGGING
702 typedef struct logent {
703 double time;
704 int seqno;
705 int srcpe;
706 int dstpe;
707 int kind;
708 } *logent;
711 logent log;
712 int log_pos;
713 int log_wrap;
715 static void log_init(void)
717 log = (logent)malloc(50000 * sizeof(struct logent));
718 _MEMCHECK(log);
719 log_pos = 0;
720 log_wrap = 0;
723 static void log_done(void)
725 char logname[100]; FILE *f; int i, size;
726 sprintf(logname, "log.%d", Lrts_myNode);
727 f = fopen(logname, "w");
728 if (f==0) KillEveryone("fopen problem");
729 if (log_wrap) size = 50000; else size=log_pos;
730 for (i=0; i<size; i++) {
731 logent ent = log+i;
732 fprintf(f, "%1.4f %d %c %d %d\n",
733 ent->time, ent->srcpe, ent->kind, ent->dstpe, ent->seqno);
735 fclose(f);
738 void printLog(void)
740 char logname[100]; FILE *f; int i, j, size;
741 static int logged = 0;
742 if (logged)
743 return;
744 logged = 1;
745 CmiPrintf("Logging: %d\n", Lrts_myNode);
746 sprintf(logname, "log.%d", Lrts_myNode);
747 f = fopen(logname, "w");
748 if (f==0) KillEveryone("fopen problem");
749 for (i = 5000; i; i--)
751 /*for (i=0; i<size; i++) */
752 j = log_pos - i;
753 if (j < 0)
755 if (log_wrap)
756 j = 5000 + j;
757 else
758 j = 0;
761 logent ent = log+j;
762 fprintf(f, "%1.4f %d %c %d %d\n",
763 ent->time, ent->srcpe, ent->kind, ent->dstpe, ent->seqno);
766 fclose(f);
767 CmiPrintf("Done Logging: %d\n", Lrts_myNode);
770 #define LOG(t,s,k,d,q) { if (log_pos==50000) { log_pos=0; log_wrap=1;} { logent ent=log+log_pos; ent->time=t; ent->srcpe=s; ent->kind=k; ent->dstpe=d; ent->seqno=q; log_pos++; }}
772 #endif
774 #if !LOGGING
776 #define log_init() /*empty*/
777 #define log_done() /*empty*/
778 #define printLog() /*empty*/
779 #define LOG(t,s,k,d,q) /*empty*/
781 #endif
783 /******************************************************************************
785 * Node state
787 *****************************************************************************/
790 static CmiNodeLock Cmi_scanf_mutex;
791 static double Cmi_clock;
792 static double Cmi_check_delay = 3.0;
794 /******************************************************************************
796 * OS Threads
797 * SMP implementation moved to machine-smp.c
798 *****************************************************************************/
799 int inProgress[128];
801 /** Mechanism to prevent dual locking when comm-layer functions, including prints,
802 * are called recursively. (UN)LOCK_IF_AVAILABLE is used before and after a code piece
803 * which is guaranteed not to make any-recursive locking calls. (UN)LOCK_AND_(UN)SET
804 * is used before and after a code piece that may make recursive locking calls.
807 #define LOCK_IF_AVAILABLE() \
808 if(!inProgress[CmiMyRank()]) { \
809 CmiCommLock(); \
812 #define UNLOCK_IF_AVAILABLE() \
813 if(!inProgress[CmiMyRank()]) { \
814 CmiCommUnlock(); \
817 #define LOCK_AND_SET() \
818 if(!inProgress[CmiMyRank()]) { \
819 CmiCommLock(); \
820 acqLock = 1; \
822 inProgress[CmiMyRank()] += 1;
824 #define UNLOCK_AND_UNSET() \
825 if(acqLock) { \
826 CmiCommUnlock(); \
827 acqLock = 0; \
829 inProgress[CmiMyRank()] -= 1;
831 /************************ No kernel SMP threads ***************/
832 //XX
833 #if CMK_SHARED_VARS_UNAVAILABLE
835 static volatile int memflag=0;
836 void CmiMemLockNet() { memflag++; }
837 void CmiMemUnlockNet() { memflag--; }
839 static volatile int comm_flag=0;
840 #define CmiCommLockOrElse(dothis) if (comm_flag!=0) dothis
841 #ifndef MACHLOCK_DEBUG
842 # define CmiCommLock() (comm_flag=1)
843 # define CmiCommUnlock() (comm_flag=0)
844 #else /* Error-checking flag locks */
845 void CmiCommLock(void) {
846 MACHLOCK_ASSERT(!comm_flag,"CmiCommLock");
847 comm_flag=1;
849 void CmiCommUnlock(void) {
850 MACHLOCK_ASSERT(comm_flag,"CmiCommUnlock");
851 comm_flag=0;
853 #endif
855 //int _Cmi_myrank=0; /* Normally zero; only 1 during SIGIO handling */
856 _Cmi_myrank=0;
858 static void CommunicationInterrupt(int ignored)
860 MACHLOCK_ASSERT(!_Cmi_myrank,"CommunicationInterrupt");
861 if (memflag || comm_flag || _immRunning || CmiCheckImmediateLock(0))
862 { /* Already busy inside malloc, comm, or immediate messages */
863 MACHSTATE(5,"--SKIPPING SIGIO--");
864 return;
866 MACHSTATE1(2,"--BEGIN SIGIO comm_mutex_isLocked: %d--", comm_flag)
868 /*Make sure any malloc's we do in here are NOT migratable:*/
869 CmiIsomallocBlockList *oldList=CmiIsomallocBlockListActivate(NULL);
870 /* _Cmi_myrank=1; */
871 CommunicationServerNet(0, COMM_SERVER_FROM_INTERRUPT); /* from interrupt */
872 //CommunicationServer(0); /* from interrupt */
873 /* _Cmi_myrank=0; */
874 CmiIsomallocBlockListActivate(oldList);
876 MACHSTATE(2,"--END SIGIO--")
879 extern void CmiSignal(int sig1, int sig2, int sig3, void (*handler)());
881 static void CmiDestroyLocks()
883 comm_flag = 0;
884 memflag = 0;
887 #endif
889 CpvExtern(int,_charmEpoch);
891 /*Add a message to this processor's receive queue
892 Must be called while holding comm. lock
895 extern double evacTime;
898 /***************************************************************
899 Communication with charmrun:
900 We can send (ctrl_sendone) and receive (ctrl_getone)
901 messages on a TCP socket connected to charmrun.
902 This is used for printfs, CCS, etc; and also for
903 killing ourselves if charmrun dies.
906 /*This flag prevents simultanious outgoing
907 messages on the charmrun socket. It is protected
908 by the commlock.*/
909 static int Cmi_charmrun_fd_sendflag=0;
911 /* ctrl_sendone */
912 static int sendone_abort_fn(int code,const char *msg) {
913 fprintf(stderr,"Socket error %d in ctrl_sendone! %s\n",code,msg);
914 machine_exit(1);
915 return -1;
918 static void ctrl_sendone_nolock(const char *type,
919 const char *data1,int dataLen1,
920 const char *data2,int dataLen2)
922 const void *bufs[3]; int lens[3]; int nBuffers=0;
923 ChMessageHeader hdr;
924 skt_abortFn oldAbort=skt_set_abort(sendone_abort_fn);
925 MACHSTATE1(2,"ctrl_sendone_nolock { type=%s", type);
926 if (Cmi_charmrun_fd==-1)
927 charmrun_abort("ctrl_sendone called in standalone!\n");
928 Cmi_charmrun_fd_sendflag=1;
929 ChMessageHeader_new(type,dataLen1+dataLen2,&hdr);
930 bufs[nBuffers]=&hdr; lens[nBuffers]=sizeof(hdr); nBuffers++;
931 if (dataLen1>0) {bufs[nBuffers]=data1; lens[nBuffers]=dataLen1; nBuffers++;}
932 if (dataLen2>0) {bufs[nBuffers]=data2; lens[nBuffers]=dataLen2; nBuffers++;}
933 skt_sendV(Cmi_charmrun_fd,nBuffers,bufs,lens);
934 Cmi_charmrun_fd_sendflag=0;
935 skt_set_abort(oldAbort);
936 MACHSTATE(2,"} ctrl_sendone_nolock");
939 static void ctrl_sendone_locking(const char *type,
940 const char *data1,int dataLen1,
941 const char *data2,int dataLen2)
943 LOCK_IF_AVAILABLE();
944 ctrl_sendone_nolock(type,data1,dataLen1,data2,dataLen2);
945 UNLOCK_IF_AVAILABLE();
948 #ifndef MEMORYUSAGE_OUTPUT
949 #define MEMORYUSAGE_OUTPUT 0
950 #endif
951 #if MEMORYUSAGE_OUTPUT
952 #define MEMORYUSAGE_OUTPUT_FREQ 10 //how many prints in a second
953 static int memoryusage_counter;
954 #define memoryusage_isOutput ((memoryusage_counter%MEMORYUSAGE_OUTPUT_FREQ)==0)
955 #define memoryusage_output {\
956 memoryusage_counter++;\
957 if(CmiMyPe()==0) printf("-- %d %f %ld --\n", CmiMyPe(), GetClock(), CmiMemoryUsage());}
958 #endif
960 static double Cmi_check_last;
962 /* if charmrun dies, we finish */
963 static void pingCharmrun(void *ignored)
965 #if MEMORYUSAGE_OUTPUT
966 memoryusage_output;
967 if(memoryusage_isOutput){
968 memoryusage_counter = 0;
969 #else
971 #endif
973 double clock=GetClock();
974 if (clock > Cmi_check_last + Cmi_check_delay) {
975 MACHSTATE1(3,"CommunicationsClock pinging charmrun Cmi_charmrun_fd_sendflag=%d", Cmi_charmrun_fd_sendflag);
976 Cmi_check_last = clock;
977 CmiCommLockOrElse(return;); /*Already busy doing communication*/
978 if (Cmi_charmrun_fd_sendflag) return; /*Busy talking to charmrun*/
979 LOCK_IF_AVAILABLE();
980 ctrl_sendone_nolock("ping",NULL,0,NULL,0); /*Charmrun may have died*/
981 UNLOCK_IF_AVAILABLE();
983 CmiStdoutFlush(); /*Make sure stdout buffer hasn't filled up*/
987 /* periodic charm ping, for netpoll */
988 static void pingCharmrunPeriodic(void *ignored)
990 pingCharmrun(ignored);
991 CcdCallFnAfter((CcdVoidFn)pingCharmrunPeriodic,NULL,1000);
994 static int ignore_further_errors(int c,const char *msg) {machine_exit(2);return -1;}
995 static void charmrun_abort(const char *s)
997 if (Cmi_charmrun_fd==-1) {/*Standalone*/
998 fprintf(stderr,"Charm++ fatal error:\n%s\n",s);
999 CmiPrintStackTrace(0);
1000 abort();
1001 } else {
1002 char msgBuf[80];
1003 skt_set_abort(ignore_further_errors);
1004 if (CmiNumPartitions() == 1) {
1005 sprintf(msgBuf,"Fatal error on PE %d> ",CmiMyPe());
1007 else
1009 sprintf(msgBuf,"Fatal error on Partition %d PE %d> ", CmiMyPartition(), CmiMyPe());
1011 ctrl_sendone_nolock("abort",msgBuf,strlen(msgBuf),s,strlen(s)+1);
1015 /* ctrl_getone */
1017 #ifdef __FAULT__
1018 #include "machine-recover.c"
1019 #endif
1021 static void node_addresses_store(ChMessage *msg);
1023 static int barrierReceived = 0;
1025 static void ctrl_getone(void)
1027 ChMessage msg;
1028 MACHSTATE(2,"ctrl_getone")
1029 MACHLOCK_ASSERT(comm_mutex_isLocked,"ctrl_getone")
1030 ChMessage_recv(Cmi_charmrun_fd,&msg);
1031 MACHSTATE1(2,"ctrl_getone recv one '%s'", msg.header.type);
1033 if (strcmp(msg.header.type,"die")==0) {
1034 MACHSTATE(2,"ctrl_getone bye bye")
1035 fprintf(stderr,"aborting: %s\n",msg.data);
1036 log_done();
1037 ConverseCommonExit();
1038 machine_exit(0);
1040 #if CMK_CCS_AVAILABLE
1041 else if (strcmp(msg.header.type, "req_fw")==0) {
1042 CcsImplHeader *hdr=(CcsImplHeader *)msg.data;
1043 /*Sadly, I *can't* do a:
1044 CcsImpl_netRequest(hdr,msg.data+sizeof(CcsImplHeader));
1045 here, because I can't send converse messages in the
1046 communication thread. I *can* poke this message into
1047 any convenient processor's queue, though: (OSL, 9/14/2000)
1049 int pe=0;/*<- node-local processor number. Any one will do.*/
1050 void *cmsg=(void *)CcsImpl_ccs2converse(hdr,msg.data+sizeof(CcsImplHeader),NULL);
1051 MACHSTATE(2,"Incoming CCS request");
1052 if (cmsg!=NULL) CmiPushPE(pe,cmsg);
1054 #endif
1055 #ifdef __FAULT__
1056 else if(strcmp(msg.header.type,"crashnode")==0) {
1057 crash_node_handle(&msg);
1059 else if(strcmp(msg.header.type,"initnodetab")==0) {
1060 /** A processor crashed and got recreated. So charmrun sent
1061 across the whole nodetable data to update this processor*/
1062 node_addresses_store(&msg);
1063 // fprintf(stdout,"nodetable added %d\n",CmiMyPe());
1065 #endif
1066 else if(strcmp(msg.header.type,"barrier")==0) {
1067 barrierReceived = 1;
1069 else if(strcmp(msg.header.type,"barrier0")==0) {
1070 barrierReceived = 2;
1072 else {
1073 /* We do not use KillEveryOne here because it calls CmiMyPe(),
1074 * which is not available to the communication thread on an SMP version.
1076 /* CmiPrintf("Unknown message: %s\n", msg.header.type); */
1077 charmrun_abort("ERROR> Unrecognized message from charmrun.\n");
1078 machine_exit(1);
1081 MACHSTATE(2,"ctrl_getone done")
1082 ChMessage_free(&msg);
1085 #if CMK_CCS_AVAILABLE && !NODE_0_IS_CONVHOST
1086 /*Deliver this reply data to this reply socket.
1087 The data is forwarded to CCS server via charmrun.*/
1088 void CcsImpl_reply(CcsImplHeader *hdr,int repLen,const void *repData)
1090 MACHSTATE(2,"Outgoing CCS reply");
1091 ctrl_sendone_locking("reply_fw",(const char *)hdr,sizeof(CcsImplHeader),
1092 repData,repLen);
1093 MACHSTATE(1,"Outgoing CCS reply away");
1095 #endif
1097 /*****************************************************************************
1099 * CmiPrintf, CmiError, CmiScanf
1101 *****************************************************************************/
1102 static void InternalWriteToTerminal(int isStdErr,const char *str,int len);
1103 static void InternalPrintf(const char *f, va_list l)
1105 ChMessage replymsg;
1106 char *buffer = CmiTmpAlloc(PRINTBUFSIZE);
1107 CmiStdoutFlush();
1108 vsprintf(buffer, f, l);
1109 if(Cmi_syncprint) {
1110 LOCK_IF_AVAILABLE();
1111 ctrl_sendone_nolock("printsyn", buffer,strlen(buffer)+1,NULL,0);
1112 ChMessage_recv(Cmi_charmrun_fd,&replymsg);
1113 ChMessage_free(&replymsg);
1114 UNLOCK_IF_AVAILABLE();
1115 } else {
1116 ctrl_sendone_locking("print", buffer,strlen(buffer)+1,NULL,0);
1118 InternalWriteToTerminal(0,buffer,strlen(buffer));
1119 CmiTmpFree(buffer);
1122 static void InternalError(const char *f, va_list l)
1124 ChMessage replymsg;
1125 char *buffer = CmiTmpAlloc(PRINTBUFSIZE);
1126 CmiStdoutFlush();
1127 vsprintf(buffer, f, l);
1128 if(Cmi_syncprint) {
1129 ctrl_sendone_locking("printerrsyn", buffer,strlen(buffer)+1,NULL,0);
1130 LOCK_IF_AVAILABLE();
1131 ChMessage_recv(Cmi_charmrun_fd,&replymsg);
1132 ChMessage_free(&replymsg);
1133 UNLOCK_IF_AVAILABLE();
1134 } else {
1135 ctrl_sendone_locking("printerr", buffer,strlen(buffer)+1,NULL,0);
1137 InternalWriteToTerminal(1,buffer,strlen(buffer));
1138 CmiTmpFree(buffer);
1141 static int InternalScanf(char *fmt, va_list l)
1143 ChMessage replymsg;
1144 char *ptr[20];
1145 char *p; int nargs, i;
1146 nargs=0;
1147 p=fmt;
1148 while (*p) {
1149 if ((p[0]=='%')&&(p[1]=='*')) { p+=2; continue; }
1150 if ((p[0]=='%')&&(p[1]=='%')) { p+=2; continue; }
1151 if (p[0]=='%') { nargs++; p++; continue; }
1152 if (*p=='\n') *p=' '; p++;
1154 if (nargs > 18) KillEveryone("CmiScanf only does 18 args.\n");
1155 for (i=0; i<nargs; i++) ptr[i]=va_arg(l, char *);
1156 CmiLock(Cmi_scanf_mutex);
1157 if (Cmi_charmrun_fd!=-1)
1158 {/*Send charmrun the format string*/
1159 ctrl_sendone_locking("scanf", fmt, strlen(fmt)+1,NULL,0);
1160 /*Wait for the reply (characters to scan) from charmrun*/
1161 LOCK_IF_AVAILABLE();
1162 ChMessage_recv(Cmi_charmrun_fd,&replymsg);
1163 i = sscanf((char*)replymsg.data, fmt,
1164 ptr[ 0], ptr[ 1], ptr[ 2], ptr[ 3], ptr[ 4], ptr[ 5],
1165 ptr[ 6], ptr[ 7], ptr[ 8], ptr[ 9], ptr[10], ptr[11],
1166 ptr[12], ptr[13], ptr[14], ptr[15], ptr[16], ptr[17]);
1167 ChMessage_free(&replymsg);
1168 UNLOCK_IF_AVAILABLE();
1169 } else
1170 {/*Just do the scanf normally*/
1171 i=scanf(fmt, ptr[ 0], ptr[ 1], ptr[ 2], ptr[ 3], ptr[ 4], ptr[ 5],
1172 ptr[ 6], ptr[ 7], ptr[ 8], ptr[ 9], ptr[10], ptr[11],
1173 ptr[12], ptr[13], ptr[14], ptr[15], ptr[16], ptr[17]);
1175 CmiUnlock(Cmi_scanf_mutex);
1176 return i;
1178 #if CMK_CMIPRINTF_IS_A_BUILTIN
1180 /*New stdarg.h declarations*/
1181 void CmiPrintf(const char *fmt, ...)
1183 CpdSystemEnter();
1185 va_list p; va_start(p, fmt);
1186 if (Cmi_charmrun_fd!=-1 && _writeToStdout)
1187 InternalPrintf(fmt, p);
1188 else
1189 vfprintf(stdout,fmt,p);
1190 va_end(p);
1192 CpdSystemExit();
1195 void CmiError(const char *fmt, ...)
1197 CpdSystemEnter();
1199 va_list p; va_start (p, fmt);
1200 if (Cmi_charmrun_fd!=-1)
1201 InternalError(fmt, p);
1202 else
1203 vfprintf(stderr,fmt,p);
1204 va_end(p);
1206 CpdSystemExit();
1209 int CmiScanf(const char *fmt, ...)
1211 int i;
1212 CpdSystemEnter();
1214 va_list p; va_start(p, fmt);
1215 i = InternalScanf((char *)fmt, p);
1216 va_end(p);
1218 CpdSystemExit();
1219 return i;
1222 #endif
1224 /***************************************************************************
1225 * Output redirection:
1226 * When people don't use CkPrintf, like above, we'd still like to be able
1227 * to collect their output. Thus we make a pipe and dup2 it to stdout,
1228 * which lets us read the characters sent to stdout at our lesiure.
1229 ***************************************************************************/
1231 /*Can read from stdout or stderr using these fd's*/
1232 static int readStdout[2];
1233 static int writeStdout[2]; /*The original stdout/stderr sockets*/
1234 static int serviceStdout[2]; /*(bool) Normally zero; one if service needed.*/
1235 #define readStdoutBufLen (16*1024)
1236 static char readStdoutBuf[readStdoutBufLen+1]; /*Protected by comm. lock*/
1237 static int servicingStdout;
1239 /*Initialization-- should only be called once per node*/
1240 static void CmiStdoutInit(void) {
1241 int i;
1242 if (Cmi_charmrun_fd==-1) return; /* standalone mode */
1244 /*There's some way to do this same thing in windows, but I don't know how*/
1245 #if !defined(_WIN32) || defined(__CYGWIN__)
1246 /*Prevent buffering in stdio library:*/
1247 setbuf(stdout,NULL); setbuf(stderr,NULL);
1249 /*Reopen stdout and stderr fd's as new pipes:*/
1250 for (i=0;i<2;i++) {
1251 int pair[2];
1252 int srcFd=1+i; /* 1 is stdout; 2 is stderr */
1254 /*First, save a copy of the original stdout*/
1255 writeStdout[i]=dup(srcFd);
1256 #if 0
1257 /*Build a pipe to connect to stdout (4kb buffer, but no SIGIO...)*/
1258 if (-1==pipe(pair)) {perror("building stdio redirection pipe"); exit(1);}
1259 #else
1260 /* UNIX socket (16kb default buffer, and works with SIGIO!) */
1261 if (-1==socketpair(PF_UNIX,SOCK_STREAM,0,pair))
1262 {perror("building stdio redirection socketpair"); exit(1);}
1263 #endif
1264 readStdout[i]=pair[0]; /*We get the read end of pipe*/
1265 if (-1==dup2(pair[1],srcFd)) {perror("dup2 redirection pipe"); exit(1);}
1266 //if (-1==dup2(srcFd,pair[1])) {perror("dup2 redirection pipe"); exit(1);}
1268 #if 0 /*Keep writes from blocking. This just drops excess output, which is bad.*/
1269 CmiEnableNonblockingIO(srcFd);
1270 #endif
1271 #if CMK_SHARED_VARS_UNAVAILABLE
1272 if (Cmi_asyncio)
1274 /*No communication thread-- get a SIGIO on each write(), which keeps the buffer clean*/
1275 CmiEnableAsyncIO(pair[1]);
1277 #endif
1279 #else
1280 /*Windows system-- just fake reads for now*/
1281 # ifndef read
1282 # define read(x,y,z) 0
1283 # endif
1284 # ifndef write
1285 # define write(x,y,z)
1286 # endif
1287 #endif
1290 /*Sends data to original stdout (e.g., for ++debug or ++in-xterm)*/
1291 static void InternalWriteToTerminal(int isStdErr,const char *str,int len)
1293 write(writeStdout[isStdErr],str,len);
1297 Service this particular stdout pipe.
1298 Must hold comm. lock.
1300 static void CmiStdoutServiceOne(int i) {
1301 int nBytes;
1302 const static char *cmdName[2]={"print","printerr"};
1303 servicingStdout=1;
1304 while(1) {
1305 const char *tooMuchWarn=NULL; int tooMuchLen=0;
1306 if (!skt_select1(readStdout[i],0)) break; /*Nothing to read*/
1307 nBytes=read(readStdout[i],readStdoutBuf,readStdoutBufLen);
1308 if (nBytes<=0) break; /*Nothing to send*/
1310 /*Send these bytes off to charmrun*/
1311 readStdoutBuf[nBytes]=0; /*Zero-terminate read string*/
1312 nBytes++; /*Include zero-terminator in message to charmrun*/
1314 if (nBytes>=readStdoutBufLen-100)
1315 { /*We must have filled up our output pipe-- most output libraries
1316 don't handle this well (e.g., glibc printf just drops the line).*/
1318 tooMuchWarn="\nWARNING: Too much output at once-- possible output discontinuity!\n"
1319 "Use CkPrintf to avoid discontinuity (and this warning).\n\n";
1320 nBytes--; /*Remove terminator from user's data*/
1321 tooMuchLen=strlen(tooMuchWarn)+1;
1323 ctrl_sendone_nolock(cmdName[i],readStdoutBuf,nBytes,
1324 tooMuchWarn,tooMuchLen);
1326 InternalWriteToTerminal(i,readStdoutBuf,nBytes);
1328 servicingStdout=0;
1329 serviceStdout[i]=0; /*This pipe is now serviced*/
1332 /*Service all stdout pipes, whether it looks like they need it
1333 or not. Used when you aren't sure if select() has been called recently.
1334 Must hold comm. lock.
1336 static void CmiStdoutServiceAll(void) {
1337 int i;
1338 for (i=0;i<2;i++) {
1339 if (readStdout[i]==0) continue; /*Pipe not open*/
1340 CmiStdoutServiceOne(i);
1344 /*Service any outstanding stdout pipes.
1345 Must hold comm. lock.
1347 static void CmiStdoutService(void) {
1348 CmiStdoutServiceAll();
1351 /*Add our pipes to the pile for select() or poll().
1352 Both can be called with or without the comm. lock.
1354 static void CmiStdoutAdd(CMK_PIPE_PARAM) {
1355 int i;
1356 for (i=0;i<2;i++) {
1357 if (readStdout[i]==0) continue; /*Pipe not open*/
1358 CMK_PIPE_ADDREAD(readStdout[i]);
1361 static void CmiStdoutCheck(CMK_PIPE_PARAM) {
1362 int i;
1363 for (i=0;i<2;i++) {
1364 if (readStdout[i]==0) continue; /*Pipe not open*/
1365 if (CMK_PIPE_CHECKREAD(readStdout[i])) serviceStdout[i]=1;
1368 static int CmiStdoutNeedsService(void) {
1369 return (serviceStdout[0]!=0 || serviceStdout[1]!=0);
1372 /*Called every few milliseconds to flush the stdout pipes*/
1373 static void CmiStdoutFlush(void) {
1374 if (servicingStdout) return; /* might be called by SIGALRM */
1375 CmiCommLockOrElse( return; )
1376 LOCK_IF_AVAILABLE();
1377 CmiStdoutServiceAll();
1378 UNLOCK_IF_AVAILABLE();
1381 /***************************************************************************
1382 * Message Delivery:
1384 ***************************************************************************/
1386 #include "machine-dgram.c"
1389 /*****************************************************************************
1391 * node_addresses
1393 * These two functions fill the node-table.
1396 * This node, like all others, first sends its own address to charmrun
1397 * using this command:
1399 * Type: nodeinfo
1400 * Data: Big-endian 4-byte ints
1401 * <my-node #><Dataport>
1403 * When charmrun has all the addresses, he sends this table to me:
1405 * Type: nodes
1406 * Data: Big-endian 4-byte ints
1407 * <number of nodes n>
1408 * <#PEs><IP><Dataport> Node 0
1409 * <#PEs><IP><Dataport> Node 1
1410 * ...
1411 * <#PEs><IP><Dataport> Node n-1
1413 *****************************************************************************/
1415 /*Note: node_addresses_obtain is called before starting
1416 threads, so no locks are needed (or valid!)*/
1417 static void node_addresses_obtain(char **argv)
1419 ChMessage nodetabmsg; /* info about all nodes*/
1420 MACHSTATE(3,"node_addresses_obtain { ");
1421 if (Cmi_charmrun_fd==-1)
1422 {/*Standalone-- fake a single-node nodetab message*/
1423 int npes=1;
1424 ChSingleNodeinfo *fakeTab;
1425 ChMessage_new("nodeinfo",sizeof(ChSingleNodeinfo),&nodetabmsg);
1426 fakeTab=(ChSingleNodeinfo *)(nodetabmsg.data);
1427 CmiGetArgIntDesc(argv,"+p",&npes,"Set the number of processes to create");
1428 #if CMK_SHARED_VARS_UNAVAILABLE
1429 if (npes!=1) {
1430 fprintf(stderr,
1431 "To use multiple processors, you must run this program as:\n"
1432 " > charmrun +p%d %s <args>\n"
1433 "or build the %s-smp version of Charm++.\n",
1434 npes,argv[0],CMK_MACHINE_NAME);
1435 exit(1);
1437 #else
1438 /* standalone smp version reads ppn */
1439 if (CmiGetArgInt(argv, "+ppn", &_Cmi_mynodesize) ||
1440 CmiGetArgInt(argv, "++ppn", &_Cmi_mynodesize) )
1441 npes = _Cmi_mynodesize;
1442 #endif
1443 /*This is a stupid hack: we expect the *number* of nodes
1444 followed by ChNodeinfo structs; so we use a ChSingleNodeinfo
1445 (which happens to have exactly that layout!) and stuff
1446 a 1 into the "node number" slot
1448 fakeTab->nodeNo=ChMessageInt_new(1); /* <- hack */
1449 fakeTab->info.nPE=ChMessageInt_new(npes);
1450 fakeTab->info.dataport=ChMessageInt_new(0);
1451 fakeTab->info.IP=_skt_invalid_ip;
1453 else
1454 { /*Contact charmrun for machine info.*/
1455 ChSingleNodeinfo me;
1457 me.nodeNo=ChMessageInt_new(Lrts_myNode);
1459 /*The nPE fields are set by charmrun--
1460 these values don't matter.
1461 Set IP in case it is mpiexec mode where charmrun does not have IP yet
1463 me.info.nPE=ChMessageInt_new(0);
1464 /* me.info.IP=_skt_invalid_ip; */
1465 me.info.IP=skt_innode_my_ip();
1466 me.info.dataport=ChMessageInt_new(dataport);
1468 /*Send our node info. to charmrun.
1469 CommLock hasn't been initialized yet--
1470 use non-locking version*/
1471 ctrl_sendone_nolock("initnode",(const char *)&me,sizeof(me),NULL,0);
1472 MACHSTATE1(5,"send initnode - dataport:%d", dataport);
1474 MACHSTATE(3,"initnode sent");
1476 /*We get the other node addresses from a message sent
1477 back via the charmrun control port.*/
1478 if (!skt_select1(Cmi_charmrun_fd,1200*1000)){
1479 CmiAbort("Timeout waiting for nodetab!\n");
1481 MACHSTATE(2,"recv initnode {");
1482 ChMessage_recv(Cmi_charmrun_fd,&nodetabmsg);
1483 MACHSTATE(2,"} recv initnode");
1485 //#if CMK_USE_IBVERBS
1486 //#else
1487 node_addresses_store(&nodetabmsg);
1488 ChMessage_free(&nodetabmsg);
1489 //#endif
1490 MACHSTATE(3,"} node_addresses_obtain ");
1494 /***********************************************************************
1495 * DeliverOutgoingMessage()
1497 * This function takes care of delivery of outgoing messages from the
1498 * sender end. Broadcast messages are divided into sets of messages that
1499 * are bound to the local node, and to remote nodes. For local
1500 * transmission, the messages are directly pushed into the recv
1501 * queues. For non-local transmission, the function DeliverViaNetwork()
1502 * is called
1503 ***********************************************************************/
1504 int DeliverOutgoingMessage(OutgoingMsg ogm)
1506 int i, rank, dst; OtherNode node;
1508 int network = 1;
1510 dst = ogm->dst;
1512 //printf("deliver outgoing message, dest: %d \n", dst);
1513 #if CMK_ERROR_CHECKING
1514 if (dst<0 || dst>=CmiNumPesGlobal())
1515 CmiAbort("Send to out-of-bounds processor!");
1516 #endif
1517 node = nodes_by_pe[dst];
1518 rank = dst - node->nodestart;
1519 int acqLock = 0;
1520 if (node->nodestart != Cmi_nodestartGlobal) {
1521 #if !CMK_SMP_NOT_RELAX_LOCK
1522 LOCK_AND_SET();
1523 #endif
1524 DeliverViaNetwork(ogm, node, rank, DGRAM_ROOTPE_MASK, 0);
1525 GarbageCollectMsg(ogm);
1526 #if !CMK_SMP_NOT_RELAX_LOCK
1527 UNLOCK_AND_UNSET();
1528 #endif
1530 #if CMK_MULTICORE
1531 network = 0;
1532 #endif
1533 return network;
1537 * Set up an OutgoingMsg structure for this message.
1539 static OutgoingMsg PrepareOutgoing(int pe,int size,int freemode,char *data) {
1540 OutgoingMsg ogm;
1541 MallocOutgoingMsg(ogm);
1542 MACHSTATE2(2,"Preparing outgoing message for pe %d, size %d",pe,size);
1543 ogm->size = size;
1544 ogm->data = data;
1545 ogm->src = CmiMyPeGlobal();
1546 ogm->dst = pe;
1547 ogm->freemode = freemode;
1548 ogm->refcount = 0;
1549 return (CmiCommHandle)ogm;
1553 /******************************************************************************
1555 * CmiGeneralSend
1557 * Description: This is a generic message sending routine. All the
1558 * converse message send functions are implemented in terms of this
1559 * function. (By setting appropriate flags (eg freemode) that tell
1560 * CmiGeneralSend() how exactly to handle the particular case of
1561 * message send)
1563 *****************************************************************************/
1565 //CmiCommHandle CmiGeneralSend(int pe, int size, int freemode, char *data)
1566 CmiCommHandle LrtsSendFunc(int destNode, int pe, int size, char *data, int freemode)
1568 int sendonnetwork;
1569 OutgoingMsg ogm;
1570 MACHSTATE(1,"CmiGeneralSend {");
1572 CMI_MSG_SIZE(data) = size;
1574 ogm=PrepareOutgoing(pe,size,'F',data);
1576 int acqLock = 0;
1577 #if CMK_SMP_NOT_RELAX_LOCK
1578 LOCK_AND_SET();
1579 #endif
1581 sendonnetwork = DeliverOutgoingMessage(ogm);
1583 #if CMK_SMP_NOT_RELAX_LOCK
1584 UNLOCK_AND_UNSET();
1585 #endif
1587 //#if CMK_SMP
1588 // if (sendonnetwork!=0) /* only call server when we send msg on network in SMP */
1589 // CommunicationServerNet(0, COMM_SERVER_FROM_WORKER);
1590 //#endif
1591 MACHSTATE(1,"} LrtsSend");
1592 return (CmiCommHandle)ogm;
1596 /******************************************************************************
1598 * Comm Handle manipulation.
1600 *****************************************************************************/
1602 #if ! CMK_MULTICAST_LIST_USE_COMMON_CODE
1604 /*****************************************************************************
1606 * NET version List-Cast and Multicast Code
1608 ****************************************************************************/
1610 void LrtsSyncListSendFn(int npes, int *pes, int len, char *msg)
1612 int i;
1613 for(i=0;i<npes;i++) {
1614 CmiReference(msg);
1615 CmiSyncSendAndFree(pes[i], len, msg);
1619 CmiCommHandle LrtsAsyncListSendFn(int npes, int *pes, int len, char *msg)
1621 CmiError("ListSend not implemented.");
1622 return (CmiCommHandle) 0;
1626 because in all net versions, the message buffer after CmiSyncSendAndFree
1627 returns is not changed, we can use memory reference trick to avoid
1628 memory copying here
1630 void LrtsFreeListSendFn(int npes, int *pes, int len, char *msg)
1632 int i;
1633 for(i=0;i<npes;i++) {
1634 CmiReference(msg);
1635 CmiSyncSendAndFree(pes[i], len, msg);
1637 CmiFree(msg);
1640 #endif
1642 void LrtsDrainResources(){}
1643 void LrtsPostNonLocal() {}
1645 /* Network progress function is used to poll the network when for
1646 messages. This flushes receive buffers on some implementations*/
1648 #if CMK_MACHINE_PROGRESS_DEFINED
1649 void CmiMachineProgressImpl(){
1650 CommunicationServerNet(0, COMM_SERVER_FROM_SMP);
1652 #endif
1654 void LrtsAdvanceCommunication(int whileidle)
1656 #if CMK_SMP
1657 CommunicationServerNet(0, COMM_SERVER_FROM_SMP);
1658 #else
1659 CommunicationServerNet(0, COMM_SERVER_FROM_WORKER);
1660 #endif
1664 /******************************************************************************
1666 * Main code, Init, and Exit
1668 *****************************************************************************/
1670 #if CMK_BARRIER_USE_COMMON_CODE
1672 /* happen at node level */
1673 /* must be called on every PE including communication processors */
1674 void LrtsBarrier()
1676 int numnodes = CmiNumNodesGlobal();
1677 static int barrier_phase = 0;
1679 if (Cmi_charmrun_fd == -1) return; // standalone
1680 if (numnodes == 1) {
1681 return;
1684 ctrl_sendone_locking("barrier",NULL,0,NULL,0);
1685 while (barrierReceived != 1) {
1686 LOCK_IF_AVAILABLE();
1687 ctrl_getone();
1688 UNLOCK_IF_AVAILABLE();
1690 barrierReceived = 0;
1691 barrier_phase ++;
1694 int CmiBarrierZero()
1696 int i;
1697 int numnodes = CmiNumNodesGlobal();
1698 ChMessage msg;
1700 if (Cmi_charmrun_fd == -1) return 0; // standalone
1701 if (numnodes == 1) {
1702 CmiNodeAllBarrier();
1703 return 0;
1706 if (CmiMyRank() == 0) {
1707 char str[64];
1708 sprintf(str, "%d", CmiMyNodeGlobal());
1709 ctrl_sendone_locking("barrier0",str,strlen(str)+1,NULL,0);
1710 if (CmiMyNodeGlobal() == 0) {
1711 while (barrierReceived != 2) {
1712 LOCK_IF_AVAILABLE();
1713 ctrl_getone();
1714 UNLOCK_IF_AVAILABLE();
1716 barrierReceived = 0;
1720 CmiNodeAllBarrier();
1721 return 0;
1724 #endif
1726 /******************************************************************************
1728 * Main code, Init, and Exit
1730 *****************************************************************************/
1732 void LrtsPreCommonInit(int everReturn)
1734 #if !CMK_SMP
1735 #if !CMK_ASYNC_NOT_NEEDED
1736 if (Cmi_asyncio)
1738 CmiSignal(SIGIO, 0, 0, CommunicationInterrupt);
1739 if (!Cmi_netpoll) {
1740 if (dataskt!=-1) CmiEnableAsyncIO(dataskt);
1741 if (Cmi_charmrun_fd!=-1) CmiEnableAsyncIO(Cmi_charmrun_fd);
1744 #endif
1745 #endif
1748 void LrtsPostCommonInit(int everReturn)
1750 /* better to show the status here */
1751 if (CmiMyPe() == 0) {
1752 if (Cmi_netpoll == 1) {
1753 CmiPrintf("Charm++> scheduler running in netpoll mode.\n");
1755 #if CMK_SHARED_VARS_UNAVAILABLE
1756 else {
1757 if (CmiMemoryIs(CMI_MEMORY_IS_OS))
1758 CmiAbort("Charm++ Fatal Error: interrupt mode does not work with default system memory allocator. Run with +netpoll to disable the interrupt.");
1760 #endif
1763 #if MEMORYUSAGE_OUTPUT
1764 memoryusage_counter = 0;
1765 #endif
1767 #if CMK_SHARED_VARS_UNAVAILABLE
1768 if (Cmi_netpoll) /*Repeatedly call CommServer*/
1769 CcdCallOnConditionKeep(CcdPERIODIC,
1770 (CcdVoidFn) CommunicationPeriodic, NULL);
1771 else /*Only need this for retransmits*/
1772 CcdCallOnConditionKeep(CcdPERIODIC_10ms,
1773 (CcdVoidFn) CommunicationPeriodic, NULL);
1774 #endif
1776 if (CmiMyRank()==0 && Cmi_charmrun_fd!=-1) {
1777 CcdCallOnConditionKeep(CcdPERIODIC_10ms, (CcdVoidFn) CmiStdoutFlush, NULL);
1778 #if CMK_SHARED_VARS_UNAVAILABLE
1779 if (!Cmi_asyncio) {
1780 CcdCallFnAfter((CcdVoidFn)pingCharmrunPeriodic,NULL,1000);
1782 else {
1783 /*Occasionally ping charmrun, to test if it's dead*/
1784 struct itimerval i;
1785 CmiSignal(SIGALRM, 0, 0, pingCharmrun);
1786 #if MEMORYUSAGE_OUTPUT
1787 i.it_interval.tv_sec = 0;
1788 i.it_interval.tv_usec = 1000000/MEMORYUSAGE_OUTPUT_FREQ;
1789 i.it_value.tv_sec = 0;
1790 i.it_value.tv_usec = 1000000/MEMORYUSAGE_OUTPUT_FREQ;
1791 #else
1792 i.it_interval.tv_sec = 10;
1793 i.it_interval.tv_usec = 0;
1794 i.it_value.tv_sec = 10;
1795 i.it_value.tv_usec = 0;
1796 #endif
1797 setitimer(ITIMER_REAL, &i, NULL);
1800 #if ! CMK_USE_TCP
1801 /*Occasionally check for retransmissions, outgoing acks, etc.*/
1802 CcdCallFnAfter((CcdVoidFn)CommunicationsClockCaller,NULL,Cmi_comm_clock_delay);
1803 #endif
1804 #endif
1806 /*Initialize the clock*/
1807 Cmi_clock=GetClock();
1810 #ifdef IGET_FLOWCONTROL
1811 /* Call the function once to determine the amount of physical memory available */
1812 getAvailSysMem();
1813 /* Call the function to periodically call the token adapt function */
1814 CcdCallFnAfter((CcdVoidFn)TokenUpdatePeriodic, NULL, 2000); // magic number of 2000ms
1815 CcdCallOnConditionKeep(CcdPERIODIC_10s, // magic number of PERIOD 10s
1816 (CcdVoidFn) TokenUpdatePeriodic, NULL);
1817 #endif
1819 #ifdef CMK_RANDOMLY_CORRUPT_MESSAGES
1820 srand((int)(1024.0*CmiWallTimer()));
1821 if (CmiMyPe()==0)
1822 CmiPrintf("Charm++: Machine layer will randomly corrupt every %d'th message (rand %d)\n",
1823 CMK_RANDOMLY_CORRUPT_MESSAGES,rand());
1824 #endif
1826 #ifdef __ONESIDED_IMPL
1827 #ifdef __ONESIDED_NO_HARDWARE
1828 putSrcHandler = CmiRegisterHandler((CmiHandler)handlePutSrc);
1829 putDestHandler = CmiRegisterHandler((CmiHandler)handlePutDest);
1830 getSrcHandler = CmiRegisterHandler((CmiHandler)handleGetSrc);
1831 getDestHandler = CmiRegisterHandler((CmiHandler)handleGetDest);
1832 #endif
1833 #endif
1837 void LrtsExit()
1839 int i;
1840 machine_initiated_shutdown=1;
1842 CmiStdoutFlush();
1843 if (Cmi_charmrun_fd==-1) {
1844 exit(0); /*Standalone version-- just leave*/
1845 } else {
1846 Cmi_check_delay = 1.0; /* speed up checking of charmrun */
1847 for(i = 0; i < CmiMyNodeSize(); i++) {
1848 ctrl_sendone_locking("ending",NULL,0,NULL,0); /* this causes charmrun to go away, every PE needs to report */
1850 while(1) CommunicationServerNet(5, COMM_SERVER_FROM_SMP);
1854 static void set_signals(void)
1856 if(!Cmi_truecrash) {
1857 signal(SIGSEGV, KillOnAllSigs);
1858 signal(SIGFPE, KillOnAllSigs);
1859 signal(SIGILL, KillOnAllSigs);
1860 signal(SIGINT, KillOnAllSigs);
1861 signal(SIGTERM, KillOnAllSigs);
1862 signal(SIGABRT, KillOnAllSigs);
1863 # if !defined(_WIN32) || defined(__CYGWIN__) /*UNIX-only signals*/
1864 signal(SIGQUIT, KillOnAllSigs);
1865 signal(SIGBUS, KillOnAllSigs);
1866 # if CMK_HANDLE_SIGUSR
1867 signal(SIGUSR1, HandleUserSignals);
1868 signal(SIGUSR2, HandleUserSignals);
1869 # endif
1870 # endif /*UNIX*/
1874 /*Socket idle function to use before addresses have been
1875 obtained. During the real program, we idle with CmiYield.
1877 static void obtain_idleFn(void) {sleep(0);}
1879 static int net_default_skt_abort(int code,const char *msg)
1881 fprintf(stderr,"Fatal socket error: code %d-- %s\n",code,msg);
1882 machine_exit(1);
1883 return -1;
1886 void LrtsInit(int *argc, char ***argv, int *numNodes, int *myNodeID)
1888 int i;
1889 Cmi_netpoll = 0;
1890 #if CMK_NETPOLL
1891 Cmi_netpoll = 1;
1892 #endif
1893 #if CMK_WHEN_PROCESSOR_IDLE_USLEEP
1894 Cmi_idlepoll = 0;
1895 #else
1896 Cmi_idlepoll = 1;
1897 #endif
1898 Cmi_truecrash = 0;
1899 if (CmiGetArgFlagDesc(*argv,"+truecrash","Do not install signal handlers") ||
1900 CmiGetArgFlagDesc(*argv,"++debug",NULL /*meaning: don't show this*/)) Cmi_truecrash = 1;
1901 /* netpoll disable signal */
1902 if (CmiGetArgFlagDesc(*argv,"+netpoll","Do not use SIGIO--poll instead")) Cmi_netpoll = 1;
1903 if (CmiGetArgFlagDesc(*argv,"+netint","Use SIGIO")) Cmi_netpoll = 0;
1904 /* idlepoll use poll instead if sleep when idle */
1905 if (CmiGetArgFlagDesc(*argv,"+idlepoll","Do not sleep when idle")) Cmi_idlepoll = 1;
1906 /* idlesleep use sleep instead if busywait when idle */
1907 if (CmiGetArgFlagDesc(*argv,"+idlesleep","Make sleep calls when idle")) Cmi_idlepoll = 0;
1908 Cmi_syncprint = CmiGetArgFlagDesc(*argv,"+syncprint", "Flush each CmiPrintf to the terminal");
1910 Cmi_asyncio = 1;
1911 #if CMK_ASYNC_NOT_NEEDED
1912 Cmi_asyncio = 0;
1913 #endif
1914 if (CmiGetArgFlagDesc(*argv,"+asyncio","Use async IO")) Cmi_asyncio = 1;
1915 if (CmiGetArgFlagDesc(*argv,"+asynciooff","Don not use async IO")) Cmi_asyncio = 0;
1916 #if CMK_MULTICORE
1917 if (CmiGetArgFlagDesc(*argv,"+commthread","Use communication thread")) {
1918 Cmi_commthread = 1;
1919 #if CMK_SHARED_VARS_POSIX_THREADS_SMP
1920 _Cmi_sleepOnIdle = 1; /* worker thread go sleep */
1921 #endif
1922 if (CmiMyPe() == 0) CmiPrintf("Charm++> communication thread is launched in multicore version. \n");
1924 #endif
1926 skt_init();
1927 /* use special abort handler instead of default_skt_abort to
1928 prevent exit trapped by atexit_check() due to the exit() call */
1929 skt_set_abort(net_default_skt_abort);
1930 atexit(machine_atexit_check);
1931 parse_netstart();
1932 parse_magic();
1933 #if ! defined(_WIN32)
1934 /* only get forks in non-smp mode */
1935 parse_forks();
1936 #endif
1937 extract_args(*argv);
1938 log_init();
1939 Cmi_scanf_mutex = CmiCreateLock();
1941 /* NOTE: can not acutally call timer before timerInit ! GZ */
1942 MACHSTATE2(5,"Init: (netpoll=%d), (idlepoll=%d)",Cmi_netpoll,Cmi_idlepoll);
1944 skt_set_idle(obtain_idleFn);
1945 if (!skt_ip_match(Cmi_charmrun_IP,_skt_invalid_ip)) {
1946 set_signals();
1947 #if CMK_USE_TCP
1948 dataskt=skt_server(&dataport);
1949 #else
1950 dataskt=skt_datagram(&dataport, Cmi_os_buffer_size);
1951 #endif
1952 MACHSTATE2(5,"skt_connect at dataskt:%d Cmi_charmrun_port:%d",dataskt, Cmi_charmrun_port);
1953 Cmi_charmrun_fd = skt_connect(Cmi_charmrun_IP, Cmi_charmrun_port, 1800);
1954 MACHSTATE2(5,"Opened connection to charmrun at socket %d, dataport=%d", Cmi_charmrun_fd, dataport);
1955 skt_tcp_no_nagle(Cmi_charmrun_fd);
1956 CmiStdoutInit();
1957 } else {/*Standalone operation*/
1958 printf("Charm++: standalone mode (not using charmrun)\n");
1959 dataskt=-1;
1960 Cmi_charmrun_fd=-1;
1963 CmiMachineInit(*argv);
1965 node_addresses_obtain(*argv);
1966 MACHSTATE(5,"node_addresses_obtain done");
1968 CmiCommunicationInit(*argv);
1970 skt_set_idle(CmiYield);
1971 Cmi_check_delay = 1.0+0.25*Lrts_numNodes;
1973 if (Cmi_charmrun_fd==-1) /*Don't bother with check in standalone mode*/
1974 Cmi_check_delay=1.0e30;
1976 for(i = 0; i < _Cmi_mynodesize; i++)
1977 inProgress[i] = 0;
1979 *numNodes = Lrts_numNodes;
1980 *myNodeID = Lrts_myNode;
1984 #if CMK_CELL
1986 #include "spert_ppu.h"
1988 void machine_OffloadAPIProgress() {
1989 LOCK_IF_AVAILABLE();
1990 OffloadAPIProgress();
1991 UNLOCK_IF_AVAILABLE();
1993 #endif
1995 void LrtsPrepareEnvelope(char *msg, int size)
1997 CMI_MSG_SIZE(msg) = size;
2001 /*@}*/