verbs: verbs seperated from netlrts build
[charm.git] / src / arch / verbs / machine.c
blobdcd5f669c9d8ee1746da578a292dafab790afea4
2 /** @file
3 * Basic NET 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 #if CMK_MULTICORE
236 int Cmi_commthread = 0;
237 #endif
239 #include "conv-ccs.h"
240 #include "ccs-server.h"
241 #include "sockRoutines.h"
243 #if defined(_WIN32) && ! defined(__CYGWIN__)
244 /*For windows systems:*/
245 # include <windows.h>
246 # include <wincon.h>
247 # include <sys/types.h>
248 # include <sys/timeb.h>
249 # define fdopen _fdopen
250 # define SIGBUS -1 /*These signals don't exist in Win32*/
251 # define SIGKILL -1
252 # define SIGQUIT -1
253 /*# define SIGTERM -1*/ /* VC++ ver 8 now has SIGTERM */
255 #else /*UNIX*/
256 # include <pwd.h>
257 # include <unistd.h>
258 # include <fcntl.h>
259 # include <sys/file.h>
260 #endif
262 #if CMK_PERSISTENT_COMM
263 #include "machine-persistent.c"
264 #endif
266 #define PRINTBUFSIZE 16384
268 #ifdef __ONESIDED_IMPL
269 #ifdef __ONESIDED_NO_HARDWARE
270 int putSrcHandler;
271 int putDestHandler;
272 int getSrcHandler;
273 int getDestHandler;
274 #include "conv-onesided.c"
275 #endif
276 #endif
279 static void CommunicationServerNet(int withDelayMs, int where);
280 //static void CommunicationServer(int withDelayMs);
282 void CmiHandleImmediate();
283 extern int CmemInsideMem();
284 extern void CmemCallWhenMemAvail();
286 static unsigned int dataport=0;
287 static int Cmi_mach_id=0; /* Machine-specific identifier (GM-only) */
288 static SOCKET dataskt;
290 extern void TokenUpdatePeriodic();
291 extern void getAvailSysMem();
293 /****************************************************************************
295 * Handling Errors
297 * Errors should be handled by printing a message on stderr and
298 * calling exit(1). Nothing should be sent to charmrun, no attempt at
299 * communication should be made. The other processes will notice the
300 * abnormal termination and will deal with it.
302 * Rationale: if an error triggers an attempt to send a message,
303 * the attempt to send a message is likely to trigger another error,
304 * leading to an infinite loop and a process that spins instead of
305 * shutting down.
307 *****************************************************************************/
309 static int machine_initiated_shutdown=0;
310 static int already_in_signal_handler=0;
312 static void CmiDestroyLocks();
314 void MachineExit();
316 static void machine_exit(int status)
318 MACHSTATE(3," machine_exit");
319 machine_initiated_shutdown=1;
321 CmiDestroyLocks(); /* destory locks to prevent dead locking */
322 EmergencyExit();
324 MachineExit();
325 exit(status);
328 static void charmrun_abort(const char*);
330 static void KillEveryone(const char *msg)
332 charmrun_abort(msg);
333 machine_exit(1);
336 static void KillEveryoneCode(n)
337 int n;
339 char _s[100];
340 sprintf(_s, "[%d] Fatal error #%d\n", CmiMyPe(), n);
341 charmrun_abort(_s);
342 machine_exit(1);
345 CpvExtern(int, freezeModeFlag);
347 static void KillOnAllSigs(int sigNo)
349 const char *sig="unknown signal";
350 const char *suggestion="";
351 if (machine_initiated_shutdown ||
352 already_in_signal_handler)
353 machine_exit(1); /*Don't infinite loop if there's a signal during a signal handler-- just die.*/
354 already_in_signal_handler=1;
356 #if CMK_CCS_AVAILABLE
357 if (CpvAccess(cmiArgDebugFlag)) {
358 int reply = 0;
359 CpdNotify(CPD_SIGNAL,sigNo);
360 #if ! CMK_BIGSIM_CHARM
361 CcsSendReplyNoError(4,&reply);/*Send an empty reply if not*/
362 CpvAccess(freezeModeFlag) = 1;
363 CpdFreezeModeScheduler();
364 #else
365 CpdFreeze();
366 #endif
368 #endif
370 CmiDestroyLocks(); /* destory locks */
372 if (sigNo==SIGSEGV) {
373 sig="segmentation violation";
374 suggestion="Try running with '++debug', or linking with '-memory paranoid' (memory paranoid requires '+netpoll' at runtime).\n";
376 if (sigNo==SIGFPE) {
377 sig="floating point exception";
378 suggestion="Check for integer or floating-point division by zero.\n";
380 if (sigNo==SIGBUS) {
381 sig="bus error";
382 suggestion="Check for misaligned reads or writes to memory.\n";
384 if (sigNo==SIGILL) {
385 sig="illegal instruction";
386 suggestion="Check for calls to uninitialized function pointers.\n";
388 if (sigNo==SIGKILL) sig="caught signal KILL";
389 if (sigNo==SIGQUIT) sig="caught signal QUIT";
390 if (sigNo==SIGTERM) sig="caught signal TERM";
391 MACHSTATE1(5," Caught signal %s ",sig);
392 /*ifdef this part*/
393 #ifdef __FAULT__
394 if(sigNo == SIGKILL || sigNo == SIGQUIT || sigNo == SIGTERM){
395 CmiPrintf("[%d] Caught but ignoring signal\n",CmiMyPe());
396 }else{
397 #else
399 #endif
400 CmiError("------------- Processor %d Exiting: Caught Signal ------------\n"
401 "Signal: %s\n",CmiMyPe(),sig);
402 if (0!=suggestion[0])
403 CmiError("Suggestion: %s",suggestion);
404 CmiPrintStackTrace(1);
405 charmrun_abort(sig);
406 machine_exit(1);
410 static void machine_atexit_check(void)
412 if (!machine_initiated_shutdown)
413 CmiAbort("unexpected call to exit by user program. Must use CkExit, not exit!");
414 printf("Program finished.\n");
415 #if 0 /*Wait for the user to press any key (for Win32 debugging)*/
416 fgetc(stdin);
417 #endif
420 #if !defined(_WIN32) || defined(__CYGWIN__)
421 static void HandleUserSignals(int signum)
423 int condnum = ((signum==SIGUSR1) ? CcdSIGUSR1 : CcdSIGUSR2);
424 CcdRaiseCondition(condnum);
426 #endif
428 /*****************************************************************************
430 * Utility routines for network machine interface.
432 *****************************************************************************/
435 Horrific #defines to hide the differences between select() and poll().
437 #if CMK_USE_POLL /*poll() version*/
438 # define CMK_PIPE_DECL(delayMs) \
439 struct pollfd fds[10]; \
440 int nFds_sto=0; int *nFds=&nFds_sto; \
441 int pollDelayMs=delayMs;
442 # define CMK_PIPE_SUB fds,nFds
443 # define CMK_PIPE_CALL() poll(fds, *nFds, pollDelayMs); *nFds=0
445 # define CMK_PIPE_PARAM struct pollfd *fds,int *nFds
446 # define CMK_PIPE_ADDREAD(rd_fd) \
447 do {fds[*nFds].fd=rd_fd; fds[*nFds].events=POLLIN; (*nFds)++;} while(0)
448 # define CMK_PIPE_ADDWRITE(wr_fd) \
449 do {fds[*nFds].fd=wr_fd; fds[*nFds].events=POLLOUT; (*nFds)++;} while(0)
450 # define CMK_PIPE_CHECKREAD(rd_fd) fds[(*nFds)++].revents&POLLIN
451 # define CMK_PIPE_CHECKWRITE(wr_fd) fds[(*nFds)++].revents&POLLOUT
453 #elif CMK_USE_KQUEUE /* kqueue version */
455 # define CMK_PIPE_DECL(delayMs) \
456 if (_kq == -1) _kq = kqueue(); \
457 struct kevent ke_sto; \
458 struct kevent* ke = &ke_sto; \
459 struct timespec tmo; \
460 tmo.tv_sec = 0; tmo.tv_nsec = delayMs*1e6;
461 # define CMK_PIPE_SUB ke
462 # define CMK_PIPE_CALL() kevent(_kq, NULL, 0, ke, 1, &tmo)
464 # define CMK_PIPE_PARAM struct kevent* ke
465 # define CMK_PIPE_ADDREAD(rd_fd) \
466 do { EV_SET(ke, rd_fd, EVFILT_READ, EV_ADD, 0, 10, NULL); \
467 kevent(_kq, ke, 1, NULL, 0, NULL); memset(ke, 0, sizeof(ke));} while(0)
468 # define CMK_PIPE_ADDWRITE(wr_fd) \
469 do { EV_SET(ke, wr_fd, EVFILT_WRITE, EV_ADD, 0, 10, NULL); \
470 kevent(_kq, ke, 1, NULL, 0, NULL); memset(ke, 0, sizeof(ke));} while(0)
471 # define CMK_PIPE_CHECKREAD(rd_fd) (ke->ident == rd_fd && ke->filter == EVFILT_READ)
472 # define CMK_PIPE_CHECKWRITE(wr_fd) (ke->ident == wr_fd && ke->filter == EVFILT_WRITE)
474 #else /*select() version*/
476 # define CMK_PIPE_DECL(delayMs) \
477 fd_set rfds_sto,wfds_sto;\
478 fd_set *rfds=&rfds_sto,*wfds=&wfds_sto; struct timeval tmo; \
479 FD_ZERO(rfds); FD_ZERO(wfds);tmo.tv_sec=0; tmo.tv_usec=1000*delayMs;
480 # define CMK_PIPE_SUB rfds,wfds
481 # define CMK_PIPE_CALL() select(FD_SETSIZE, rfds, wfds, NULL, &tmo)
483 # define CMK_PIPE_PARAM fd_set *rfds,fd_set *wfds
484 # define CMK_PIPE_ADDREAD(rd_fd) FD_SET(rd_fd,rfds)
485 # define CMK_PIPE_ADDWRITE(wr_fd) FD_SET(wr_fd,wfds)
486 # define CMK_PIPE_CHECKREAD(rd_fd) FD_ISSET(rd_fd,rfds)
487 # define CMK_PIPE_CHECKWRITE(wr_fd) FD_ISSET(wr_fd,wfds)
488 #endif
490 static void CMK_PIPE_CHECKERR(void) {
491 #if defined(_WIN32) && !defined(__CYGWIN__)
492 /* Win32 socket seems to randomly return inexplicable errors
493 here-- WSAEINVAL, WSAENOTSOCK-- yet everything is actually OK.
494 int err=WSAGetLastError();
495 CmiPrintf("(%d)Select returns -1; errno=%d, WSAerr=%d\n",withDelayMs,errn
496 o,err);
498 #else /*UNIX machine*/
499 if (errno!=EINTR)
500 KillEveryone("Socket error in CheckSocketsReady!\n");
501 #endif
505 static void CmiStdoutFlush(void);
506 static int CmiStdoutNeedsService(void);
507 static void CmiStdoutService(void);
508 static void CmiStdoutAdd(CMK_PIPE_PARAM);
509 static void CmiStdoutCheck(CMK_PIPE_PARAM);
512 double GetClock(void)
514 #if defined(_WIN32) && !defined(__CYGWIN__)
515 struct _timeb tv;
516 _ftime(&tv);
517 return (tv.time * 1.0 + tv.millitm * 1.0E-3);
518 #else
519 struct timeval tv; int ok;
520 ok = gettimeofday(&tv, NULL);
521 if (ok<0) { perror("gettimeofday"); KillEveryoneCode(9343112); }
522 return (tv.tv_sec * 1.0 + tv.tv_usec * 1.0E-6);
523 #endif
527 /***********************************************************************
529 * Abort function:
531 ************************************************************************/
533 static int Cmi_truecrash;
534 static int already_aborting=0;
535 void LrtsAbort(const char *message)
537 if (already_aborting) machine_exit(1);
538 already_aborting=1;
539 MACHSTATE1(5,"CmiAbort(%s)",message);
541 #if CMK_CCS_AVAILABLE
542 /* if CharmDebug is attached simply try to send a message to it */
543 if (CpvAccess(cmiArgDebugFlag)) {
544 CpdNotify(CPD_ABORT, message);
545 CpdFreeze();
547 #endif
549 CmiError("------------- Processor %d Exiting: Called CmiAbort ------------\n"
550 "Reason: %s\n",CmiMyPe(),message);
551 CmiPrintStackTrace(0);
553 /*Send off any remaining prints*/
554 CmiStdoutFlush();
556 if(Cmi_truecrash) {
557 printf("CHARM++ FATAL ERROR: %s\n", message);
558 *(int *)NULL = 0; /*Write to null, causing bus error*/
559 } else {
560 charmrun_abort(message);
561 machine_exit(1);
566 /******************************************************************************
568 * CmiEnableAsyncIO
570 * The net and tcp versions use a bunch of unix processes talking to each
571 * other via file descriptors. We need for a signal SIGIO to be generated
572 * each time a message arrives, making it possible to write a signal
573 * handler to handle the messages. The vast majority of unixes can,
574 * in fact, do this. However, there isn't any standard for how this is
575 * supposed to be done, so each version of UNIX has a different set of
576 * calls to turn this signal on. So, there is like one version here for
577 * every major brand of UNIX.
579 *****************************************************************************/
581 #if CMK_ASYNC_USE_F_SETFL_AND_F_SETOWN
582 #include <fcntl.h>
583 void CmiEnableAsyncIO(int fd)
585 if ( fcntl(fd, F_SETOWN, getpid()) < 0 ) {
586 CmiError("setting socket owner: %s\n", strerror(errno)) ;
587 exit(1);
589 if ( fcntl(fd, F_SETFL, FASYNC) < 0 ) {
590 CmiError("setting socket async: %s\n", strerror(errno)) ;
591 exit(1);
594 #else
595 void CmiEnableAsyncIO(int fd) { }
596 #endif
598 /* We should probably have a set of "CMK_NONBLOCK_USE_..." defines here:*/
599 #if !defined(_WIN32) || defined(__CYGWIN__)
600 void CmiEnableNonblockingIO(int fd) {
601 int on=1;
602 if (fcntl(fd,F_SETFL,O_NONBLOCK,&on)<0) {
603 CmiError("setting nonblocking IO: %s\n", strerror(errno)) ;
604 exit(1);
607 #else
608 void CmiEnableNonblockingIO(int fd) { }
609 #endif
612 /******************************************************************************
614 * Configuration Data
616 * This data is all read in from the NETSTART variable (provided by the
617 * charmrun) and from the command-line arguments. Once read in, it is never
618 * modified.
620 *****************************************************************************/
622 static skt_ip_t Cmi_self_IP;
623 static skt_ip_t Cmi_charmrun_IP; /*Address of charmrun machine*/
624 static int Cmi_charmrun_port;
625 static int Cmi_charmrun_pid;
626 static int Cmi_charmrun_fd=-1;
627 /* Magic number to be used for sanity check in messege header */
628 static int Cmi_net_magic;
630 static int Cmi_netpoll;
631 static int Cmi_asyncio;
632 static int Cmi_idlepoll;
633 static int Cmi_syncprint;
634 static int Cmi_print_stats = 0;
636 #if ! CMK_SMP && ! defined(_WIN32)
637 /* parse forks only used in non-smp mode */
638 static void parse_forks(void) {
639 char *forkstr;
640 int nread;
641 int forks;
642 int i,pid;
643 forkstr=getenv("CmiMyForks");
644 if(forkstr!=0) { /* charmrun */
645 nread = sscanf(forkstr,"%d",&forks);
646 for(i=1;i<=forks;i++) { /* by default forks = 0 */
647 pid=fork();
648 if(pid<0) CmiAbort("Fork returned an error");
649 if(pid==0) { /* forked process */
650 /* reset mynode,pe & exit loop */
651 _Cmi_mynode+=i;
652 _Cmi_mype+=i;
653 break;
658 #endif
659 static void parse_magic(void)
661 char* nm;
662 int nread;
663 nm = getenv("NETMAGIC");
664 if (nm!=0)
665 {/*Read values set by Charmrun*/
666 nread = sscanf(nm, "%d",&Cmi_net_magic);
669 static void parse_netstart(void)
671 char *ns;
672 int nread;
673 int port;
674 ns = getenv("NETSTART");
675 if (ns!=0)
676 {/*Read values set by Charmrun*/
677 char Cmi_charmrun_name[1024];
678 nread = sscanf(ns, "%d%s%d%d%d",
679 &_Cmi_mynode,
680 Cmi_charmrun_name, &Cmi_charmrun_port,
681 &Cmi_charmrun_pid, &port);
682 Cmi_charmrun_IP=skt_lookup_ip(Cmi_charmrun_name);
684 if (nread!=5) {
685 fprintf(stderr,"Error parsing NETSTART '%s'\n",ns);
686 exit(1);
688 } else
689 {/*No charmrun-- set flag values for standalone operation*/
690 _Cmi_mynode=0;
691 Cmi_charmrun_IP=_skt_invalid_ip;
692 Cmi_charmrun_port=0;
693 Cmi_charmrun_pid=0;
694 dataport = -1;
696 #if CMK_USE_IBVERBS | CMK_USE_IBUD
697 char *cmi_num_nodes = getenv("CmiNumNodes");
698 if(cmi_num_nodes != NULL){
699 sscanf(cmi_num_nodes,"%d",&_Cmi_numnodes);
701 #endif
704 static void extract_common_args(char **argv)
706 if (CmiGetArgFlagDesc(argv,"+stats","Print network statistics at shutdown"))
707 Cmi_print_stats = 1;
711 /******************************************************************************
713 * Packet Performance Logging
715 * This module is designed to give a detailed log of the packets and their
716 * acknowledgements, for performance tuning. It can be disabled.
718 *****************************************************************************/
720 #define LOGGING 0
722 #if LOGGING
724 typedef struct logent {
725 double time;
726 int seqno;
727 int srcpe;
728 int dstpe;
729 int kind;
730 } *logent;
733 logent log;
734 int log_pos;
735 int log_wrap;
737 static void log_init(void)
739 log = (logent)malloc(50000 * sizeof(struct logent));
740 _MEMCHECK(log);
741 log_pos = 0;
742 log_wrap = 0;
745 static void log_done(void)
747 char logname[100]; FILE *f; int i, size;
748 sprintf(logname, "log.%d", _Cmi_mynode);
749 f = fopen(logname, "w");
750 if (f==0) KillEveryone("fopen problem");
751 if (log_wrap) size = 50000; else size=log_pos;
752 for (i=0; i<size; i++) {
753 logent ent = log+i;
754 fprintf(f, "%1.4f %d %c %d %d\n",
755 ent->time, ent->srcpe, ent->kind, ent->dstpe, ent->seqno);
757 fclose(f);
760 void printLog(void)
762 char logname[100]; FILE *f; int i, j, size;
763 static int logged = 0;
764 if (logged)
765 return;
766 logged = 1;
767 CmiPrintf("Logging: %d\n", _Cmi_mynode);
768 sprintf(logname, "log.%d", _Cmi_mynode);
769 f = fopen(logname, "w");
770 if (f==0) KillEveryone("fopen problem");
771 for (i = 5000; i; i--)
773 /*for (i=0; i<size; i++) */
774 j = log_pos - i;
775 if (j < 0)
777 if (log_wrap)
778 j = 5000 + j;
779 else
780 j = 0;
783 logent ent = log+j;
784 fprintf(f, "%1.4f %d %c %d %d\n",
785 ent->time, ent->srcpe, ent->kind, ent->dstpe, ent->seqno);
788 fclose(f);
789 CmiPrintf("Done Logging: %d\n", _Cmi_mynode);
792 #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++; }}
794 #endif
796 #if !LOGGING
798 #define log_init() /*empty*/
799 #define log_done() /*empty*/
800 #define printLog() /*empty*/
801 #define LOG(t,s,k,d,q) /*empty*/
803 #endif
805 /******************************************************************************
807 * Node state
809 *****************************************************************************/
812 static CmiNodeLock Cmi_scanf_mutex;
813 static double Cmi_clock;
814 static double Cmi_check_delay = 3.0;
816 /******************************************************************************
818 * OS Threads
819 * SMP implementation moved to machine-smp.c
820 *****************************************************************************/
822 /************************ No kernel SMP threads ***************/
823 #if !CMK_SMP
825 static volatile int memflag=0;
826 void CmiMemLock() { memflag++; }
827 void CmiMemUnlock() { memflag--; }
829 static volatile int comm_flag=0;
830 #define CmiCommLockOrElse(dothis) if (comm_flag!=0) dothis
831 #ifndef MACHLOCK_DEBUG
832 # define CmiCommLock() (comm_flag=1)
833 # define CmiCommUnlock() (comm_flag=0)
834 #else /* Error-checking flag locks */
835 void CmiCommLock(void) {
836 MACHLOCK_ASSERT(!comm_flag,"CmiCommLock");
837 comm_flag=1;
839 void CmiCommUnlock(void) {
840 MACHLOCK_ASSERT(comm_flag,"CmiCommUnlock");
841 comm_flag=0;
843 #endif
845 //int _Cmi_myrank=0; /* Normally zero; only 1 during SIGIO handling */
846 _Cmi_myrank=0;
848 static void CommunicationInterrupt(int ignored)
850 MACHLOCK_ASSERT(!_Cmi_myrank,"CommunicationInterrupt");
851 if (memflag || comm_flag || _immRunning || CmiCheckImmediateLock(0))
852 { /* Already busy inside malloc, comm, or immediate messages */
853 MACHSTATE(5,"--SKIPPING SIGIO--");
854 return;
856 MACHSTATE1(2,"--BEGIN SIGIO comm_mutex_isLocked: %d--", comm_flag)
858 /*Make sure any malloc's we do in here are NOT migratable:*/
859 CmiIsomallocBlockList *oldList=CmiIsomallocBlockListActivate(NULL);
860 /* _Cmi_myrank=1; */
861 CommunicationServerNet(0, COMM_SERVER_FROM_INTERRUPT); /* from interrupt */
862 //CommunicationServer(0); /* from interrupt */
863 /* _Cmi_myrank=0; */
864 CmiIsomallocBlockListActivate(oldList);
866 MACHSTATE(2,"--END SIGIO--")
869 extern void CmiSignal(int sig1, int sig2, int sig3, void (*handler)());
871 static void CmiDestroyLocks()
873 comm_flag = 0;
874 memflag = 0;
877 #endif
879 CpvExtern(int,_charmEpoch);
881 /*Add a message to this processor's receive queue
882 Must be called while holding comm. lock
885 extern double evacTime;
888 /***************************************************************
889 Communication with charmrun:
890 We can send (ctrl_sendone) and receive (ctrl_getone)
891 messages on a TCP socket connected to charmrun.
892 This is used for printfs, CCS, etc; and also for
893 killing ourselves if charmrun dies.
896 /*This flag prevents simultanious outgoing
897 messages on the charmrun socket. It is protected
898 by the commlock.*/
899 static int Cmi_charmrun_fd_sendflag=0;
901 /* ctrl_sendone */
902 static int sendone_abort_fn(int code,const char *msg) {
903 fprintf(stderr,"Socket error %d in ctrl_sendone! %s\n",code,msg);
904 machine_exit(1);
905 return -1;
908 static void ctrl_sendone_nolock(const char *type,
909 const char *data1,int dataLen1,
910 const char *data2,int dataLen2)
912 const void *bufs[3]; int lens[3]; int nBuffers=0;
913 ChMessageHeader hdr;
914 skt_abortFn oldAbort=skt_set_abort(sendone_abort_fn);
915 MACHSTATE1(2,"ctrl_sendone_nolock { type=%s", type);
916 if (Cmi_charmrun_fd==-1)
917 charmrun_abort("ctrl_sendone called in standalone!\n");
918 Cmi_charmrun_fd_sendflag=1;
919 ChMessageHeader_new(type,dataLen1+dataLen2,&hdr);
920 bufs[nBuffers]=&hdr; lens[nBuffers]=sizeof(hdr); nBuffers++;
921 if (dataLen1>0) {bufs[nBuffers]=data1; lens[nBuffers]=dataLen1; nBuffers++;}
922 if (dataLen2>0) {bufs[nBuffers]=data2; lens[nBuffers]=dataLen2; nBuffers++;}
923 skt_sendV(Cmi_charmrun_fd,nBuffers,bufs,lens);
924 Cmi_charmrun_fd_sendflag=0;
925 skt_set_abort(oldAbort);
926 MACHSTATE(2,"} ctrl_sendone_nolock");
929 static void ctrl_sendone_locking(const char *type,
930 const char *data1,int dataLen1,
931 const char *data2,int dataLen2)
933 CmiCommLock();
934 ctrl_sendone_nolock(type,data1,dataLen1,data2,dataLen2);
935 CmiCommUnlock();
938 #ifndef MEMORYUSAGE_OUTPUT
939 #define MEMORYUSAGE_OUTPUT 0
940 #endif
941 #if MEMORYUSAGE_OUTPUT
942 #define MEMORYUSAGE_OUTPUT_FREQ 10 //how many prints in a second
943 static int memoryusage_counter;
944 #define memoryusage_isOutput ((memoryusage_counter%MEMORYUSAGE_OUTPUT_FREQ)==0)
945 #define memoryusage_output {\
946 memoryusage_counter++;\
947 if(CmiMyPe()==0) printf("-- %d %f %ld --\n", CmiMyPe(), GetClock(), CmiMemoryUsage());}
948 #endif
950 static double Cmi_check_last;
952 /* if charmrun dies, we finish */
953 static void pingCharmrun(void *ignored)
955 #if MEMORYUSAGE_OUTPUT
956 memoryusage_output;
957 if(memoryusage_isOutput){
958 memoryusage_counter = 0;
959 #else
961 #endif
963 double clock=GetClock();
964 if (clock > Cmi_check_last + Cmi_check_delay) {
965 MACHSTATE1(3,"CommunicationsClock pinging charmrun Cmi_charmrun_fd_sendflag=%d", Cmi_charmrun_fd_sendflag);
966 Cmi_check_last = clock;
967 #if CMK_USE_GM || CMK_USE_MX
968 if (!Cmi_netpoll) /* GM netpoll, charmrun service is done in interrupt */
969 #endif
970 CmiCommLockOrElse(return;); /*Already busy doing communication*/
971 if (Cmi_charmrun_fd_sendflag) return; /*Busy talking to charmrun*/
972 CmiCommLock();
973 ctrl_sendone_nolock("ping",NULL,0,NULL,0); /*Charmrun may have died*/
974 CmiCommUnlock();
976 #if 1
977 #if CMK_USE_GM || CMK_USE_MX
978 if (!Cmi_netpoll)
979 #endif
980 CmiStdoutFlush(); /*Make sure stdout buffer hasn't filled up*/
981 #endif
985 /* periodic charm ping, for gm and netpoll */
986 static void pingCharmrunPeriodic(void *ignored)
988 pingCharmrun(ignored);
989 CcdCallFnAfter((CcdVoidFn)pingCharmrunPeriodic,NULL,1000);
992 static int ignore_further_errors(int c,const char *msg) {machine_exit(2);return -1;}
993 static void charmrun_abort(const char *s)
995 if (Cmi_charmrun_fd==-1) {/*Standalone*/
996 fprintf(stderr,"Charm++ fatal error:\n%s\n",s);
997 CmiPrintStackTrace(0);
998 abort();
999 } else {
1000 char msgBuf[80];
1001 skt_set_abort(ignore_further_errors);
1002 sprintf(msgBuf,"Fatal error on PE %d> ",CmiMyPe());
1003 ctrl_sendone_nolock("abort",msgBuf,strlen(msgBuf),s,strlen(s)+1);
1007 /* ctrl_getone */
1009 #ifdef __FAULT__
1010 #include "machine-recover.c"
1011 #endif
1013 static void node_addresses_store(ChMessage *msg);
1015 static int barrierReceived = 0;
1017 static void ctrl_getone(void)
1019 ChMessage msg;
1020 MACHSTATE(2,"ctrl_getone")
1021 MACHLOCK_ASSERT(comm_mutex_isLocked,"ctrl_getone")
1022 ChMessage_recv(Cmi_charmrun_fd,&msg);
1023 MACHSTATE1(2,"ctrl_getone recv one '%s'", msg.header.type);
1025 if (strcmp(msg.header.type,"die")==0) {
1026 MACHSTATE(2,"ctrl_getone bye bye")
1027 fprintf(stderr,"aborting: %s\n",msg.data);
1028 log_done();
1029 ConverseCommonExit();
1030 machine_exit(0);
1032 #if CMK_CCS_AVAILABLE
1033 else if (strcmp(msg.header.type, "req_fw")==0) {
1034 CcsImplHeader *hdr=(CcsImplHeader *)msg.data;
1035 /*Sadly, I *can't* do a:
1036 CcsImpl_netRequest(hdr,msg.data+sizeof(CcsImplHeader));
1037 here, because I can't send converse messages in the
1038 communication thread. I *can* poke this message into
1039 any convenient processor's queue, though: (OSL, 9/14/2000)
1041 int pe=0;/*<- node-local processor number. Any one will do.*/
1042 void *cmsg=(void *)CcsImpl_ccs2converse(hdr,msg.data+sizeof(CcsImplHeader),NULL);
1043 MACHSTATE(2,"Incoming CCS request");
1044 if (cmsg!=NULL) CmiPushPE(pe,cmsg);
1046 #endif
1047 #ifdef __FAULT__
1048 else if(strcmp(msg.header.type,"crashnode")==0) {
1049 crash_node_handle(&msg);
1051 else if(strcmp(msg.header.type,"initnodetab")==0) {
1052 /** A processor crashed and got recreated. So charmrun sent
1053 across the whole nodetable data to update this processor*/
1054 node_addresses_store(&msg);
1055 // fprintf(stdout,"nodetable added %d\n",CmiMyPe());
1057 #endif
1058 else if(strcmp(msg.header.type,"barrier")==0) {
1059 barrierReceived = 1;
1061 else if(strcmp(msg.header.type,"barrier0")==0) {
1062 barrierReceived = 2;
1064 else {
1065 /* We do not use KillEveryOne here because it calls CmiMyPe(),
1066 * which is not available to the communication thread on an SMP version.
1068 /* CmiPrintf("Unknown message: %s\n", msg.header.type); */
1069 charmrun_abort("ERROR> Unrecognized message from charmrun.\n");
1070 machine_exit(1);
1073 MACHSTATE(2,"ctrl_getone done")
1074 ChMessage_free(&msg);
1077 #if CMK_CCS_AVAILABLE && !NODE_0_IS_CONVHOST
1078 /*Deliver this reply data to this reply socket.
1079 The data is forwarded to CCS server via charmrun.*/
1080 void CcsImpl_reply(CcsImplHeader *hdr,int repLen,const void *repData)
1082 MACHSTATE(2,"Outgoing CCS reply");
1083 ctrl_sendone_locking("reply_fw",(const char *)hdr,sizeof(CcsImplHeader),
1084 repData,repLen);
1085 MACHSTATE(1,"Outgoing CCS reply away");
1087 #endif
1089 /*****************************************************************************
1091 * CmiPrintf, CmiError, CmiScanf
1093 *****************************************************************************/
1094 static void InternalWriteToTerminal(int isStdErr,const char *str,int len);
1095 static void InternalPrintf(const char *f, va_list l)
1097 ChMessage replymsg;
1098 char *buffer = CmiTmpAlloc(PRINTBUFSIZE);
1099 CmiStdoutFlush();
1100 vsprintf(buffer, f, l);
1101 if(Cmi_syncprint) {
1102 CmiCommLock();
1103 ctrl_sendone_nolock("printsyn", buffer,strlen(buffer)+1,NULL,0);
1104 ChMessage_recv(Cmi_charmrun_fd,&replymsg);
1105 ChMessage_free(&replymsg);
1106 CmiCommUnlock();
1107 } else {
1108 ctrl_sendone_locking("print", buffer,strlen(buffer)+1,NULL,0);
1110 InternalWriteToTerminal(0,buffer,strlen(buffer));
1111 CmiTmpFree(buffer);
1114 static void InternalError(const char *f, va_list l)
1116 ChMessage replymsg;
1117 char *buffer = CmiTmpAlloc(PRINTBUFSIZE);
1118 CmiStdoutFlush();
1119 vsprintf(buffer, f, l);
1120 if(Cmi_syncprint) {
1121 ctrl_sendone_locking("printerrsyn", buffer,strlen(buffer)+1,NULL,0);
1122 CmiCommLock();
1123 ChMessage_recv(Cmi_charmrun_fd,&replymsg);
1124 ChMessage_free(&replymsg);
1125 CmiCommUnlock();
1126 } else {
1127 ctrl_sendone_locking("printerr", buffer,strlen(buffer)+1,NULL,0);
1129 InternalWriteToTerminal(1,buffer,strlen(buffer));
1130 CmiTmpFree(buffer);
1133 static int InternalScanf(char *fmt, va_list l)
1135 ChMessage replymsg;
1136 char *ptr[20];
1137 char *p; int nargs, i;
1138 nargs=0;
1139 p=fmt;
1140 while (*p) {
1141 if ((p[0]=='%')&&(p[1]=='*')) { p+=2; continue; }
1142 if ((p[0]=='%')&&(p[1]=='%')) { p+=2; continue; }
1143 if (p[0]=='%') { nargs++; p++; continue; }
1144 if (*p=='\n') *p=' '; p++;
1146 if (nargs > 18) KillEveryone("CmiScanf only does 18 args.\n");
1147 for (i=0; i<nargs; i++) ptr[i]=va_arg(l, char *);
1148 CmiLock(Cmi_scanf_mutex);
1149 if (Cmi_charmrun_fd!=-1)
1150 {/*Send charmrun the format string*/
1151 ctrl_sendone_locking("scanf", fmt, strlen(fmt)+1,NULL,0);
1152 /*Wait for the reply (characters to scan) from charmrun*/
1153 CmiCommLock();
1154 ChMessage_recv(Cmi_charmrun_fd,&replymsg);
1155 i = sscanf((char*)replymsg.data, fmt,
1156 ptr[ 0], ptr[ 1], ptr[ 2], ptr[ 3], ptr[ 4], ptr[ 5],
1157 ptr[ 6], ptr[ 7], ptr[ 8], ptr[ 9], ptr[10], ptr[11],
1158 ptr[12], ptr[13], ptr[14], ptr[15], ptr[16], ptr[17]);
1159 ChMessage_free(&replymsg);
1160 CmiCommUnlock();
1161 } else
1162 {/*Just do the scanf normally*/
1163 i=scanf(fmt, ptr[ 0], ptr[ 1], ptr[ 2], ptr[ 3], ptr[ 4], ptr[ 5],
1164 ptr[ 6], ptr[ 7], ptr[ 8], ptr[ 9], ptr[10], ptr[11],
1165 ptr[12], ptr[13], ptr[14], ptr[15], ptr[16], ptr[17]);
1167 CmiUnlock(Cmi_scanf_mutex);
1168 return i;
1170 #if CMK_CMIPRINTF_IS_A_BUILTIN
1172 /*New stdarg.h declarations*/
1173 void CmiPrintf(const char *fmt, ...)
1175 CpdSystemEnter();
1177 va_list p; va_start(p, fmt);
1178 if (Cmi_charmrun_fd!=-1)
1179 InternalPrintf(fmt, p);
1180 else
1181 vfprintf(stdout,fmt,p);
1182 va_end(p);
1184 CpdSystemExit();
1187 void CmiError(const char *fmt, ...)
1189 CpdSystemEnter();
1191 va_list p; va_start (p, fmt);
1192 if (Cmi_charmrun_fd!=-1)
1193 InternalError(fmt, p);
1194 else
1195 vfprintf(stderr,fmt,p);
1196 va_end(p);
1198 CpdSystemExit();
1201 int CmiScanf(const char *fmt, ...)
1203 int i;
1204 CpdSystemEnter();
1206 va_list p; va_start(p, fmt);
1207 i = InternalScanf((char *)fmt, p);
1208 va_end(p);
1210 CpdSystemExit();
1211 return i;
1214 #endif
1216 /***************************************************************************
1217 * Output redirection:
1218 * When people don't use CkPrintf, like above, we'd still like to be able
1219 * to collect their output. Thus we make a pipe and dup2 it to stdout,
1220 * which lets us read the characters sent to stdout at our lesiure.
1221 ***************************************************************************/
1223 /*Can read from stdout or stderr using these fd's*/
1224 static int readStdout[2];
1225 static int writeStdout[2]; /*The original stdout/stderr sockets*/
1226 static int serviceStdout[2]; /*(bool) Normally zero; one if service needed.*/
1227 #define readStdoutBufLen (16*1024)
1228 static char readStdoutBuf[readStdoutBufLen+1]; /*Protected by comm. lock*/
1229 static int servicingStdout;
1231 /*Initialization-- should only be called once per node*/
1232 static void CmiStdoutInit(void) {
1233 int i;
1234 if (Cmi_charmrun_fd==-1) return; /* standalone mode */
1236 /*There's some way to do this same thing in windows, but I don't know how*/
1237 #if !defined(_WIN32) || defined(__CYGWIN__)
1238 /*Prevent buffering in stdio library:*/
1239 setbuf(stdout,NULL); setbuf(stderr,NULL);
1241 /*Reopen stdout and stderr fd's as new pipes:*/
1242 for (i=0;i<2;i++) {
1243 int pair[2];
1244 int srcFd=1+i; /* 1 is stdout; 2 is stderr */
1246 /*First, save a copy of the original stdout*/
1247 writeStdout[i]=dup(srcFd);
1248 #if 0
1249 /*Build a pipe to connect to stdout (4kb buffer, but no SIGIO...)*/
1250 if (-1==pipe(pair)) {perror("building stdio redirection pipe"); exit(1);}
1251 #else
1252 /* UNIX socket (16kb default buffer, and works with SIGIO!) */
1253 if (-1==socketpair(PF_UNIX,SOCK_STREAM,0,pair))
1254 {perror("building stdio redirection socketpair"); exit(1);}
1255 #endif
1256 readStdout[i]=pair[0]; /*We get the read end of pipe*/
1257 if (-1==dup2(srcFd,pair[1])) {perror("dup2 redirection pipe"); exit(1);}
1259 #if 0 /*Keep writes from blocking. This just drops excess output, which is bad.*/
1260 CmiEnableNonblockingIO(srcFd);
1261 #endif
1262 //NOTSURE #if CMK_SHARED_VARS_UNAVAILABLE
1263 #if !CMK_SMP
1264 if (Cmi_asyncio)
1266 /*No communication thread-- get a SIGIO on each write(), which keeps the buffer clean*/
1267 CmiEnableAsyncIO(readStdout[i]);
1269 #endif
1271 #else
1272 /*Windows system-- just fake reads for now*/
1273 # ifndef read
1274 # define read(x,y,z) 0
1275 # endif
1276 # ifndef write
1277 # define write(x,y,z)
1278 # endif
1279 #endif
1282 /*Sends data to original stdout (e.g., for ++debug or ++in-xterm)*/
1283 static void InternalWriteToTerminal(int isStdErr,const char *str,int len)
1285 write(writeStdout[isStdErr],str,len);
1289 Service this particular stdout pipe.
1290 Must hold comm. lock.
1292 static void CmiStdoutServiceOne(int i) {
1293 int nBytes;
1294 const static char *cmdName[2]={"print","printerr"};
1295 servicingStdout=1;
1296 while(1) {
1297 const char *tooMuchWarn=NULL; int tooMuchLen=0;
1298 if (!skt_select1(readStdout[i],0)) break; /*Nothing to read*/
1299 nBytes=read(readStdout[i],readStdoutBuf,readStdoutBufLen);
1300 if (nBytes<=0) break; /*Nothing to send*/
1302 /*Send these bytes off to charmrun*/
1303 readStdoutBuf[nBytes]=0; /*Zero-terminate read string*/
1304 nBytes++; /*Include zero-terminator in message to charmrun*/
1306 if (nBytes>=readStdoutBufLen-100)
1307 { /*We must have filled up our output pipe-- most output libraries
1308 don't handle this well (e.g., glibc printf just drops the line).*/
1310 tooMuchWarn="\nWARNING: Too much output at once-- possible output discontinuity!\n"
1311 "Use CkPrintf to avoid discontinuity (and this warning).\n\n";
1312 nBytes--; /*Remove terminator from user's data*/
1313 tooMuchLen=strlen(tooMuchWarn)+1;
1315 ctrl_sendone_nolock(cmdName[i],readStdoutBuf,nBytes,
1316 tooMuchWarn,tooMuchLen);
1318 InternalWriteToTerminal(i,readStdoutBuf,nBytes);
1320 servicingStdout=0;
1321 serviceStdout[i]=0; /*This pipe is now serviced*/
1324 /*Service all stdout pipes, whether it looks like they need it
1325 or not. Used when you aren't sure if select() has been called recently.
1326 Must hold comm. lock.
1328 static void CmiStdoutServiceAll(void) {
1329 int i;
1330 for (i=0;i<2;i++) {
1331 if (readStdout[i]==0) continue; /*Pipe not open*/
1332 CmiStdoutServiceOne(i);
1336 /*Service any outstanding stdout pipes.
1337 Must hold comm. lock.
1339 static void CmiStdoutService(void) {
1340 CmiStdoutServiceAll();
1343 /*Add our pipes to the pile for select() or poll().
1344 Both can be called with or without the comm. lock.
1346 static void CmiStdoutAdd(CMK_PIPE_PARAM) {
1347 int i;
1348 for (i=0;i<2;i++) {
1349 if (readStdout[i]==0) continue; /*Pipe not open*/
1350 CMK_PIPE_ADDREAD(readStdout[i]);
1353 static void CmiStdoutCheck(CMK_PIPE_PARAM) {
1354 int i;
1355 for (i=0;i<2;i++) {
1356 if (readStdout[i]==0) continue; /*Pipe not open*/
1357 if (CMK_PIPE_CHECKREAD(readStdout[i])) serviceStdout[i]=1;
1360 static int CmiStdoutNeedsService(void) {
1361 return (serviceStdout[0]!=0 || serviceStdout[1]!=0);
1364 /*Called every few milliseconds to flush the stdout pipes*/
1365 static void CmiStdoutFlush(void) {
1366 if (servicingStdout) return; /* might be called by SIGALRM */
1367 CmiCommLockOrElse( return; )
1368 CmiCommLock();
1369 CmiStdoutServiceAll();
1370 CmiCommUnlock();
1373 /***************************************************************************
1374 * Message Delivery:
1376 ***************************************************************************/
1378 #include "machine-dgram.c"
1381 /*****************************************************************************
1383 * node_addresses
1385 * These two functions fill the node-table.
1388 * This node, like all others, first sends its own address to charmrun
1389 * using this command:
1391 * Type: nodeinfo
1392 * Data: Big-endian 4-byte ints
1393 * <my-node #><Dataport>
1395 * When charmrun has all the addresses, he sends this table to me:
1397 * Type: nodes
1398 * Data: Big-endian 4-byte ints
1399 * <number of nodes n>
1400 * <#PEs><IP><Dataport> Node 0
1401 * <#PEs><IP><Dataport> Node 1
1402 * ...
1403 * <#PEs><IP><Dataport> Node n-1
1405 *****************************************************************************/
1407 #if CMK_USE_IBVERBS
1408 void copyInfiAddr(ChInfiAddr *qpList);
1409 #endif
1411 #if CMK_IBVERBS_FAST_START
1412 static void send_partial_init()
1414 ChMessageInt_t nodeNo = ChMessageInt_new(_Cmi_mynode);
1415 ctrl_sendone_nolock("partinit",(const char *)&(nodeNo),sizeof(nodeNo),NULL,0);
1417 #endif
1420 /*Note: node_addresses_obtain is called before starting
1421 threads, so no locks are needed (or valid!)*/
1422 static void node_addresses_obtain(char **argv)
1424 ChMessage nodetabmsg; /* info about all nodes*/
1425 MACHSTATE(3,"node_addresses_obtain { ");
1426 if (Cmi_charmrun_fd==-1)
1427 {/*Standalone-- fake a single-node nodetab message*/
1428 int npes=1;
1429 ChSingleNodeinfo *fakeTab;
1430 ChMessage_new("nodeinfo",sizeof(ChSingleNodeinfo),&nodetabmsg);
1431 fakeTab=(ChSingleNodeinfo *)(nodetabmsg.data);
1432 CmiGetArgIntDesc(argv,"+p",&npes,"Set the number of processes to create");
1433 //#if CMK_SHARED_VARS_UNAVAILABLE
1434 #if !CMK_SMP
1435 if (npes!=1) {
1436 fprintf(stderr,
1437 "To use multiple processors, you must run this program as:\n"
1438 " > charmrun +p%d %s <args>\n"
1439 "or build the %s-smp version of Charm++.\n",
1440 npes,argv[0],CMK_MACHINE_NAME);
1441 exit(1);
1443 #else
1444 /* standalone smp version reads ppn */
1445 if (CmiGetArgInt(argv, "+ppn", &_Cmi_mynodesize) ||
1446 CmiGetArgInt(argv, "++ppn", &_Cmi_mynodesize) )
1447 npes = _Cmi_mynodesize;
1448 #endif
1449 /*This is a stupid hack: we expect the *number* of nodes
1450 followed by ChNodeinfo structs; so we use a ChSingleNodeinfo
1451 (which happens to have exactly that layout!) and stuff
1452 a 1 into the "node number" slot
1454 fakeTab->nodeNo=ChMessageInt_new(1); /* <- hack */
1455 fakeTab->info.nPE=ChMessageInt_new(npes);
1456 fakeTab->info.dataport=ChMessageInt_new(0);
1457 fakeTab->info.IP=_skt_invalid_ip;
1459 else
1460 { /*Contact charmrun for machine info.*/
1461 ChSingleNodeinfo me;
1463 me.nodeNo=ChMessageInt_new(_Cmi_mynode);
1465 #if CMK_USE_IBVERBS
1467 int qpListSize = (_Cmi_numnodes-1)*sizeof(ChInfiAddr);
1468 me.info.qpList = malloc(qpListSize);
1469 copyInfiAddr(me.info.qpList);
1470 MACHSTATE1(3,"me.info.qpList created and copied size %d bytes",qpListSize);
1471 ctrl_sendone_nolock("initnode",(const char *)&me,sizeof(me),(const char *)me.info.qpList,qpListSize);
1472 free(me.info.qpList);
1474 #else
1475 /*The nPE fields are set by charmrun--
1476 these values don't matter.
1477 Set IP in case it is mpiexec mode where charmrun does not have IP yet
1479 me.info.nPE=ChMessageInt_new(0);
1480 /* me.info.IP=_skt_invalid_ip; */
1481 me.info.IP=skt_innode_my_ip();
1482 me.info.mach_id=ChMessageInt_new(Cmi_mach_id);
1483 #if CMK_USE_IBUD
1484 me.info.qp.lid=ChMessageInt_new(context->localAddr.lid);
1485 me.info.qp.qpn=ChMessageInt_new(context->localAddr.qpn);
1486 me.info.qp.psn=ChMessageInt_new(context->localAddr.psn);
1487 MACHSTATE3(3,"IBUD Information lid=%i qpn=%i psn=%i\n",me.info.qp.lid,me.info.qp.qpn,me.info.qp.psn);
1488 #endif
1489 me.info.dataport=ChMessageInt_new(dataport);
1491 /*Send our node info. to charmrun.
1492 CommLock hasn't been initialized yet--
1493 use non-locking version*/
1494 ctrl_sendone_nolock("initnode",(const char *)&me,sizeof(me),NULL,0);
1495 MACHSTATE1(5,"send initnode - dataport:%d", dataport);
1496 #endif //CMK_USE_IBVERBS
1498 MACHSTATE(3,"initnode sent");
1500 /*We get the other node addresses from a message sent
1501 back via the charmrun control port.*/
1502 if (!skt_select1(Cmi_charmrun_fd,1200*1000)){
1503 CmiAbort("Timeout waiting for nodetab!\n");
1505 MACHSTATE(2,"recv initnode {");
1506 ChMessage_recv(Cmi_charmrun_fd,&nodetabmsg);
1507 MACHSTATE(2,"} recv initnode");
1509 //#if CMK_USE_IBVERBS
1510 //#else
1511 node_addresses_store(&nodetabmsg);
1512 ChMessage_free(&nodetabmsg);
1513 //#endif
1514 MACHSTATE(3,"} node_addresses_obtain ");
1518 /***********************************************************************
1519 * DeliverOutgoingMessage()
1521 * This function takes care of delivery of outgoing messages from the
1522 * sender end. Broadcast messages are divided into sets of messages that
1523 * are bound to the local node, and to remote nodes. For local
1524 * transmission, the messages are directly pushed into the recv
1525 * queues. For non-local transmission, the function DeliverViaNetwork()
1526 * is called
1527 ***********************************************************************/
1528 int DeliverOutgoingMessage(OutgoingMsg ogm)
1530 int i, rank, dst; OtherNode node;
1532 int network = 1;
1534 dst = ogm->dst;
1536 //printf("deliver outgoing message, dest: %d \n", dst);
1537 #ifndef CMK_OPTIMIZE
1538 if (dst<0 || dst>=CmiNumPes())
1539 CmiAbort("Send to out-of-bounds processor!");
1540 #endif
1541 node = nodes_by_pe[dst];
1542 rank = dst - node->nodestart;
1543 if (node->nodestart != Cmi_nodestart) {
1544 #if !CMK_SMP_NOT_RELAX_LOCK
1545 CmiCommLock();
1546 #endif
1547 DeliverViaNetwork(ogm, node, rank, DGRAM_ROOTPE_MASK, 0);
1548 GarbageCollectMsg(ogm);
1549 #if !CMK_SMP_NOT_RELAX_LOCK
1550 CmiCommUnlock();
1551 #endif
1553 #if CMK_MULTICORE
1554 network = 0;
1555 #endif
1556 return network;
1560 * Set up an OutgoingMsg structure for this message.
1562 static OutgoingMsg PrepareOutgoing(CmiState cs,int pe,int size,int freemode,char *data) {
1563 OutgoingMsg ogm;
1564 MallocOutgoingMsg(ogm);
1565 MACHSTATE2(2,"Preparing outgoing message for pe %d, size %d",pe,size);
1566 ogm->size = size;
1567 ogm->data = data;
1568 ogm->src = cs->pe;
1569 ogm->dst = pe;
1570 ogm->freemode = freemode;
1571 ogm->refcount = 0;
1572 return (CmiCommHandle)ogm;
1576 /******************************************************************************
1578 * CmiGeneralSend
1580 * Description: This is a generic message sending routine. All the
1581 * converse message send functions are implemented in terms of this
1582 * function. (By setting appropriate flags (eg freemode) that tell
1583 * CmiGeneralSend() how exactly to handle the particular case of
1584 * message send)
1586 *****************************************************************************/
1588 //CmiCommHandle CmiGeneralSend(int pe, int size, int freemode, char *data)
1589 CmiCommHandle LrtsSendFunc(int destNode, int pe, int size, char *data, int freemode)
1591 int sendonnetwork;
1592 CmiState cs = CmiGetState(); OutgoingMsg ogm;
1593 MACHSTATE(1,"CmiGeneralSend {");
1595 CmiMsgHeaderSetLength(data, size);
1596 ogm=PrepareOutgoing(cs,pe,size,freemode,data);
1598 #if CMK_SMP_NOT_RELAX_LOCK
1599 CmiCommLock();
1600 #endif
1602 sendonnetwork = DeliverOutgoingMessage(ogm);
1604 #if CMK_SMP_NOT_RELAX_LOCK
1605 CmiCommUnlock();
1606 #endif
1608 MACHSTATE(1,"} LrtsSend");
1609 return (CmiCommHandle)ogm;
1613 /******************************************************************************
1615 * Comm Handle manipulation.
1617 *****************************************************************************/
1619 #if ! CMK_MULTICAST_LIST_USE_COMMON_CODE
1621 /*****************************************************************************
1623 * NET version List-Cast and Multicast Code
1625 ****************************************************************************/
1627 void LrtsSyncListSendFn(int npes, int *pes, int len, char *msg)
1629 int i;
1630 for(i=0;i<npes;i++) {
1631 CmiReference(msg);
1632 CmiSyncSendAndFree(pes[i], len, msg);
1636 CmiCommHandle LrtsAsyncListSendFn(int npes, int *pes, int len, char *msg)
1638 CmiError("ListSend not implemented.");
1639 return (CmiCommHandle) 0;
1643 because in all net versions, the message buffer after CmiSyncSendAndFree
1644 returns is not changed, we can use memory reference trick to avoid
1645 memory copying here
1647 void LrtsFreeListSendFn(int npes, int *pes, int len, char *msg)
1649 int i;
1650 for(i=0;i<npes;i++) {
1651 CmiReference(msg);
1652 CmiSyncSendAndFree(pes[i], len, msg);
1654 CmiFree(msg);
1657 #endif
1660 void LrtsDrainResources()
1664 void LrtsPostNonLocal()
1668 /* Network progress function is used to poll the network when for
1669 messages. This flushes receive buffers on some implementations*/
1671 #if CMK_MACHINE_PROGRESS_DEFINED
1672 void CmiMachineProgressImpl(){
1673 LrtsAdvanceCommunication(0);
1675 #endif
1677 void LrtsAdvanceCommunication(int whileidle)
1679 CommunicationServerNet(0, COMM_SERVER_FROM_WORKER);
1682 /******************************************************************************
1684 * Main code, Init, and Exit
1686 *****************************************************************************/
1688 #if !CMK_BARRIER_USE_COMMON_CODE
1690 /* happen at node level */
1691 /* must be called on every PE including communication processors */
1692 int CmiBarrier()
1694 int len, size, i;
1695 int status;
1696 int numnodes = CmiNumNodes();
1697 static int barrier_phase = 0;
1699 if (Cmi_charmrun_fd == -1) return 0; // standalone
1700 if (numnodes == 1) {
1701 CmiNodeAllBarrier();
1702 return 0;
1705 if (CmiMyRank() == 0) {
1706 ctrl_sendone_locking("barrier",NULL,0,NULL,0);
1707 while (barrierReceived != 1) {
1708 CmiCommLock();
1709 ctrl_getone();
1710 CmiCommUnlock();
1712 barrierReceived = 0;
1713 barrier_phase ++;
1716 CmiNodeAllBarrier();
1717 /* printf("[%d] OUT of barrier %d \n", CmiMyPe(), barrier_phase); */
1718 return 0;
1722 int CmiBarrierZero()
1724 int i;
1725 int numnodes = CmiNumNodes();
1726 ChMessage msg;
1728 if (Cmi_charmrun_fd == -1) return 0; // standalone
1729 if (numnodes == 1) {
1730 CmiNodeAllBarrier();
1731 return 0;
1734 if (CmiMyRank() == 0) {
1735 char str[64];
1736 sprintf(str, "%d", CmiMyNode());
1737 ctrl_sendone_locking("barrier0",str,strlen(str)+1,NULL,0);
1738 if (CmiMyNode() == 0) {
1739 while (barrierReceived != 2) {
1740 CmiCommLock();
1741 ctrl_getone();
1742 CmiCommUnlock();
1744 barrierReceived = 0;
1748 CmiNodeAllBarrier();
1749 return 0;
1752 #endif
1754 /******************************************************************************
1756 * Main code, Init, and Exit
1758 *****************************************************************************/
1760 void LrtsPreCommonInit(int everReturn)
1762 CmiNodeAllBarrier();
1765 void LrtsPostCommonInit(int everReturn)
1767 CmiIdleState *s=CmiNotifyGetState();
1769 /* better to show the status here */
1770 if (CmiMyPe() == 0) {
1771 if (Cmi_netpoll == 1) {
1772 CmiPrintf("Charm++> scheduler running in netpoll mode.\n");
1774 #if CMK_SHARED_VARS_UNAVAILABLE
1775 else {
1776 if (CmiMemoryIs(CMI_MEMORY_IS_OS))
1777 CmiAbort("Charm++ Fatal Error: interrupt mode does not work with default system memory allocator. Run with +netpoll to disable the interrupt.");
1779 #endif
1782 #if MEMORYUSAGE_OUTPUT
1783 memoryusage_counter = 0;
1784 #endif
1786 CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE,
1787 (CcdVoidFn) CmiNotifyBeginIdle, (void *) s);
1788 CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,
1789 (CcdVoidFn) CmiNotifyStillIdle, (void *) s);
1792 #if CMK_SHARED_VARS_UNAVAILABLE
1793 if (Cmi_netpoll) /*Repeatedly call CommServer*/
1794 CcdCallOnConditionKeep(CcdPERIODIC,
1795 (CcdVoidFn) CommunicationPeriodic, NULL);
1796 else /*Only need this for retransmits*/
1797 CcdCallOnConditionKeep(CcdPERIODIC_10ms,
1798 (CcdVoidFn) CommunicationPeriodic, NULL);
1799 #endif
1801 if (CmiMyRank()==0 && Cmi_charmrun_fd!=-1) {
1802 CcdCallOnConditionKeep(CcdPERIODIC_10ms, (CcdVoidFn) CmiStdoutFlush, NULL);
1803 #if CMK_SHARED_VARS_UNAVAILABLE
1804 if (!Cmi_asyncio) {
1805 /* gm cannot live with setitimer */
1806 CcdCallFnAfter((CcdVoidFn)pingCharmrunPeriodic,NULL,1000);
1808 else {
1809 /*Occasionally ping charmrun, to test if it's dead*/
1810 struct itimerval i;
1811 CmiSignal(SIGALRM, 0, 0, pingCharmrun);
1812 #if MEMORYUSAGE_OUTPUT
1813 i.it_interval.tv_sec = 0;
1814 i.it_interval.tv_usec = 1000000/MEMORYUSAGE_OUTPUT_FREQ;
1815 i.it_value.tv_sec = 0;
1816 i.it_value.tv_usec = 1000000/MEMORYUSAGE_OUTPUT_FREQ;
1817 #else
1818 i.it_interval.tv_sec = 1;
1819 i.it_interval.tv_usec = 0;
1820 i.it_value.tv_sec = 1;
1821 i.it_value.tv_usec = 0;
1822 #endif
1823 setitimer(ITIMER_REAL, &i, NULL);
1826 #if ! CMK_USE_IBVERBS
1827 /*Occasionally check for retransmissions, outgoing acks, etc.*/
1828 /*no need for GM case */
1829 CcdCallFnAfter((CcdVoidFn)CommunicationsClockCaller,NULL,Cmi_comm_clock_delay);
1830 #endif
1831 #endif
1833 /*Initialize the clock*/
1834 Cmi_clock=GetClock();
1837 #ifdef IGET_FLOWCONTROL
1838 /* Call the function once to determine the amount of physical memory available */
1839 getAvailSysMem();
1840 /* Call the function to periodically call the token adapt function */
1841 CcdCallFnAfter((CcdVoidFn)TokenUpdatePeriodic, NULL, 2000); // magic number of 2000ms
1842 CcdCallOnConditionKeep(CcdPERIODIC_10s, // magic number of PERIOD 10s
1843 (CcdVoidFn) TokenUpdatePeriodic, NULL);
1844 #endif
1846 #ifdef CMK_RANDOMLY_CORRUPT_MESSAGES
1847 srand((int)(1024.0*CmiWallTimer()));
1848 if (CmiMyPe()==0)
1849 CmiPrintf("Charm++: Machine layer will randomly corrupt every %d'th message (rand %d)\n",
1850 CMK_RANDOMLY_CORRUPT_MESSAGES,rand());
1851 #endif
1853 #ifdef __ONESIDED_IMPL
1854 #ifdef __ONESIDED_NO_HARDWARE
1855 putSrcHandler = CmiRegisterHandler((CmiHandler)handlePutSrc);
1856 putDestHandler = CmiRegisterHandler((CmiHandler)handlePutDest);
1857 getSrcHandler = CmiRegisterHandler((CmiHandler)handleGetSrc);
1858 getDestHandler = CmiRegisterHandler((CmiHandler)handleGetDest);
1859 #endif
1860 #ifdef __ONESIDED_GM_HARDWARE
1861 getSrcHandler = CmiRegisterHandler((CmiHandler)handleGetSrc);
1862 getDestHandler = CmiRegisterHandler((CmiHandler)handleGetDest);
1863 #endif
1864 #endif
1868 void LrtsExit()
1870 MACHSTATE(2,"ConverseExit {");
1871 machine_initiated_shutdown=1;
1873 CmiNodeBarrier(); /* single node SMP, make sure every rank is done */
1874 if (CmiMyRank()==0) CmiStdoutFlush();
1875 if (Cmi_charmrun_fd==-1) {
1876 if (CmiMyRank() == 0) exit(0); /*Standalone version-- just leave*/
1877 else while (1) CmiYield();
1879 else {
1880 ctrl_sendone_locking("ending",NULL,0,NULL,0); /* this causes charmrun to go away, every PE needs to report */
1881 #if CMK_SHARED_VARS_UNAVAILABLE
1882 Cmi_check_delay = 1.0; /* speed up checking of charmrun */
1883 while (1) CommunicationServerNet(500, COMM_SERVER_FROM_WORKER);
1884 #elif CMK_MULTICORE
1885 if (!Cmi_commthread && CmiMyRank()==0) {
1886 Cmi_check_delay = 1.0; /* speed up checking of charmrun */
1887 while (1) CommunicationServerNet(500, COMM_SERVER_FROM_WORKER);
1889 #endif
1891 MACHSTATE(2,"} ConverseExit");
1895 static void set_signals(void)
1897 if(!Cmi_truecrash) {
1898 signal(SIGSEGV, KillOnAllSigs);
1899 signal(SIGFPE, KillOnAllSigs);
1900 signal(SIGILL, KillOnAllSigs);
1901 signal(SIGINT, KillOnAllSigs);
1902 signal(SIGTERM, KillOnAllSigs);
1903 signal(SIGABRT, KillOnAllSigs);
1904 # if !defined(_WIN32) || defined(__CYGWIN__) /*UNIX-only signals*/
1905 signal(SIGQUIT, KillOnAllSigs);
1906 signal(SIGBUS, KillOnAllSigs);
1907 # if CMK_HANDLE_SIGUSR
1908 signal(SIGUSR1, HandleUserSignals);
1909 signal(SIGUSR2, HandleUserSignals);
1910 # endif
1911 # endif /*UNIX*/
1915 /*Socket idle function to use before addresses have been
1916 obtained. During the real program, we idle with CmiYield.
1918 static void obtain_idleFn(void) {sleep(0);}
1920 static int net_default_skt_abort(int code,const char *msg)
1922 fprintf(stderr,"Fatal socket error: code %d-- %s\n",code,msg);
1923 machine_exit(1);
1924 return -1;
1927 void LrtsInit(int *argc, char ***argv, int *numNodes, int *myNodeID)
1929 #if CMK_USE_HP_MAIN_FIX
1930 #if FOR_CPLUS
1931 _main(argc,*argv);
1932 #endif
1933 #endif
1934 Cmi_netpoll = 0;
1935 #if CMK_NETPOLL
1936 Cmi_netpoll = 1;
1937 #endif
1938 #if CMK_WHEN_PROCESSOR_IDLE_USLEEP
1939 Cmi_idlepoll = 0;
1940 #else
1941 Cmi_idlepoll = 1;
1942 #endif
1943 Cmi_truecrash = 0;
1944 if (CmiGetArgFlagDesc(*argv,"+truecrash","Do not install signal handlers") ||
1945 CmiGetArgFlagDesc(*argv,"++debug",NULL /*meaning: don't show this*/)) Cmi_truecrash = 1;
1946 /* netpoll disable signal */
1947 if (CmiGetArgFlagDesc(*argv,"+netpoll","Do not use SIGIO--poll instead")) Cmi_netpoll = 1;
1948 if (CmiGetArgFlagDesc(*argv,"+netint","Use SIGIO")) Cmi_netpoll = 0;
1949 /* idlepoll use poll instead if sleep when idle */
1950 if (CmiGetArgFlagDesc(*argv,"+idlepoll","Do not sleep when idle")) Cmi_idlepoll = 1;
1951 /* idlesleep use sleep instead if busywait when idle */
1952 if (CmiGetArgFlagDesc(*argv,"+idlesleep","Make sleep calls when idle")) Cmi_idlepoll = 0;
1953 Cmi_syncprint = CmiGetArgFlagDesc(*argv,"+syncprint", "Flush each CmiPrintf to the terminal");
1955 Cmi_asyncio = 1;
1956 #if CMK_ASYNC_NOT_NEEDED
1957 Cmi_asyncio = 0;
1958 #endif
1959 if (CmiGetArgFlagDesc(*argv,"+asyncio","Use async IO")) Cmi_asyncio = 1;
1960 if (CmiGetArgFlagDesc(*argv,"+asynciooff","Don not use async IO")) Cmi_asyncio = 0;
1961 #if CMK_MULTICORE
1962 if (CmiGetArgFlagDesc(*argv,"+commthread","Use communication thread")) {
1963 Cmi_commthread = 1;
1964 #if CMK_SHARED_VARS_POSIX_THREADS_SMP
1965 _Cmi_noprocforcommthread = 1; /* worker thread go sleep */
1966 #endif
1967 if (CmiMyPe() == 0) CmiPrintf("Charm++> communication thread is launched in multicore version. \n");
1969 #endif
1971 skt_init();
1972 /* use special abort handler instead of default_skt_abort to
1973 prevent exit trapped by atexit_check() due to the exit() call */
1974 skt_set_abort(net_default_skt_abort);
1975 atexit(machine_atexit_check);
1976 parse_netstart();
1977 parse_magic();
1978 #if ! CMK_SMP && ! defined(_WIN32)
1979 /* only get forks in non-smp mode */
1980 parse_forks();
1981 #endif
1982 extract_args(*argv);
1983 log_init();
1984 Cmi_scanf_mutex = CmiCreateLock();
1986 /* NOTE: can not acutally call timer before timerInit ! GZ */
1987 MACHSTATE2(5,"Init: (netpoll=%d), (idlepoll=%d)",Cmi_netpoll,Cmi_idlepoll);
1989 skt_set_idle(obtain_idleFn);
1990 if (!skt_ip_match(Cmi_charmrun_IP,_skt_invalid_ip)) {
1991 set_signals();
1992 dataskt=skt_datagram(&dataport, Cmi_os_buffer_size);
1993 MACHSTATE2(5,"skt_connect at dataskt:%d Cmi_charmrun_port:%d",dataskt, Cmi_charmrun_port);
1994 Cmi_charmrun_fd = skt_connect(Cmi_charmrun_IP, Cmi_charmrun_port, 1800);
1995 MACHSTATE2(5,"Opened connection to charmrun at socket %d, dataport=%d", Cmi_charmrun_fd, dataport);
1996 skt_tcp_no_nagle(Cmi_charmrun_fd);
1997 CmiStdoutInit();
1998 } else {/*Standalone operation*/
1999 printf("Charm++: standalone mode (not using charmrun)\n");
2000 dataskt=-1;
2001 Cmi_charmrun_fd=-1;
2004 CmiMachineInit(*argv);
2006 node_addresses_obtain(*argv);
2007 MACHSTATE(5,"node_addresses_obtain done");
2009 CmiCommunicationInit(*argv);
2011 skt_set_idle(CmiYield);
2012 Cmi_check_delay = 1.0+0.25*_Cmi_numnodes;
2014 if (Cmi_charmrun_fd==-1) /*Don't bother with check in standalone mode*/
2015 Cmi_check_delay=1.0e30;
2020 #if CMK_CELL
2022 #include "spert_ppu.h"
2024 void machine_OffloadAPIProgress() {
2025 CmiCommLock();
2026 OffloadAPIProgress();
2027 CmiCommUnlock();
2029 #endif
2033 /*@}*/