/** * Main and Execute Commands */ int main(int argc, char* argv[]) { char input_buffer[COMMAND_LENGTH]; char *tokens[NUM_TOKENS]; char currentDir[COMMAND_LENGTH]; struct sigaction handler; handler.sa_handler = handle_SIGINT; sigaction(SIGINT, &handler, NULL); while (true) { getcwd(currentDir, sizeof(currentDir)); // Use write because we need to use read() to work with // signals, and read() is incompatible with printf(). write(STDOUT_FILENO, currentDir, strlen(currentDir)); write(STDOUT_FILENO, ">", strlen(">")); _Bool in_background = false; int token_count = 0; char *bufCopy = read_command(input_buffer, tokens, &in_background, &token_count); // Cmd was invalid, or it was part of the Ctr+C signal. // Nothing was copied, and therefore there is nothing to be run. if (bufCopy == NULL) { continue; } int handledInline = handle_inline_commands(tokens, bufCopy, input_buffer, &in_background); // Cmd was handled by the inline command handler. if (handledInline != 0) { continue; } pid_t pid = fork(); handle_fork(pid, in_background, tokens); add_to_history(bufCopy); // Cleanup any previously exited background child processes // (The zombies) while (waitpid(-1, NULL, WNOHANG) > 0); } return 0; }
int main(int argc, char *argv[]) { printf("\nThis is the server with pid %d listening on port %d\n", getpid(), SERVER_PORT); // setup the server to bind and listen on a port int s = listen_on(SERVER_PORT); while(1) { // forever int msgsock = accept_connection(s); // wait for a client to connect // handle the request with a new process handle_fork(msgsock); } close(s); exit (0); }
void sched_update(struct ls_state *ls) { struct sched_state *s = &ls->sched; int old_tid = s->cur_agent->tid; int new_tid; /* wait until the guest is ready */ if (!s->guest_init_done) { if (kern_sched_init_done(ls->eip)) { s->guest_init_done = true; /* Deprecated since kern_get_current_tid went away. */ // assert(old_tid == new_tid && "init tid mismatch"); } else { return; } } /* The Importance of Being Assertive, A Trivial Style Guideline for * Serious Programmers, by Ben Blum */ if (s->entering_timer) { assert(ls->eip == kern_get_timer_wrap_begin() && "simics is a clown and tried to delay our interrupt :<"); s->entering_timer = false; } else { if (kern_timer_entering(ls->eip)) { lsprintf(DEV, "A timer tick that wasn't ours (0x%x).\n", (int)READ_STACK(ls->cpu0, 0)); ls->eip = avoid_timer_interrupt_immediately(ls->cpu0); } } /********************************************************************** * Update scheduler state. **********************************************************************/ if (kern_thread_switch(ls->cpu0, ls->eip, &new_tid) && new_tid != old_tid) { /* * So, fork needs to be handled twice, both here and below in the * runnable case. And for kernels that trigger both, both places will * need to have a check for whether the newly forked thread exists * already. * * Sleep and vanish actually only need to happen here. They should * check both the rq and the dq, 'cause there's no telling where the * thread got moved to before. As for the descheduling case, that needs * to check for a new type of action flag "asleep" or "vanished" (and * I guess using last_vanished_agent might work), and probably just * assert that that condition holds if the thread couldn't be found * for the normal descheduling case. */ /* Has to be handled before updating cur_agent, of course. */ handle_sleep(s); handle_vanish(s); handle_unsleep(s, new_tid); /* Careful! On some kernels, the trigger for a new agent forking * (where it first gets added to the RQ) may happen AFTER its * tcb is set to be the currently running thread. This would * cause this case to be reached before agent_fork() is called, * so agent_by_tid would fail. Instead, we have an option to * find it later. (see the kern_thread_runnable case below.) */ struct agent *next = agent_by_tid_or_null(&s->rq, new_tid); if (next == NULL) next = agent_by_tid_or_null(&s->dq, new_tid); if (next != NULL) { lsprintf(DEV, "switched threads %d -> %d\n", old_tid, new_tid); s->last_agent = s->cur_agent; s->cur_agent = next; /* This fork check is for kernels which context switch to a * newly-forked thread before adding it to the runqueue - and * possibly won't do so at all (if current_extra_runnable). We * need to do agent_fork now. (agent_fork *also* needs to be * handled below, for kernels which don't c-s to the new thread * immediately.) The */ } else if (handle_fork(s, new_tid, false)) { next = agent_by_tid_or_null(&s->dq, new_tid); assert(next != NULL && "Newly forked thread not on DQ"); lsprintf(DEV, "switching threads %d -> %d\n", old_tid, new_tid); s->last_agent = s->cur_agent; s->cur_agent = next; } else { lsprintf(ALWAYS, COLOUR_BOLD COLOUR_RED "Couldn't find " "new thread %d; current %d; did you forget to " "tell_landslide_forking()?\n" COLOUR_DEFAULT, new_tid, s->cur_agent->tid); assert(0); } /* Some debug info to help the studence. */ if (s->cur_agent->tid == kern_get_init_tid()) { lsprintf(DEV, "Now running init.\n"); } else if (s->cur_agent->tid == kern_get_shell_tid()) { lsprintf(DEV, "Now running shell.\n"); } else if (kern_has_idle() && s->cur_agent->tid == kern_get_idle_tid()) { lsprintf(DEV, "Now idling.\n"); } } s->current_extra_runnable = kern_current_extra_runnable(ls->cpu0); int target_tid; int mutex_addr; /* Timer interrupt handling. */ if (kern_timer_entering(ls->eip)) { // XXX: same as the comment in the below condition. if (!kern_timer_exiting(READ_STACK(ls->cpu0, 0))) { assert(!ACTION(s, handling_timer)); } else { lsprintf(DEV, "WARNING: allowing a nested timer on " "tid %d's stack\n", s->cur_agent->tid); } ACTION(s, handling_timer) = true; lsprintf(INFO, "%d timer enter from 0x%x\n", s->cur_agent->tid, (unsigned int)READ_STACK(ls->cpu0, 0)); } else if (kern_timer_exiting(ls->eip)) { if (ACTION(s, handling_timer)) { // XXX: This condition is a hack to compensate for when // simics "sometimes", when keeping a schedule-in- // flight, takes the caused timer interrupt immediately, // even before the iret. if (!kern_timer_exiting(READ_STACK(ls->cpu0, 0))) { ACTION(s, handling_timer) = false; s->just_finished_reschedule = true; } /* If the schedule target was in a timer interrupt when we * decided to schedule him, then now is when the operation * finishes landing. (otherwise, see below) * FIXME: should this be inside the above if statement? */ if (ACTION(s, schedule_target)) { ACTION(s, schedule_target) = false; s->schedule_in_flight = NULL; } } else { lsprintf(INFO, "WARNING: exiting a non-timer interrupt " "through a path shared with the timer..? (from 0x%x, #%d)\n", (int)READ_STACK(ls->cpu0, 0), (int)READ_STACK(ls->cpu0, -2)); } /* Context switching. */ } else if (kern_context_switch_entering(ls->eip)) { /* It -is- possible for a context switch to interrupt a * context switch if a timer goes off before c-s disables * interrupts. TODO: if we care, make this an int counter. */ ACTION(s, context_switch) = true; /* Maybe update the voluntary resched trace. See schedule.h */ if (!ACTION(s, handling_timer)) { lsprintf(DEV, "Voluntary resched tid "); print_agent(DEV, s->cur_agent); printf(DEV, "\n"); s->voluntary_resched_tid = s->cur_agent->tid; if (s->voluntary_resched_stack != NULL) MM_FREE(s->voluntary_resched_stack); s->voluntary_resched_stack = stack_trace(ls->cpu0, ls->eip, s->cur_agent->tid); } } else if (kern_context_switch_exiting(ls->eip)) { assert(ACTION(s, cs_free_pass) || ACTION(s, context_switch)); ACTION(s, context_switch) = false; ACTION(s, cs_free_pass) = false; /* For threads that context switched of their own accord. */ if (!HANDLING_INTERRUPT(s)) { s->just_finished_reschedule = true; if (ACTION(s, schedule_target)) { ACTION(s, schedule_target) = false; s->schedule_in_flight = NULL; } } /* Lifecycle. */ } else if (kern_forking(ls->eip)) { assert_no_action(s, "forking"); ACTION(s, forking) = true; } else if (kern_sleeping(ls->eip)) { assert_no_action(s, "sleeping"); ACTION(s, sleeping) = true; } else if (kern_vanishing(ls->eip)) { assert_no_action(s, "vanishing"); ACTION(s, vanishing) = true; } else if (kern_readline_enter(ls->eip)) { assert_no_action(s, "readlining"); ACTION(s, readlining) = true; } else if (kern_readline_exit(ls->eip)) { assert(ACTION(s, readlining)); ACTION(s, readlining) = false; /* Runnable state change (incl. consequences of fork, vanish, sleep). */ } else if (kern_thread_runnable(ls->cpu0, ls->eip, &target_tid)) { /* A thread is about to become runnable. Was it just spawned? */ if (!handle_fork(s, target_tid, true)) { agent_wake(s, target_tid); } } else if (kern_thread_descheduling(ls->cpu0, ls->eip, &target_tid)) { /* A thread is about to deschedule. Is it vanishing/sleeping? */ agent_deschedule(s, target_tid); /* Mutex tracking and noob deadlock detection */ } else if (kern_mutex_locking(ls->cpu0, ls->eip, &mutex_addr)) { //assert(!ACTION(s, mutex_locking)); assert(!ACTION(s, mutex_unlocking)); ACTION(s, mutex_locking) = true; s->cur_agent->blocked_on_addr = mutex_addr; } else if (kern_mutex_blocking(ls->cpu0, ls->eip, &target_tid)) { /* Possibly not the case - if this thread entered mutex_lock, * then switched and someone took it, these would be set already * assert(s->cur_agent->blocked_on == NULL); * assert(s->cur_agent->blocked_on_tid == -1); */ lsprintf(DEV, "mutex: on 0x%x tid %d blocks, owned by %d\n", s->cur_agent->blocked_on_addr, s->cur_agent->tid, target_tid); s->cur_agent->blocked_on_tid = target_tid; if (deadlocked(s)) { lsprintf(BUG, COLOUR_BOLD COLOUR_RED "DEADLOCK! "); print_deadlock(BUG, s->cur_agent); printf(BUG, "\n"); found_a_bug(ls); } } else if (kern_mutex_locking_done(ls->eip)) { //assert(ACTION(s, mutex_locking)); assert(!ACTION(s, mutex_unlocking)); ACTION(s, mutex_locking) = false; s->cur_agent->blocked_on = NULL; s->cur_agent->blocked_on_tid = -1; s->cur_agent->blocked_on_addr = -1; /* no need to check for deadlock; this can't create a cycle. */ mutex_block_others(&s->rq, mutex_addr, s->cur_agent, s->cur_agent->tid); } else if (kern_mutex_unlocking(ls->cpu0, ls->eip, &mutex_addr)) { /* It's allowed to have a mutex_unlock call inside a mutex_lock * (and it can happen), or mutex_lock inside of mutex_lock, but * not the other way around. */ assert(!ACTION(s, mutex_unlocking)); ACTION(s, mutex_unlocking) = true; mutex_block_others(&s->rq, mutex_addr, NULL, -1); } else if (kern_mutex_unlocking_done(ls->eip)) { assert(ACTION(s, mutex_unlocking)); ACTION(s, mutex_unlocking) = false; } /********************************************************************** * Exercise our will upon the guest kernel **********************************************************************/ /* Some checks before invoking the arbiter. First see if an operation of * ours is already in-flight. */ if (s->schedule_in_flight) { if (s->schedule_in_flight == s->cur_agent) { /* the in-flight schedule operation is cleared for * landing. note that this may cause another one to * be triggered again as soon as the context switcher * and/or the timer handler finishes; it is up to the * arbiter to decide this. */ assert(ACTION(s, schedule_target)); /* this condition should trigger in the middle of the * switch, rather than after it finishes. (which is also * why we leave the schedule_target flag turned on). * the special case is for newly forked agents that are * schedule targets - they won't exit timer or c-s above * so here is where we have to clear it for them. */ if (ACTION(s, just_forked)) { /* Interrupts are "probably" off, but that's why * just_finished_reschedule is persistent. */ lsprintf(DEV, "Finished flying to %d.\n", s->cur_agent->tid); ACTION(s, schedule_target) = false; ACTION(s, just_forked) = false; s->schedule_in_flight = NULL; s->just_finished_reschedule = true; } else { assert(ACTION(s, cs_free_pass) || ACTION(s, context_switch) || HANDLING_INTERRUPT(s)); } /* The schedule_in_flight flag itself is cleared above, * along with schedule_target. Sometimes sched_recover * sets in_flight and needs it not cleared here. */ } else { /* An undesirable thread has been context-switched away * from either from an interrupt handler (timer/kbd) or * of its own accord. We need to wait for it to get back * to its own execution before triggering an interrupt * on it; in the former case, this will be just after it * irets; in the latter, just after the c-s returns. */ if (kern_timer_exiting(ls->eip) || (!HANDLING_INTERRUPT(s) && kern_context_switch_exiting(ls->eip)) || ACTION(s, just_forked)) { /* an undesirable agent just got switched to; * keep the pending schedule in the air. */ // XXX: this seems to get taken too soon? change // it somehow to cause_.._immediately. and then // see the asserts/comments in the action // handling_timer sections above. /* some kernels (pathos) still have interrupts * off or scheduler locked at this point; so * properties of !R */ if (interrupts_enabled(ls->cpu0) && kern_ready_for_timer_interrupt(ls->cpu0)) { lsprintf(INFO, "keeping schedule in-" "flight at 0x%x\n", ls->eip); cause_timer_interrupt(ls->cpu0); s->entering_timer = true; s->delayed_in_flight = false; } else { lsprintf(INFO, "Want to keep schedule " "in-flight at 0x%x; have to " "delay\n", ls->eip); s->delayed_in_flight = true; } /* If this was the special case where the * undesirable thread was just forked, keeping * the schedule in flight will cause it to do a * normal context switch. So just_forked is no * longer needed. */ ACTION(s, just_forked) = false; } else if (s->delayed_in_flight && interrupts_enabled(ls->cpu0) && kern_ready_for_timer_interrupt(ls->cpu0)) { lsprintf(INFO, "Delayed in-flight timer tick " "at 0x%x\n", ls->eip); cause_timer_interrupt(ls->cpu0); s->entering_timer = true; s->delayed_in_flight = false; } else { /* they'd better not have "escaped" */ assert(ACTION(s, cs_free_pass) || ACTION(s, context_switch) || HANDLING_INTERRUPT(s) || !interrupts_enabled(ls->cpu0) || !kern_ready_for_timer_interrupt(ls->cpu0)); } } /* in any case we have no more decisions to make here */ return; } else if (ACTION(s, just_forked)) { ACTION(s, just_forked) = false; s->just_finished_reschedule = true; } assert(!s->schedule_in_flight); /* Can't do anything before the test actually starts. */ if (ls->test.current_test == NULL) { return; } /* XXX TODO: This will "leak" an undesirable thread to execute an * instruction if the timer/kbd handler is an interrupt gate, so check * also if we're about to iret and then examine the eflags on the * stack. Also, "sti" and "popf" are interesting, so check for those. * Also, do trap gates enable interrupts if they were off? o_O */ if (!interrupts_enabled(ls->cpu0)) { return; } /* If a schedule operation is just finishing, we should allow the thread * to get back to its own execution before making another choice. Note * that when we previously decided to interrupt the thread, it will have * executed the single instruction we made the choice at then taken the * interrupt, so we return to the next instruction, not the same one. */ if (ACTION(s, schedule_target)) { return; } /* TODO: have an extra mode which will allow us to preempt the timer * handler. */ if (HANDLING_INTERRUPT(s) || !kern_ready_for_timer_interrupt(ls->cpu0)) { return; } /* As kernel_specifics.h says, no preempting during mutex unblocking. */ if (ACTION(s, mutex_unlocking)) { return; } /* Okay, are we at a choice point? */ bool voluntary; bool just_finished_reschedule = s->just_finished_reschedule; s->just_finished_reschedule = false; /* TODO: arbiter may also want to see the trace_entry_t */ if (arbiter_interested(ls, just_finished_reschedule, &voluntary)) { struct agent *a; bool our_choice; /* TODO: as an optimisation (in serialisation state / etc), the * arbiter may return NULL if there was only one possible * choice. */ if (arbiter_choose(ls, &a, &our_choice)) { /* Effect the choice that was made... */ if (a != s->cur_agent) { lsprintf(CHOICE, "from agent %d, arbiter chose " "%d at 0x%x (called at 0x%x)\n", s->cur_agent->tid, a->tid, ls->eip, (unsigned int)READ_STACK(ls->cpu0, 0)); set_schedule_target(s, a); cause_timer_interrupt(ls->cpu0); s->entering_timer = true; } /* Record the choice that was just made. */ if (ls->test.test_ever_caused && ls->test.start_population != s->most_agents_ever) { save_setjmp(&ls->save, ls, a->tid, our_choice, false, voluntary); } } else { lsprintf(BUG, "no agent was chosen at eip 0x%x\n", ls->eip); } } /* XXX TODO: it may be that not every timer interrupt triggers a context * switch, so we should watch out if a handler doesn't enter the c-s. */ }