140 likes | 250 Views
System Programming Project 2. Due : 4/19 ...?. Foreground & Background. Foreground job Only one at moment Having user ’ s focus Background job Many jobs running in background They are totally inpendent No focus. BG. BG. FG. BG. FG & BG & Stopped in Unix. BG. FG. fg. cmd&. cmd.
E N D
System ProgrammingProject 2 Due : 4/19 ...?
Foreground & Background • Foreground job • Only one at moment • Having user’s focus • Background job • Many jobs runningin background • They are totallyinpendent • No focus BG BG FG BG
FG & BG & Stopped in Unix BG FG fg cmd& cmd bg fg Ctrl+Z Stopped
FG & BG & Stopped Example >parrot hi 01-hi 02-hi >jobs [1] Stopped parrot hi >bg 1 >03-hi 04-hi >ls hello.c abc.txt shell >05-hi 06-hi >parrot hi & >01-hi 02-hi >jobs [1] Running parrot hi & >03-hi 04-hi >fg 1 05-hi ... 10-hi > Ctrl+Z Ex.1 Ex.2
Signal Handling in shell Ex. Terminating FG job user push Ctrl+C Shell receives ‘SIGINT’ signal Shell sends ‘SIGINT’ to FG job FG job receives ‘SIGINT’and terminates
Important Unix Signals • SIGINT (Ctrl+C by user) • terminate process • SIGTSTP (Ctrl+Z by user) • stop process • SIGCONT (from shell to child) • continue stopped process • SIGCHLD (from child to shell) • notify state change of child process • Run -> Complete • Run -> Terminate or Stop • Stop -> Run > kill –l : show all signals
signal(), sigaction() #include <signal.h> int flag; void myHandler (int sig) { flag=1; // this can stop while loop } main() { flag=0; while (!flag); printf(“1”); flag=0; while (!flag); printf(“2”); flag=0; while (!flag); printf(“3”); } // After myHandler is executed // SIGINT handler changes to default signal(SIGINT, myHandler); // SIGINT handler is myHandler forever struct sigaction action, old_action; action.sa_handler = myHandler; sigemptyset(&action.sa_mask); action.sa_flags = SA_RESTART; sigaction(SIGINT, &action, &old_action; This is exampleof busy-waiting
Specification 1/2 • Ctrl+C terminates FG job • Ctrl+C shouldn’t terminate shell • Do nothing if there is no FG job • Ctrl+Z stops FG job • Ctrl+Z shouldn’t stop shell • Do nothing if there is no FG job • Running in background • Putting ‘&’ in the end of command • Terminate all jobs when shell ‘exit’
Specification 2/2 • ‘jobs’ command • Shows list of job state • [job_id] state command • State is ‘BG running’ or ‘Stopped’ • ‘fg job_id’ command • Change ‘job_id’ job to FG job • Stopped or BG FG • ‘bg job_id’ command change a job to BG • Change ‘job_id’ job to BG job • Stopped BG - Don’t use exec(). - If ‘job_id’ is not specified, it’s up to you. Make it work like bash
SIGINT, SIGTSTP Handler sigint_handler { search FG job if there is FG job send SIGINT to FG job to terminate } sigtstp_handler { search FG job if there is FG job change the job’s state to Stopped send SIGTSTP to FG job to stop } Use ‘kill (pid, sig)’ to send signal!!
SIGCHLD Handler sigchld_handler { get pid whose state changed to completed / terminated / stopped / continue ... if it is terminated(SIGINT) or completed delete the job from job list shell comes back else if it is stopped(SIGTSTP) shell comes back } See Hints page!!
Hints • waitpid(pid, &status, option) • If pid=-1, wait for any child to change state • If option = WUNTRACED|WNOHANG • Return value is pid of process when process is terminated or stopped. 0 or -1 for other state change • WNOHANG means doesn’t wait • Status can be checked with macros. - If WIFEXITED(status) > 0, completed - If WIFSIGNALED(status) > 0, terminated - If WIFSTOPPED(status) > 0, stopped from http://database.sarang.net/study/glibc/24.htm and my try and error...T.T
Hints • Signal from group A goes to all process in group A • Shell’s group and child group is same as default. • But only shell should receive user’s signal. • setpgid(pid, pgid) • Set process group id • If pid=0, it is same as getpid() • If pgid=0, it is same as pid.(pid becomes a group leader) • getpgrp(), getpgid(pid) • get process group id
Hints • sigprocmask(mode, set, oldset) • Block signals • Example code sigset_t sigset, oldset;sigemptyset(&sigset);sigaddset(&sigset, SIGCHLD); sigprocmask(SIG_BLOCK, &sigset, &oldset); /* run the job *//* add job to job list */sigprocmask(SIG_UNBLOCK, &sigset, &oldset); Short jobs are terminated(sending SIGCHLD) before shell adds them to job list. Mask prevents this by blocking SIGCHLD.