/*free given mailbox*/ void free_mb(mailbox* mb){ if (mb == NULL) return; free_mb(mb->next); free_mail(mb->msg); if (mb != NULL) { kmem_cache_free(mbCache, mb); } }
/* free hashtable */ void free_ht(void){ int i; for (i = 0; i < HASHTABLE_SIZE; i++){ free_mb(all[i]); } }
int main(int argc, char *argv[]) { int ch; int exit; char *debug_level = NULL; char *timeout; program_name = argv[0]; pid = getpid(); noinput = false; while ((ch = getopt(argc, argv, "ion")) != -1) { switch (ch) { case 'i': multiple_inputs = true; break; case 'o': multiple_inputs = false; break; case 'n': // special output conc that takes no input if (!multiple_inputs) noinput = true; else usage(); break; case '?': default: usage(); } } argc -= optind; argv += optind; if (argc != 1) usage(); debug_level = getenv("DGSH_DEBUG_LEVEL"); if (debug_level != NULL) dgsh_debug_level = atoi(debug_level); signal(SIGALRM, dgsh_alarm_handler); if ((timeout = getenv("DGSH_TIMEOUT")) != NULL) alarm(atoi(timeout)); else alarm(DGSH_TIMEOUT); /* +1 for stdin when scatter/stdout when gather * +1 for stderr which is not used */ if (atoi(argv[0]) == 1) nfd = 2; else nfd = atoi(argv[0]) + 2; pi = (struct portinfo *)calloc(nfd, sizeof(struct portinfo)); chosen_mb = NULL; exit = pass_message_blocks(); if (exit == PS_RUN) { if (noinput) DPRINTF(1, "%s(): Special (no-input) conc communicated the solution", __func__); if (multiple_inputs) gather_input_fds(chosen_mb); else if (!noinput) // Output noinput conc has no job here scatter_input_fds(chosen_mb); exit = PS_COMPLETE; } free_mb(chosen_mb); free(pi); DPRINTF(3, "conc with pid %d terminates %s", pid, exit == PS_COMPLETE ? "normally" : "with error"); #ifdef DEBUG fflush(stderr); #endif #ifdef TIME if (noinput) { clock_gettime(CLOCK_MONOTONIC, &tend); fprintf(stderr, "The dgsh negotiation procedure took about %.5f seconds\n", ((double)tend.tv_sec + 1.0e-9*tend.tv_nsec) - ((double)tstart.tv_sec + 1.0e-9*tstart.tv_nsec)); fflush(stderr); } #endif set_negotiation_complete(); alarm(0); // Cancel alarm signal(SIGALRM, SIG_IGN); // Do not handle the signal return exit; }
/* * Pass around the message blocks so that they reach all processes * connected through the concentrator. */ STATIC int pass_message_blocks(void) { fd_set readfds, writefds; int nfds = 0; int i; int oi = -1; /* scatter/gather block's origin index */ int ofd = -1; /* ... origin fd direction */ bool ro = false; /* Whether the read block's origin should * be restored */ bool iswrite = false; if (noinput) { #ifdef TIME clock_gettime(CLOCK_MONOTONIC, &tstart); #endif construct_message_block("dgsh-conc", pid); chosen_mb->origin_fd_direction = STDOUT_FILENO; chosen_mb->is_origin_conc = true; chosen_mb->conc_pid = pid; pi[STDOUT_FILENO].to_write = chosen_mb; } for (;;) { // Create select(2) masks FD_ZERO(&readfds); FD_ZERO(&writefds); for (i = 0; i < nfd; i++) { if (noinput && i == STDIN_FILENO) continue; if (i == STDERR_FILENO) continue; if (!pi[i].seen) { FD_SET(i, &readfds); nfds = max(i + 1, nfds); } if (pi[i].to_write && !pi[i].written) { FD_SET(i, &writefds); nfds = max(i + 1, nfds); pi[i].to_write->is_origin_conc = true; pi[i].to_write->conc_pid = pid; DPRINTF(4, "Actual origin: conc with pid %d", pid); } } again: if (select(nfds, &readfds, &writefds, NULL, NULL) < 0) { if (errno == EINTR) goto again; /* All other cases are internal errors. */ err(1, "select"); } // Read/write what we can for (i = 0; i < nfd; i++) { if (FD_ISSET(i, &writefds)) { iswrite = true; assert(pi[i].to_write); chosen_mb = pi[i].to_write; DPRINTF(4, "**fd i: %d set for writing to tool with pid %d", i, pi[i].pid); write_message_block(i); // XXX check return if (pi[i].to_write->state == PS_RUN || pi[i].to_write->state == PS_DRAW_EXIT || (pi[i].to_write->state == PS_ERROR && pi[i].to_write->is_error_confirmed)) pi[i].written = true; // Write side exit if (is_ready(i, pi[i].to_write)) { pi[i].run_ready = true; DPRINTF(4, "**%s(): pi[%d] is run ready", __func__, i); } pi[i].to_write = NULL; } if (FD_ISSET(i, &readfds)) { struct dgsh_negotiation *rb; ro = false; int next = next_fd(i, &ro); assert(!pi[i].run_ready); assert(pi[next].to_write == NULL); if (read_message_block(i, &pi[next].to_write) == OP_ERROR) { chosen_mb->state = PS_ERROR; if (noinput) chosen_mb->is_error_confirmed = true; pi[next].to_write = chosen_mb; continue; } rb = pi[next].to_write; DPRINTF(4, "%s(): next write via fd %d to pid %d", __func__, next, pi[next].pid); if (oi == -1) { if ((multiple_inputs && i == 1) || (!multiple_inputs && i == 0)) { oi = rb->origin_index; ofd = rb->origin_fd_direction; DPRINTF(4, "**Store origin: %d, fd: %s", oi, ofd ? "stdout" : "stdin"); } } /* If conc talks to conc, set conc's pid * Required in order to allocate fds correctly * in the end */ if (rb->is_origin_conc) pi[i].pid = rb->conc_pid; else pi[i].pid = get_origin_pid(rb); /* If needed, re-set origin. * Don't move this block before get_origin_pid() */ if (ro) { DPRINTF(4, "**Restore origin: %d, fd: %s", oi, ofd ? "stdout" : "stdin"); pi[next].to_write->origin_index = oi; pi[next].to_write->origin_fd_direction = ofd; } else if (noinput) { pi[next].to_write->origin_index = -1; pi[next].to_write->origin_fd_direction = STDOUT_FILENO; } /* Set a conc's required/provided IO in mb */ if (!noinput) set_io_channels(pi[next].to_write); if (rb->state == PS_NEGOTIATION && noinput) { int j, seen = 0; pi[i].seen = true; for (j = 1; j < nfd; j++) if (pi[j].seen) seen++; if ((nfd > 2 && seen == nfd - 2) || seen == nfd - 1) { chosen_mb = rb; DPRINTF(1, "%s(): Gathered I/O requirements.", __func__); int state = solve_graph(); if (state == OP_ERROR) { pi[next].to_write->state = PS_ERROR; pi[next].to_write->is_error_confirmed = true; } else if (state == OP_DRAW_EXIT) pi[next].to_write->state = PS_DRAW_EXIT; else { DPRINTF(1, "%s(): Computed solution", __func__); pi[next].to_write->state = PS_RUN; } for (j = 1; j < nfd; j++) pi[j].seen = false; // Don't free chosen_mb = NULL; } } else if (rb->state == PS_RUN || rb->state == PS_DRAW_EXIT || (rb->state == PS_ERROR && rb->is_error_confirmed)) pi[i].seen = true; else if (rb->state == PS_ERROR) rb->is_error_confirmed = true; print_state(i, (int)rb->initiator_pid, 1); if (pi[i].seen && pi[i].written) { chosen_mb = pi[next].to_write; pi[i].run_ready = true; DPRINTF(4, "**%s(): pi[%d] is run ready", __func__, i); } } } // See if all processes are run-ready nfds = 0; for (i = 0; i < nfd; i++) { if (pi[i].run_ready) nfds++; print_state(i, nfds, 2); } if ((nfd > 2 && (nfds == nfd - 1 || (noinput && nfds == nfd - 2))) || (nfds == nfd || (noinput && nfds == nfd - 1))) { assert(chosen_mb != NULL); DPRINTF(4, "%s(): conc leaves negotiation", __func__); return chosen_mb->state; } else if (chosen_mb != NULL && iswrite) { // Free if we have written DPRINTF(4, "chosen_mb: %lx, i: %d, next: %d, pi[next].to_write: %lx\n", (long)chosen_mb, i, next_fd(i, &ro), (long)pi[next_fd(i, &ro)].to_write); free_mb(chosen_mb); chosen_mb = NULL; iswrite = false; } } }