void send_to_io (struct ctx_t* ctx, long long waitinstr) { printf("\nSending process of uid %d at inst no. %lld\n", ctx->uid, instr_num); interrupt itrp; itrp.type = IO_INTERRUPT; itrp.details = malloc(sizeof(io_interrupt_details)); itrp.instno = instr_num + waitinstr; ((io_interrupt_details*)(itrp.details))->proc = ctx; push_interrupt(itrp); ctx_set_status(ctx, ctx_suspended); //block_process(ctx); }
void handle_interrupt (interrupt itrp) { struct ctx_t *ctx, *currctx = ((io_interrupt_details*)(itrp.details))->proc; printf("\nHandling interrupt for uid %d at inst no. %lld\n", currctx->uid, instr_num); int k; //for (k=0, ctx = ke->suspended_list_head; ctx; ctx = ctx->suspended_next, k++) //printf ("Suspended process: %p status:%d\n", ctx, ctx->status); if (itrp.type == IO_INTERRUPT) { ctx_set_status(currctx, ctx_running); //unblock_process(currctx); } //for (k=0, ctx = ke->suspended_list_head; ctx; ctx = ctx->suspended_next, k++); //printf ("Instruction number: %lld, suspended processes:%d, process: %p, status: %d\n\nyy", instr_num, k, currctx, currctx->status); free(itrp.details); }
/* Check for events detected in spawned host threads, like waking up contexts or * sending signals. * The list is only processed if flag 'ke->process_events_force' is set. */ void ke_process_events() { struct ctx_t *ctx, *next; uint64_t now = ke_timer(); /* Check if events need actually be checked. */ pthread_mutex_lock(&ke->process_events_mutex); if (!ke->process_events_force) { pthread_mutex_unlock(&ke->process_events_mutex); return; } /* By default, no subsequent call to 'ke_process_events' is assumed */ ke->process_events_force = 0; /* * LOOP 1 * Look at the list of suspended contexts and try to find * one that needs to be woken up. */ for (ctx = ke->suspended_list_head; ctx; ctx = next) { /* Save next */ next = ctx->suspended_next; /* Context is suspended in 'nanosleep' system call. */ if (ctx_get_status(ctx, ctx_nanosleep)) { uint32_t rmtp = ctx->regs->ecx; uint64_t zero = 0; uint32_t sec, usec; uint64_t diff; /* If 'ke_host_thread_suspend' is still running for this context, do nothing. */ if (ctx->host_thread_suspend_active) continue; /* Timeout expired */ if (ctx->wakeup_time <= now) { if (rmtp) mem_write(ctx->mem, rmtp, 8, &zero); syscall_debug("syscall 'nanosleep' - continue (pid %d)\n", ctx->pid); syscall_debug(" return=0x%x\n", ctx->regs->eax); ctx_clear_status(ctx, ctx_suspended | ctx_nanosleep); continue; } /* Context received a signal */ if (ctx->signal_masks->pending & ~ctx->signal_masks->blocked) { if (rmtp) { diff = ctx->wakeup_time - now; sec = diff / 1000000; usec = diff % 1000000; mem_write(ctx->mem, rmtp, 4, &sec); mem_write(ctx->mem, rmtp + 4, 4, &usec); } ctx->regs->eax = -EINTR; syscall_debug("syscall 'nanosleep' - interrupted by signal (pid %d)\n", ctx->pid); ctx_clear_status(ctx, ctx_suspended | ctx_nanosleep); continue; } /* No event available, launch 'ke_host_thread_suspend' again */ ctx->host_thread_suspend_active = 1; if (pthread_create(&ctx->host_thread_suspend, NULL, ke_host_thread_suspend, ctx)) fatal("syscall 'poll': could not create child thread"); continue; } /* Context suspended in 'rt_sigsuspend' system call */ if (ctx_get_status(ctx, ctx_sigsuspend)) { /* Context received a signal */ if (ctx->signal_masks->pending & ~ctx->signal_masks->blocked) { signal_handler_check_intr(ctx); ctx->signal_masks->blocked = ctx->signal_masks->backup; syscall_debug("syscall 'rt_sigsuspend' - interrupted by signal (pid %d)\n", ctx->pid); ctx_clear_status(ctx, ctx_suspended | ctx_sigsuspend); continue; } /* No event available. The context will never awake on its own, so no * 'ke_host_thread_suspend' is necessary. */ continue; } /* Context suspended in 'poll' system call */ if (ctx_get_status(ctx, ctx_poll)) { uint32_t prevents = ctx->regs->ebx + 6; uint16_t revents = 0; struct fd_t *fd; struct pollfd host_fds; int err; /* If 'ke_host_thread_suspend' is still running for this context, do nothing. */ if (ctx->host_thread_suspend_active) continue; /* Get file descriptor */ fd = fdt_entry_get(ctx->fdt, ctx->wakeup_fd); if (!fd) fatal("syscall 'poll': invalid 'wakeup_fd'"); /* Context received a signal */ if (ctx->signal_masks->pending & ~ctx->signal_masks->blocked) { signal_handler_check_intr(ctx); syscall_debug("syscall 'poll' - interrupted by signal (pid %d)\n", ctx->pid); ctx_clear_status(ctx, ctx_suspended | ctx_poll); continue; } /* Perform host 'poll' call */ host_fds.fd = fd->host_fd; host_fds.events = ((ctx->wakeup_events & 4) ? POLLOUT : 0) | ((ctx->wakeup_events & 1) ? POLLIN : 0); err = poll(&host_fds, 1, 0); if (err < 0) fatal("syscall 'poll': unexpected error in host 'poll'"); /* POLLOUT event available */ if (ctx->wakeup_events & host_fds.revents & POLLOUT) { revents = POLLOUT; mem_write(ctx->mem, prevents, 2, &revents); ctx->regs->eax = 1; syscall_debug("syscall poll - continue (pid %d) - POLLOUT occurred in file\n", ctx->pid); syscall_debug(" retval=%d\n", ctx->regs->eax); ctx_clear_status(ctx, ctx_suspended | ctx_poll); continue; } /* POLLIN event available */ if (ctx->wakeup_events & host_fds.revents & POLLIN) { revents = POLLIN; mem_write(ctx->mem, prevents, 2, &revents); ctx->regs->eax = 1; syscall_debug("syscall poll - continue (pid %d) - POLLIN occurred in file\n", ctx->pid); syscall_debug(" retval=%d\n", ctx->regs->eax); ctx_clear_status(ctx, ctx_suspended | ctx_poll); continue; } /* Timeout expired */ if (ctx->wakeup_time && ctx->wakeup_time < now) { revents = 0; mem_write(ctx->mem, prevents, 2, &revents); syscall_debug("syscall poll - continue (pid %d) - time out\n", ctx->pid); syscall_debug(" return=0x%x\n", ctx->regs->eax); ctx_clear_status(ctx, ctx_suspended | ctx_poll); continue; } /* No event available, launch 'ke_host_thread_suspend' again */ ctx->host_thread_suspend_active = 1; if (pthread_create(&ctx->host_thread_suspend, NULL, ke_host_thread_suspend, ctx)) fatal("syscall 'poll': could not create child thread"); continue; } /* Context suspended in a 'write' system call */ if (ctx_get_status(ctx, ctx_write)) { struct fd_t *fd; int count, err; uint32_t pbuf; void *buf; struct pollfd host_fds; /* If 'ke_host_thread_suspend' is still running for this context, do nothing. */ if (ctx->host_thread_suspend_active) continue; /* Context received a signal */ if (ctx->signal_masks->pending & ~ctx->signal_masks->blocked) { signal_handler_check_intr(ctx); syscall_debug("syscall 'write' - interrupted by signal (pid %d)\n", ctx->pid); ctx_clear_status(ctx, ctx_suspended | ctx_write); continue; } /* Get file descriptor */ fd = fdt_entry_get(ctx->fdt, ctx->wakeup_fd); if (!fd) fatal("syscall 'write': invalid 'wakeup_fd'"); /* Check if data is ready in file by polling it */ host_fds.fd = fd->host_fd; host_fds.events = POLLOUT; err = poll(&host_fds, 1, 0); if (err < 0) fatal("syscall 'write': unexpected error in host 'poll'"); /* If data is ready in the file, wake up context */ if (host_fds.revents) { pbuf = ctx->regs->ecx; count = ctx->regs->edx; buf = malloc(count); mem_read(ctx->mem, pbuf, count, buf); count = write(fd->host_fd, buf, count); if (count < 0) fatal("syscall 'write': unexpected error in host 'write'"); ctx->regs->eax = count; free(buf); syscall_debug("syscall write - continue (pid %d)\n", ctx->pid); syscall_debug(" return=0x%x\n", ctx->regs->eax); ctx_clear_status(ctx, ctx_suspended | ctx_write); continue; } /* Data is not ready to be written - launch 'ke_host_thread_suspend' again */ ctx->host_thread_suspend_active = 1; if (pthread_create(&ctx->host_thread_suspend, NULL, ke_host_thread_suspend, ctx)) fatal("syscall 'write': could not create child thread"); continue; } /* Context suspended in 'read' system call */ if (ctx_get_status(ctx, ctx_read)) { struct fd_t *fd; uint32_t pbuf; int count, err; void *buf; struct pollfd host_fds; /* If 'ke_host_thread_suspend' is still running for this context, do nothing. */ if (ctx->host_thread_suspend_active) continue; /* Context received a signal */ if (ctx->signal_masks->pending & ~ctx->signal_masks->blocked) { signal_handler_check_intr(ctx); syscall_debug("syscall 'read' - interrupted by signal (pid %d)\n", ctx->pid); ctx_clear_status(ctx, ctx_suspended | ctx_read); continue; } /* Get file descriptor */ fd = fdt_entry_get(ctx->fdt, ctx->wakeup_fd); if (!fd) fatal("syscall 'read': invalid 'wakeup_fd'"); /* Check if data is ready in file by polling it */ host_fds.fd = fd->host_fd; host_fds.events = POLLIN; err = poll(&host_fds, 1, 0); if (err < 0) fatal("syscall 'read': unexpected error in host 'poll'"); /* If data is ready, perform host 'read' call and wake up */ if (host_fds.revents) { pbuf = ctx->regs->ecx; count = ctx->regs->edx; buf = malloc(count); count = read(fd->host_fd, buf, count); if (count < 0) fatal("syscall 'read': unexpected error in host 'read'"); ctx->regs->eax = count; mem_write(ctx->mem, pbuf, count, buf); free(buf); syscall_debug("syscall 'read' - continue (pid %d)\n", ctx->pid); syscall_debug(" return=0x%x\n", ctx->regs->eax); ctx_clear_status(ctx, ctx_suspended | ctx_read); continue; } /* Data is not ready. Launch 'ke_host_thread_suspend' again */ ctx->host_thread_suspend_active = 1; if (pthread_create(&ctx->host_thread_suspend, NULL, ke_host_thread_suspend, ctx)) fatal("syscall 'read': could not create child thread"); continue; } /* Context suspended in a 'waitpid' system call */ if (ctx_get_status(ctx, ctx_waitpid)) { struct ctx_t *child; uint32_t pstatus; /* A zombie child is available to 'waitpid' it */ child = ctx_get_zombie(ctx, ctx->wakeup_pid); if (child) { /* Continue with 'waitpid' system call */ pstatus = ctx->regs->ecx; ctx->regs->eax = child->pid; if (pstatus) mem_write(ctx->mem, pstatus, 4, &child->exit_code); ctx_set_status(child, ctx_finished); syscall_debug("syscall waitpid - continue (pid %d)\n", ctx->pid); syscall_debug(" return=0x%x\n", ctx->regs->eax); ctx_clear_status(ctx, ctx_suspended | ctx_waitpid); continue; } /* No event available. Since this context won't awake on its own, no * 'ke_host_thread_suspend' is needed. */ continue; } } /* * LOOP 2 * Check list of all contexts for expired timers. */ for (ctx = ke->context_list_head; ctx; ctx = ctx->context_next) { int sig[3] = { 14, 26, 27 }; /* SIGALRM, SIGVTALRM, SIGPROF */ int i; /* If there is already a 'ke_host_thread_timer' running, do nothing. */ if (ctx->host_thread_timer_active) continue; /* Check for any expired 'itimer': itimer_value < now * In this case, send corresponding signal to process. * Then calculate next 'itimer' occurrence: itimer_value = now + itimer_interval */ for (i = 0; i < 3; i++ ) { /* Timer inactive or not expired yet */ if (!ctx->itimer_value[i] || ctx->itimer_value[i] > now) continue; /* Timer expired - send a signal. * The target process might be suspended, so the host thread is canceled, and a new * call to 'ke_process_events' is scheduled. Since 'ke_process_events_mutex' is * already locked, the thread-unsafe version of 'ctx_host_thread_suspend_cancel' is used. */ __ctx_host_thread_suspend_cancel(ctx); ke->process_events_force = 1; sim_sigset_add(&ctx->signal_masks->pending, sig[i]); /* Calculate next occurrence */ ctx->itimer_value[i] = 0; if (ctx->itimer_interval[i]) ctx->itimer_value[i] = now + ctx->itimer_interval[i]; } /* Calculate the time when next wakeup occurs. */ ctx->host_thread_timer_wakeup = 0; for (i = 0; i < 3; i++) { if (!ctx->itimer_value[i]) continue; assert(ctx->itimer_value[i] >= now); if (!ctx->host_thread_timer_wakeup || ctx->itimer_value[i] < ctx->host_thread_timer_wakeup) ctx->host_thread_timer_wakeup = ctx->itimer_value[i]; } /* If a new timer was set, launch 'ke_host_thread_timer' again */ if (ctx->host_thread_timer_wakeup) { ctx->host_thread_timer_active = 1; if (pthread_create(&ctx->host_thread_timer, NULL, ke_host_thread_timer, ctx)) fatal("%s: could not create child thread", __FUNCTION__); } } /* * LOOP 3 * Process pending signals in running contexts to launch signal handlers */ for (ctx = ke->running_list_head; ctx; ctx = ctx->running_next) { signal_handler_check(ctx); } /* Unlock */ pthread_mutex_unlock(&ke->process_events_mutex); }