void psleep(void *event) { irqflags_t irq = di(); #ifdef DEBUG kprintf("psleep(0x%x)", event); /* WRS */ #endif switch (udata.u_ptab->p_status) { case P_SLEEP: // echo output from devtty happens while processes are still sleeping but in-context nready++; /* We will fix this back up below */ case P_RUNNING: // normal process break; default: panic("psleep: voodoo"); } if (!event) udata.u_ptab->p_status = P_PAUSE; else if (event == (char *) udata.u_ptab) udata.u_ptab->p_status = P_WAIT; else udata.u_ptab->p_status = P_SLEEP; udata.u_ptab->p_wait = event; udata.u_ptab->p_waitno = ++waitno; nready--; /* It is safe to restore interrupts here. We have already updated the process state. The worst case is that a wakeup as we switchout leads us to switch out and back in, or that we wake and run after other candidates - no different to it occuring after the switch */ irqrestore(irq); switchout(); /* Switch us out, and start another process */ /* Switchout doesn't return in this context until we have been switched back in, of course. */ }
void psleep(void *event) { irqflags_t irq = di(); #ifdef DEBUG kprintf("psleep(0x%p)", event); #endif switch (udata.u_ptab->p_status) { case P_SLEEP: // echo output from devtty happens while processes are still sleeping but in-context case P_STOPPED: // coming to a halt nready++; /* We will fix this back up below */ case P_RUNNING: // normal process break; default: #ifdef DEBUG kprintf("psleep(0x%p) -> %d:%d", event, udata.u_ptab->p_pid, udata.u_ptab->p_status); #endif panic(PANIC_VOODOO); } udata.u_ptab->p_status = P_SLEEP; udata.u_ptab->p_wait = event; udata.u_ptab->p_waitno = ++waitno; nready--; /* It is safe to restore interrupts here. We have already updated the process state. The worst case is that a wakeup as we switchout leads us to switch out and back in, or that we wake and run after other candidates - no different to it occuring after the switch */ irqrestore(irq); switchout(); /* Switch us out, and start another process */ /* Switchout doesn't return in this context until we have been switched back in, of course. */ }
// Fuzix system call handler // we arrive here from syscall.s with the kernel paged in, using the kernel stack, interrupts enabled. void unix_syscall(void) { // NO LOCAL VARIABLES PLEASE udata.u_error = 0; /* Fuzix saves the Stack Pointer and arguments in the * Assembly Language Function handler in lowlevel.s */ if (udata.u_callno >= FUZIX_SYSCALL_COUNT) { udata.u_error = EINVAL; } else { #ifdef DEBUG kprintf("\t\tpid %d: syscall %d\t%s(%x, %x, %x)\n", udata.u_ptab->p_pid, udata.u_callno, syscall_name[udata.u_callno], udata.u_argn, udata.u_argn1, udata.u_argn2); #endif // dispatch system call udata.u_retval = (*syscall_dispatch[udata.u_callno]) (); #ifdef DEBUG kprintf("\t\t\tpid %d: ret syscall %d, ret %x err %d\n", udata.u_ptab->p_pid, udata.u_callno, udata.u_retval, udata.u_error); #endif } udata.u_ptab->p_timeout = 0; chksigs(); di(); if (runticks >= udata.u_ptab->p_priority && nready > 1) { /* Time to switch out? - we may have overstayed our welcome inside a syscall so switch straight afterwards */ udata.u_ptab->p_status = P_READY; switchout(); } ei(); }
uint8_t chksigs(void) { uint8_t j; uint32_t pending = udata.u_ptab->p_pending & ~udata.u_ptab->p_held; int (**svec)(int) = &udata.u_sigvec[0]; uint32_t m; /* Fast path - no signals pending means no work. Cursig being set means we've already worked out what to do. */ rescan: if (udata.u_cursig || !pending || udata.u_ptab->p_status == P_STOPPED) return udata.u_cursig; /* Dispatch the lowest numbered signal */ for (j = 1; j < NSIGS; ++j) { svec++; m = sigmask(j); if (!(m & pending)) continue; /* This is more complex than in V7 - we have multiple behaviours plus core dump */ if (*svec == SIG_DFL) { /* SIGSTOP can't be ignored and puts the process into P_STOPPED state when it is ready to handle the signal. Annoyingly right now we have to context switch to the task in order to stop it in the right place. That would be nice to fix */ if (m & stopper) { /* Don't allow us to race SIGCONT */ irqflags_t irq = di(); /* FIXME: can we ever end up here not in READY/RUNNING ? */ nready--; udata.u_ptab->p_status = P_STOPPED; udata.u_ptab->p_event = j; udata.u_ptab->p_pending &= ~m; // unset the bit irqrestore(irq); switchout(); /* Other things may have happened */ goto rescan; } /* The signal is being handled, so clear it even if we are exiting (otherwise we'll loop in chksigs) */ udata.u_ptab->p_pending &= ~m; if ((m & clear) || udata.u_ptab->p_pid == 1) { /* SIGCONT is subtle - we woke the process to handle the signal so ignoring here works fine */ continue; } #ifdef DEBUG kprintf("process terminated by signal %d\n", j); #endif /* We may have marked ourselves as asleep and then been caught by the chksigs when we tried to task switch into bed. In that case we need to put the process back in running state */ if (udata.u_ptab->p_status == P_SLEEP) { udata.u_ptab->p_status = P_RUNNING; nready++; } doexit(dump_core(j)); } else if (*svec != SIG_IGN) { /* Arrange to call the user routine at return */ udata.u_ptab->p_pending &= ~m; // unset the bit #ifdef DEBUG kprintf("about to process signal %d\n", j); #endif udata.u_cursig = j; break; } } return udata.u_cursig; }
arg_t _sched_yield(void) { if (nready > 1) switchout(); return 0; }