void switch_to_tt(void *prev, void *next) { struct task_struct *from, *to, *prev_sched; unsigned long flags; int err, vtalrm, alrm, prof, cpu; char c; from = prev; to = next; cpu = from->thread_info->cpu; if(cpu == 0) forward_interrupts(to->thread.mode.tt.extern_pid); #ifdef CONFIG_SMP forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.mode.tt.extern_pid); #endif local_irq_save(flags); vtalrm = change_sig(SIGVTALRM, 0); alrm = change_sig(SIGALRM, 0); prof = change_sig(SIGPROF, 0); forward_pending_sigio(to->thread.mode.tt.extern_pid); c = 0; err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c)); if(err != sizeof(c)) panic("write of switch_pipe failed, err = %d", -err); if(from->thread.mode.tt.switch_pipe[0] == -1) os_kill_process(os_getpid(), 0); err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c)); if(err != sizeof(c)) panic("read of switch_pipe failed, errno = %d", -err); /* If the process that we have just scheduled away from has exited, * then it needs to be killed here. The reason is that, even though * it will kill itself when it next runs, that may be too late. Its * stack will be freed, possibly before then, and if that happens, * we have a use-after-free situation. So, it gets killed here * in case it has not already killed itself. */ prev_sched = current->thread.prev_sched; if(prev_sched->thread.mode.tt.switch_pipe[0] == -1) os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1); change_sig(SIGVTALRM, vtalrm); change_sig(SIGALRM, alrm); change_sig(SIGPROF, prof); arch_switch(); flush_tlb_all(); local_irq_restore(flags); }
void switch_to_tt(void *prev, void *next) { struct task_struct *from, *to, *prev_sched; unsigned long flags; int err, vtalrm, alrm, prof, cpu; char c; from = prev; to = next; cpu = task_thread_info(from)->cpu; if(cpu == 0) forward_interrupts(to->thread.mode.tt.extern_pid); #ifdef CONFIG_SMP forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.mode.tt.extern_pid); #endif local_irq_save(flags); vtalrm = change_sig(SIGVTALRM, 0); alrm = change_sig(SIGALRM, 0); prof = change_sig(SIGPROF, 0); forward_pending_sigio(to->thread.mode.tt.extern_pid); c = 0; /* Notice that here we "up" the semaphore on which "to" is waiting, and * below (the read) we wait on this semaphore (which is implemented by * switch_pipe) and go sleeping. Thus, after that, we have resumed in * "to", and can't use any more the value of "from" (which is outdated), * nor the value in "to" (since it was the task which stole us the CPU, * which we don't care about). */ err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c)); if(err != sizeof(c)) panic("write of switch_pipe failed, err = %d", -err); if(from->thread.mode.tt.switch_pipe[0] == -1) os_kill_process(os_getpid(), 0); err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c)); if(err != sizeof(c)) panic("read of switch_pipe failed, errno = %d", -err); /* If the process that we have just scheduled away from has exited, * then it needs to be killed here. The reason is that, even though * it will kill itself when it next runs, that may be too late. Its * stack will be freed, possibly before then, and if that happens, * we have a use-after-free situation. So, it gets killed here * in case it has not already killed itself. */ prev_sched = current->thread.prev_sched; if(prev_sched->thread.mode.tt.switch_pipe[0] == -1) os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1); change_sig(SIGVTALRM, vtalrm); change_sig(SIGALRM, alrm); change_sig(SIGPROF, prof); arch_switch_to_tt(prev_sched, current); flush_tlb_all(); local_irq_restore(flags); }
void *switch_to_tt(void *prev, void *next, void *last) { struct task_struct *from, *to, *prev_sched; unsigned long flags; int err, vtalrm, alrm, prof, cpu; char c; /* jailing and SMP are incompatible, so this doesn't need to be * made per-cpu */ static int reading; from = prev; to = next; to->thread.prev_sched = from; cpu = from->thread_info->cpu; if(cpu == 0) forward_interrupts(to->thread.mode.tt.extern_pid); #ifdef CONFIG_SMP forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.mode.tt.extern_pid); #endif local_irq_save(flags); vtalrm = change_sig(SIGVTALRM, 0); alrm = change_sig(SIGALRM, 0); prof = change_sig(SIGPROF, 0); forward_pending_sigio(to->thread.mode.tt.extern_pid); c = 0; set_current(to); reading = 0; err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c)); if(err != sizeof(c)) panic("write of switch_pipe failed, err = %d", -err); reading = 1; if((from->exit_state == EXIT_ZOMBIE) || (from->exit_state == EXIT_DEAD)) os_kill_process(os_getpid(), 0); err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c)); if(err != sizeof(c)) panic("read of switch_pipe failed, errno = %d", -err); /* If the process that we have just scheduled away from has exited, * then it needs to be killed here. The reason is that, even though * it will kill itself when it next runs, that may be too late. Its * stack will be freed, possibly before then, and if that happens, * we have a use-after-free situation. So, it gets killed here * in case it has not already killed itself. */ prev_sched = current->thread.prev_sched; if((prev_sched->exit_state == EXIT_ZOMBIE) || (prev_sched->exit_state == EXIT_DEAD)) os_kill_ptraced_process(prev_sched->thread.mode.tt.extern_pid, 1); /* This works around a nasty race with 'jail'. If we are switching * between two threads of a threaded app and the incoming process * runs before the outgoing process reaches the read, and it makes * it all the way out to userspace, then it will have write-protected * the outgoing process stack. Then, when the outgoing process * returns from the write, it will segfault because it can no longer * write its own stack. So, in order to avoid that, the incoming * thread sits in a loop yielding until 'reading' is set. This * isn't entirely safe, since there may be a reschedule from a timer * happening between setting 'reading' and sleeping in read. But, * it should get a whole quantum in which to reach the read and sleep, * which should be enough. */ if(jail){ while(!reading) sched_yield(); } change_sig(SIGVTALRM, vtalrm); change_sig(SIGALRM, alrm); change_sig(SIGPROF, prof); arch_switch(); flush_tlb_all(); local_irq_restore(flags); return(current->thread.prev_sched); }