static int IOLabelWriteLine( int fd, int rdwr, void *data ) { IOLabel *label = (IOLabel *)data; char buf[1024], *p; int n; MPIE_SYSCALL(n,read,( fd, buf, 1024 )); if (n == 0) { /* If read blocks, then returning a 0 is end-of-file */ return 1; /* ? EOF */ } p = buf; while (n > 0) { int c; if (label->lastNL) { if (label->label[0]) { fprintf( label->dest, "%s", label->label ); } label->lastNL = 0; } c = *p++; n--; if (fputc( c, label->dest ) != c) return 1; label->lastNL = (c == '\n'); } return 0; }
/*@ MPIE_IOLoop - Handle all registered I/O Input Parameters: . timeoutSeconds - Seconds until this routine should return with a timeout error. If negative, no timeout. If 0, return immediatedly after a nonblocking check for I/O. Return Value: Returns zero on success. Returns 'IOLOOP_TIMEOUT' if the timeout is reached and 'IOLOOP_ERROR' on other errors. @*/ int MPIE_IOLoop(int timeoutSeconds) { int i, maxfd, fd, nfds, rc = 0, rc2; fd_set readfds, writefds; int (*handler) (int, int, void *); struct timeval tv; /* Loop on the fds, with the timeout */ TimeoutInit(timeoutSeconds); while (1) { tv.tv_sec = TimeoutGetRemaining(); tv.tv_usec = 0; /* Determine the active FDs */ FD_ZERO(&readfds); FD_ZERO(&writefds); /* maxfd is the maximum active fd */ maxfd = -1; for (i = 0; i <= maxFD; i++) { if (handlesByFD[i].handler) { fd = handlesByFD[i].fd; if (handlesByFD[i].rdwr & IO_READ) { FD_SET(fd, &readfds); maxfd = i; } if (handlesByFD[i].rdwr & IO_WRITE) { FD_SET(fd, &writefds); maxfd = i; } } } if (maxfd < 0) break; /* DBG_PRINTF(("Calling select with readfds = %x writefds = %x\n", */ /* *(int *)&readfds, *(int*)&writefds)); */ MPIE_SYSCALL(nfds, select, (maxfd + 1, &readfds, &writefds, 0, &tv)); if (nfds < 0 && (errno == EINTR || errno == 0)) { /* Continuing through EINTR */ /* We allow errno == 0 as a synonym for EINTR. We've seen this * on Solaris; in addition, we set errno to 0 after a failed * waitpid in the process routines, and if the OS isn't careful, * the value of errno may get ECHILD instead of EINTR when the * signal handler returns (we suspect Linux of this problem), * which is why we have the signal handler in process.c reset * errno to 0 (we may need to allow ECHILD here (!)) */ /* FIXME: an EINTR may also mean that a process has exited * (SIGCHILD). If all processes have exited, we may want to * exit */ DBG_PRINTF(("errno = EINTR in select\n")); continue; } if (nfds < 0) { /* Serious error */ MPL_internal_sys_error_printf("select", errno, 0); break; } if (nfds == 0) { /* Timeout from select */ DBG_PRINTF(("Timeout in select\n")); return IOLOOP_TIMEOUT; } /* nfds > 0 */ DBG_PRINTF(("Found some fds to process (n = %d)\n", nfds)); for (fd = 0; fd <= maxfd; fd++) { if (FD_ISSET(fd, &writefds)) { handler = handlesByFD[fd].handler; if (handler) { rc = (*handler) (fd, IO_WRITE, handlesByFD[fd].extra_data); } if (rc == 1) { /* EOF? */ MPIE_SYSCALL(rc2, close, (fd)); handlesByFD[fd].rdwr = 0; FD_CLR(fd, &writefds); } } if (FD_ISSET(fd, &readfds)) { handler = handlesByFD[fd].handler; if (handler) { rc = (*handler) (fd, IO_READ, handlesByFD[fd].extra_data); } if (rc == 1) { /* EOF? */ MPIE_SYSCALL(rc2, close, (fd)); handlesByFD[fd].rdwr = 0; FD_CLR(fd, &readfds); } } } } DBG_PRINTF(("Returning from IOLOOP handler\n")); return 0; }
/* IO Handler for the listen socket Respond to a connection request by creating a new socket, which is then registered. Initialize the startup handshake. */ int PMIServAcceptFromPort( int fd, int rdwr, void *data ) { int newfd; struct sockaddr sock; socklen_t addrlen = sizeof(sock); int id; ProcessUniverse *univ = (ProcessUniverse *)data; ProcessWorld *pWorld = univ->worlds; ProcessApp *app; /* Get the new socket */ MPIE_SYSCALL(newfd,accept,( fd, &sock, &addrlen )); DBG_PRINTF(("Acquired new socket in accept (fd = %d)\n", newfd )); if (newfd < 0) { DBG(perror("Error on accept: " )); return newfd; } #ifdef FOO /* Mark this fd as non-blocking */ flags = fcntl( newfd, F_GETFL, 0 ); if (flags >= 0) { flags |= O_NDELAY; fcntl( newfd, F_SETFL, flags ); } #endif /* Make sure that exec'd processes don't get this fd */ fcntl( newfd, F_SETFD, FD_CLOEXEC ); /* Find the matching process. Do this by reading from the socket and getting the id value with which process was created. */ id = PMI_Init_port_connection( newfd ); if (id >= 0) { /* find the matching entry */ ProcessState *pState = 0; int nSoFar = 0; PMIProcess *pmiprocess; /* This code assigns processes to the states in a pWorld by using the id as the rank, and finding the corresponding process among the ranks */ while (pWorld) { app = pWorld->apps; while (app) { if (app->nProcess > id - nSoFar) { /* Found the matching app */ pState = app->pState + (id - nSoFar); break; } else { nSoFar += app->nProcess; } app = app->nextApp; } pWorld = pWorld->nextWorld; } if (!pState) { /* We have a problem */ MPL_error_printf( "Unable to find process with PMI_ID = %d in the universe", id ); return -1; } /* Now, initialize the connection */ /* Create the new process structure (see PMISetupFinishInServer for this step when a pre-existing FD is used */ DBG_PRINTF( ("Server connection to id = %d on fd %d\n", id, newfd )); pmiprocess = PMISetupNewProcess( newfd, pState ); PMI_Init_remote_proc( newfd, pmiprocess ); MPIE_IORegister( newfd, IO_READ, PMIServHandleInput, pmiprocess ); } else { /* Error, the id should never be less than zero or unset */ /* An alternative would be to dynamically assign the ranks as processes come in (but we'd still need to use the PMI_ID to identify the ProcessApp) */ DBG_PRINTF(("Found an invalid id\n" )); return -1; } /* Return success. */ return 0; }