HYD_status HYDT_bscu_wait_for_completion(int timeout) { int pgid, pid, ret, count, i, time_elapsed, time_left; struct timeval start, now; HYD_status status = HYD_SUCCESS; HYDU_FUNC_ENTER(); /* FIXME: We rely on gettimeofday here. This needs to detect the * timer type available and use that. Probably more of an MPL * functionality than Hydra's. */ gettimeofday(&start, NULL); /* Loop till all sockets have closed */ restart_wait: while (1) { count = 0; for (i = 0; i < HYD_bscu_fd_count; i++) { if (HYD_bscu_fd_list[i] == HYD_FD_CLOSED) continue; ret = HYDT_dmx_query_fd_registration(HYD_bscu_fd_list[i]); if (ret) { /* still registered */ count++; /* We still need to wait */ gettimeofday(&now, NULL); time_elapsed = (now.tv_sec - start.tv_sec); /* Ignore microsec granularity */ time_left = -1; if (timeout >= 0) { if (time_elapsed > timeout) { #if defined(HAVE_GETPGID) && defined(HAVE_SETSID) /* If we are able to get the process group ID, * send a signal to the entire process * group */ pgid = getpgid(HYD_bscu_pid_list[i]); killpg(pgid, SIGKILL); #else kill(HYD_bscu_pid_list[i], SIGKILL); #endif } else time_left = timeout - time_elapsed; } status = HYDT_dmx_wait_for_event(time_left); HYDU_ERR_POP(status, "error waiting for event\n"); /* Check if any processes terminated badly; if they * did, return an error. */ pid = waitpid(-1, &ret, WNOHANG); if (pid > 0) { /* Find the pid and mark it as complete */ for (i = 0; i < HYD_bscu_pid_count; i++) if (HYD_bscu_pid_list[i] == pid) { HYD_bscu_pid_list[i] = -1; break; } if (ret) { HYDU_ERR_SETANDJUMP(status, HYD_INTERNAL_ERROR, "one of the processes terminated badly; aborting\n"); } } goto restart_wait; } else HYD_bscu_fd_list[i] = HYD_FD_CLOSED; } if (count == 0) break; } /* Loop till all processes have completed */ while (1) { count = 0; for (i = 0; i < HYD_bscu_pid_count; i++) if (HYD_bscu_pid_list[i] != -1) count++; /* If there are no processes to wait, we are done */ if (count == 0) break; pid = waitpid(-1, &ret, WNOHANG); if (pid > 0) { /* Find the pid and mark it as complete */ for (i = 0; i < HYD_bscu_pid_count; i++) if (HYD_bscu_pid_list[i] == pid) { HYD_bscu_pid_list[i] = -1; break; } } } if (HYD_bscu_pid_list) { MPL_free(HYD_bscu_pid_list); HYD_bscu_pid_list = NULL; HYD_bscu_pid_count = 0; } if (HYD_bscu_fd_list) { MPL_free(HYD_bscu_fd_list); HYD_bscu_fd_list = NULL; HYD_bscu_fd_count = 0; } fn_exit: HYDU_FUNC_EXIT(); return status; fn_fail: goto fn_exit; }
int main(int argc, char **argv) { int i, count, pid, ret_status, sent, closed, ret, done; struct HYD_pmcd_hdr hdr; HYD_status status = HYD_SUCCESS; status = HYDU_dbg_init("proxy:unset"); HYDU_ERR_POP(status, "unable to initialization debugging\n"); status = HYDU_set_signal(SIGPIPE, signal_cb); HYDU_ERR_POP(status, "unable to set SIGPIPE\n"); status = HYDU_set_signal(SIGTSTP, signal_cb); HYDU_ERR_POP(status, "unable to set SIGTSTP\n"); status = HYDU_set_common_signals(signal_cb); HYDU_ERR_POP(status, "unable to set common signals\n"); status = init_params(); HYDU_ERR_POP(status, "Error initializing proxy params\n"); status = HYD_pmcd_pmip_get_params(argv); HYDU_ERR_POP(status, "bad parameters passed to the proxy\n"); status = HYDT_dmx_init(&HYD_pmcd_pmip.user_global.demux); HYDU_ERR_POP(status, "unable to initialize the demux engine\n"); status = HYDT_ftb_init(); HYDU_ERR_POP(status, "unable to initialize FTB\n"); /* See if HYDI_CONTROL_FD is set before trying to connect upstream */ ret = MPL_env2int("HYDI_CONTROL_FD", &HYD_pmcd_pmip.upstream.control); if (ret < 0) { HYDU_ERR_POP(status, "error reading HYDI_CONTROL_FD environment\n"); } else if (ret == 0) { status = HYDU_sock_connect(HYD_pmcd_pmip.upstream.server_name, HYD_pmcd_pmip.upstream.server_port, &HYD_pmcd_pmip.upstream.control, HYD_pmcd_pmip.local.retries, HYD_CONNECT_DELAY); HYDU_ERR_POP(status, "unable to connect to server %s at port %d (check for firewalls!)\n", HYD_pmcd_pmip.upstream.server_name, HYD_pmcd_pmip.upstream.server_port); } status = HYDU_sock_write(HYD_pmcd_pmip.upstream.control, &HYD_pmcd_pmip.local.id, sizeof(HYD_pmcd_pmip.local.id), &sent, &closed, HYDU_SOCK_COMM_MSGWAIT); HYDU_ERR_POP(status, "unable to send the proxy ID to the server\n"); if (closed) goto fn_fail; status = HYDT_dmx_register_fd(1, &HYD_pmcd_pmip.upstream.control, HYD_POLLIN, NULL, HYD_pmcd_pmip_control_cmd_cb); HYDU_ERR_POP(status, "unable to register fd\n"); while (1) { /* Wait for some event to occur */ status = HYDT_dmx_wait_for_event(-1); HYDU_ERR_POP(status, "demux engine error waiting for event\n"); /* Check to see if there's any open read socket left; if there * are, we will just wait for more events. */ count = 0; for (i = 0; i < HYD_pmcd_pmip.local.proxy_process_count; i++) { if (HYD_pmcd_pmip.downstream.out[i] != HYD_FD_CLOSED) count++; if (HYD_pmcd_pmip.downstream.err[i] != HYD_FD_CLOSED) count++; if (count) break; } if (!count) break; } /* Now wait for the processes to finish */ done = 0; while (1) { pid = waitpid(-1, &ret_status, 0); /* Find the pid and mark it as complete. */ if (pid > 0) for (i = 0; i < HYD_pmcd_pmip.local.proxy_process_count; i++) if (HYD_pmcd_pmip.downstream.pid[i] == pid) { if (HYD_pmcd_pmip.downstream.forced_cleanup) { /* If it is a forced cleanup, the exit status * is either already set or we have to ignore * it */ if (HYD_pmcd_pmip.downstream.exit_status[i] == -1) HYD_pmcd_pmip.downstream.exit_status[i] = 0; else HYD_pmcd_pmip.downstream.exit_status[i] = ret_status; } else { HYD_pmcd_pmip.downstream.exit_status[i] = ret_status; } done++; } /* If no more processes are pending, break out */ if (done == HYD_pmcd_pmip.local.proxy_process_count) break; /* Check if there are any messages from the launcher */ status = HYDT_dmx_wait_for_event(0); HYDU_IGNORE_TIMEOUT(status); HYDU_ERR_POP(status, "demux engine error waiting for event\n"); } /* Send the exit status upstream */ HYD_pmcd_init_header(&hdr); hdr.cmd = EXIT_STATUS; status = HYDU_sock_write(HYD_pmcd_pmip.upstream.control, &hdr, sizeof(hdr), &sent, &closed, HYDU_SOCK_COMM_MSGWAIT); HYDU_ERR_POP(status, "unable to send EXIT_STATUS command upstream\n"); HYDU_ASSERT(!closed, status); status = HYDU_sock_write(HYD_pmcd_pmip.upstream.control, HYD_pmcd_pmip.downstream.exit_status, HYD_pmcd_pmip.local.proxy_process_count * sizeof(int), &sent, &closed, HYDU_SOCK_COMM_MSGWAIT); HYDU_ERR_POP(status, "unable to return exit status upstream\n"); HYDU_ASSERT(!closed, status); status = HYDT_dmx_deregister_fd(HYD_pmcd_pmip.upstream.control); HYDU_ERR_POP(status, "unable to deregister fd\n"); close(HYD_pmcd_pmip.upstream.control); status = HYDT_dmx_finalize(); HYDU_ERR_POP(status, "error returned from demux finalize\n"); status = HYDT_ftb_finalize(); HYDU_ERR_POP(status, "unable to finalize FTB\n"); status = HYDT_bsci_finalize(); HYDU_ERR_POP(status, "unable to finalize the bootstrap device\n"); /* cleanup the params structure */ cleanup_params(); fn_exit: HYDU_dbg_finalize(); return status; fn_fail: /* kill all processes */ HYD_pmcd_pmip_send_signal(SIGKILL); goto fn_exit; }