/* * Requires: * "s" is a properly terminated string. * * Effects: * Prints the string "s" to stdout using only functions that can be safely * called by a signal handler, and exits the program. */ static void sio_error(char s[]) { sio_puts(s); _exit(1); }
ssize_t sio_putl(long v) /* Put long */ { char s[128]; sio_ltoa(v, s, 10); /* Based on K&R itoa() */ //line:csapp:sioltoa return sio_puts(s); }
ssize_t Sio_puts(char s[]) { ssize_t n; if ((n = sio_puts(s)) < 0) sio_error("Sio_puts error"); return n; }
/* * Requires: * None. * * Effects: * Prints the long "v" to stdout using only functions that can be safely * called by a signal handler, and returns either the number of characters * printed or -1 if the long could not be printed. */ static ssize_t sio_putl(long v) { char s[128]; sio_ltoa(v, s, 10); return (sio_puts(s)); }
/* * sigchld_handler - The kernel sends a SIGCHLD to the shell whenever * a child job terminates (becomes a zombie), or stops because it * received a SIGSTOP, SIGTSTP, SIGTTIN or SIGTTOU signal. The * handler reaps all available zombie children, but doesn't wait * for any other currently running children to terminate. */ void sigchld_handler(int sig) { int status; pid_t pid; int olderrno = errno; // store errno in handler /* * Reap child with the pid if the child is stopped or terminated * If a child is terminated normally, delete the child from the job list * If a child is stopped by a signal, set the job status as stopped * If a child is terminated by a signal that was not caught, delete the child from the job list */ while ((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) > 0) { if (WIFEXITED(status)) { deletejob(job_list, pid); // the child ternimated normally } else if (WIFSTOPPED(status)) { /* * Avoid printf() in handler, use helper function to write the output to stdout */ sio_puts("Job ["); sio_putl(pid2jid(pid)); sio_puts("] ("); sio_putl(pid); sio_puts(") stopped by signal "); sio_putl(WSTOPSIG(status)); sio_puts("\n"); getjobpid(job_list, pid) -> state = ST; // the child was stopped by a signal } else if (WIFSIGNALED(status)) { // the child was terminated by a signal that was not caught /* * Avoid printf() in handler, use helper function to write the output to stdout */ sio_puts("Job ["); sio_putl(pid2jid(pid)); sio_puts("] ("); sio_putl(pid); sio_puts(") terminated by signal "); sio_putl(WTERMSIG(status)); sio_puts("\n"); deletejob(job_list, pid); } } errno = olderrno; return; }
/* * sigchld_handler - The kernel sends a SIGCHLD to the shell whenever * a child job terminates (becomes a zombie), or stops because it * received a SIGSTOP or SIGTSTP signal. The handler reaps all * available zombie children, but doesn't wait for any other * currently running children to terminate. * * Requires: * When a child job terminates or stops, it sends out signal successfully * * Effects: * If the child job is stopped by a signal, change its state and print signal * information; if the child job is terminated by a signal, print signal * information and delete the child job; if the child job is terminated in * other ways, delete it. The handler reaps all available zombie children, * but doesn't wait for any currently running children to terminate. */ static void sigchld_handler(int signum) { // Prevent an "unused parameter" warning. (void)signum; pid_t pid; int status; // Reap zombie children but doesn't wait for currently running children while ((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { struct Job *pcurjob = getjobpid(jobs, pid); if (!pcurjob) { app_error("pcurjob in sigtstp_handler"); } // If a child stops, change its state to ST and print the information if (WIFSTOPPED(status)) { pcurjob->state = ST; char *print; asprintf(&print, "Job [%d] (%d) stopped by signal SIGTSTP\n", pid2jid(pid), pid); sio_puts(print); } // If a child terminates by signal, print the information and delete the job else if (WIFSIGNALED(status)) { char *print; asprintf(&print, "Job [%d] (%d) terminated by signal SIGINT\n", pcurjob->jid, pcurjob->pid); sio_puts(print); deletejob(jobs, pid); } // Delete the job is the child terminates in any other way else { deletejob(jobs, pid); } } return; }
/** * Writes a character to the serial console. */ void sio_putchar( char ch ) { static char buf[2] = {'\0', '\0'}; buf[0] = ch; sio_puts(buf); }
void sio_error(char s[]) /* Put error message and exit */ { sio_puts(s); _exit(1); //line:csapp:sioexit }
static void * sior_rpc_server(u32 funcno, void * data, int size) { int res = 0, c; size_t s; char * p; struct init_arguments_t * i; switch(funcno) { case SIOR_INIT: i = (struct init_arguments_t *) data; sio_init(i->baudrate, i->lcr_ueps, i->lcr_upen, i->lcr_usbl, i->lcr_umode); break; case SIOR_PUTC: c = *((int *) data); res = sio_putc(c); break; case SIOR_GETC: res = sio_getc(); break; case SIOR_GETCBLOCK: res = sio_getc_block(); break; case SIOR_WRITE: p = *((char **) data) + IOP_MEM; s = *(((size_t *) data) + 1); DI(); ee_kmode_enter(); res = sio_write(p, s); ee_kmode_exit(); EI(); break; case SIOR_READ: p = *((char **) data) + IOP_MEM; s = *(((size_t *) data) + 1); DI(); ee_kmode_enter(); res = sio_read(p, s); ee_kmode_exit(); EI(); break; case SIOR_PUTS: p = *((char **) data) + IOP_MEM; DI(); ee_kmode_enter(); res = sio_puts(p); ee_kmode_exit(); EI(); break; case SIOR_PUTSN: p = *((char **) data) + IOP_MEM; DI(); ee_kmode_enter(); res = sio_putsn(p); ee_kmode_exit(); EI(); break; case SIOR_GETS: p = *((char **) data) + IOP_MEM; DI(); ee_kmode_enter(); (char*)res = sio_gets(p); ee_kmode_exit(); EI(); break; case SIOR_FLUSH: sio_flush(); break; } *((int *) data) = res; return data; }
/* * Log - emits I/O safe logs whether global * macro LOG is on or off */ void Log(char *msg, int len) { sio_puts(msg, len & logger); }