Discussions on hw3 Objective

Slides:



Advertisements
Similar presentations
Operating Systems Semaphores II
Advertisements

CS 4284 Systems Capstone Godmar Back Processes and Threads.
CSCC69: Operating Systems
Chapter 6 Limited Direct Execution
15-213/ Intro to Computer Systems by btan with reference to Spring 10’s slides.
Context Switch Animation Another one by Anastasia.
1 Function Calls Professor Jennifer Rexford COS 217 Reading: Chapter 4 of “Programming From the Ground Up” (available online from the course Web site)
Synchronization Principles. Race Conditions Race Conditions: An Example spooler directory out in 4 7 somefile.txt list.c scores.txt Process.
Home: Phones OFF Please Unix Kernel Parminder Singh Kang Home:
1 Homework Reading –PAL, pp , Machine Projects –Finish mp2warmup Questions? –Start mp2 as soon as possible Labs –Continue labs with your.
Microprocessors Frame Pointers and the use of the –fomit-frame-pointer switch Feb 25th, 2002.
Stacks and Frames Demystified CSCI 3753 Operating Systems Spring 2005 Prof. Rick Han.
Nachos Phase 1 Code -Hints and Comments
Lecture 3 Process Concepts. What is a Process? A process is the dynamic execution context of an executing program. Several processes may run concurrently,
CPS110: Implementing threads Landon Cox. Recap and looking ahead Hardware OS Applications Where we’ve been Where we’re going.
Linux Processes Travis Willey Jeff Mihalik. What is a process? A process is a program in execution A process includes: –program counter –stack –data section.
1 Computer Systems II Introduction to Processes. 2 First Two Major Computer System Evolution Steps Led to the idea of multiprogramming (multiple concurrent.
15-410, S’ Hardware Overview Jan. 19, 2004 Dave Eckhardt Bruce Maggs L04_Hardware “Dude, what were you thinking?”
LINUX System : Lecture 7 Process Bong-Soo Sohn Lecture notes acknowledgement : The design of UNIX Operating System.
Chapter 4 Process Abstraction Chien-Chung Shen CIS, UD
Functions/Methods in Assembly
More Discussions on hw5 Timer interrupts –called ticks. ISR called tick handler Kernel uses ticks for: –time keeping, incrementing the global system time.
1 Assembly Language: Function Calls Jennifer Rexford.
1 Hardware Overview Dave Eckhardt
Discussions on hw3 Objective –To implement multitasking of 3 Tiny-UNIX processes on the SAPC –Each process tries to output data to the COM2 output port.
Mutual Exclusion -- Addendum. Mutual Exclusion in Critical Sections.
CPS110: Implementing threads on a uni-processor Landon Cox January 29, 2008.
Discussions on hw1 Objectives –Modify I/O library for serial ports –change from ring buffer to queue –implement interrupts I/O Library TTY0TTYn testio.
Chapter 6 Limited Direct Execution Chien-Chung Shen CIS/UD
Transmitter Interrupts Review of Receiver Interrupts How to Handle Transmitter Interrupts? Critical Regions Text: Tanenbaum
Threads prepared and instructed by Shmuel Wimer Eng. Faculty, Bar-Ilan University 1July 2016Processes.
Virtualizing the CPU: Processes 1. How to provide the illusion of many CPUs? CPU virtualizing – The OS can promote the illusion that many virtual CPUs.
Homework / Exam Return and Review Exam #1 Reading Machine Projects
Process Tables; Threads
Process concept.
C function call conventions and the stack
Process Management Process Concept Why only the global variables?
CS 6560: Operating Systems Design
Processes.
Mechanism: Address Translation
Discussions on hw5 Objectives:
Anton Burtsev February, 2017
ICS143A: Principles of Operating Systems Lecture 13: Context switching
Homework Reading Machine Projects Labs PAL, pp ,
CSE451 Basic Synchronization Spring 2001
Process management Information maintained by OS for process management
Structure of Processes
Interrupt Driven I/O References Text: Tanenbaum ch.1.4.3, ch Receiver Interrupt Program Example:
Discussions on hw5 Objectives:
Discussions on hw1 Objectives Modify I/O library for serial ports
Process Tables; Threads
Assembly Language Programming II: C Compiler Calling Sequences
Thread Implementations; MUTEX
CSE 451: Operating Systems Spring 2012 Module 6 Review of Processes, Kernel Threads, User-Level Threads Ed Lazowska 570 Allen.
Discussions on HW2 Objectives
Transmitter Interrupts
Implementing Mutual Exclusion
Process Control B.Ramamurthy 2/22/2019 B.Ramamurthy.
Discussions on HW2 Objectives
Implementing Mutual Exclusion
Thread Implementations; MUTEX
Unix Process Control B.Ramamurthy 4/11/2019 B.Ramamurthy.
CSE 451: Operating Systems Autumn 2003 Lecture 7 Synchronization
CSE 451: Operating Systems Autumn 2005 Lecture 7 Synchronization
CS333 Intro to Operating Systems
Low-Level Thread Dispatching on the x86
Process Description and Control in Unix
* Preemptive Scheduling Fall 2002
Mechanism: Address Translation
* Preemptive Scheduling Fall 2002
Presentation transcript:

Discussions on hw3 Objective To implement multitasking of 3 Tiny-UNIX processes on the SAPC Each process tries to output data to the COM2 output port Process 1 Process 2 Process 3 Process 0

Details on the Processes Processes 1, 2 and 3 user processes doing outputs using syscall write and then exit have output queues with length = 6 chars Process 0 kernel process turns on interrupt by setting IF =1. It then loops and calls the scheduler with IF=0 and then IF=1 when it enters critical regions has a non-preemptive scheduler that will allow one (or more) process(es) to be blocked while another runs the simple scheduler looks for user process (1,2, or 3) to run. If none, chooses 0

Zombie Process After a process (1, 2, or 3) exits, it is a "zombie" process. The reason is: All that is really left is its exit value, waiting to be picked up by its parent. But there is no parent process to pick up.

Program Operations 3 user programs each outputting >6 chars to TTY one user process runs until it has filled the output buffer, then blocks(call scheduler and looks for another process to run) another process runs, also blocks because the output queue is full a third runs, blocks and no user processes are left to run so process 0 is chosen to run. As process 0 runs, output drains at interrupt level and the user processes are unblocked by a call to the scheduler from the TX int. handler. Process 0 calls the scheduler and it finds a process to run the chosen user process runs and refills the output buffer, then blocks the other two user processes run in turn and fill the output buffer and block again process 0 runs again over and over until the output is done

lib calls to do write, exit User Program Flow startup0.s: Same as $pclibsrc/startup0.s - init stack Start from Tutor startup1.c: init kernel Init memory Part of tunix.c: new module -call ioinit, set_trap_gate(0x80, &syscall): -init PEntry[] for Proc 0,1,2,3 -call schedule() to start Proc 0 Init kernel sched.c: new module -schedule() ; sleep();wakeup() -call _ustart1, _ustart2, or _ustart3 Scheduler Start-up crt01.s, crt02.s,crt03.s: -entry points:_ustart1, _ustart2, _ustart3 -call _main1, _main2, or _main3 -call _exit Start-up Start-up User program User program uprog1.c,uprog2,uprog3: Modify from testio.c: -entry points: main1, main2, main3 -call write User program ulib.s: syscall lib setups; -add _write, _exit lib calls to do write, exit

Kernel Program Flows sysentry.s: same as hw2 -push eax,ebx,ecx,edx on stack -call system call dispatcher: _syscallc -pop stack and iret Trap handler wrapper System call dispatcher Part of tunix.c: same as hw2 -entry point _syscallc -depend on syscall #, call the handler routine -need to modify sysexit to change state, and call schedule() System call trap handler routine tty.c: modify from hw2 -need to add debug_log -need to add wakeup at irqinthandc for tx interrupt -need to add sleep at ttywrite when queue is full

Process Entry Table #define N_SAVED_REGS 7 /* 7 non-scratch CPU registers, saved in this order: */ #define ESP1 0x280000 /* process 1 stack starting address */ #define ESP2 0x290000 /* process 2 stack starting address */ #define ESP3 0x2a0000 /* process 3 stack starting address */ #define N_SAVED_REGS 7 enum cpu_regs {SAVED_ESP, SAVED_EBX, SAVED_ESI, SAVED_EDI, SAVED_EBP, SAVED_EFLAGS, SAVED_PC}; /* for p_status ( RUN=1, BLOCKED=2, ZOMBIE=3) */ typedef enum proc_status {RUN = 1, BLOCKED, ZOMBIE} ProcStatus; /* for p_waitcode, what the process is waiting for */ typedef enum proc_wait {TTY0_OUTPUT = 1, TTY1_OUTPUT} WaitCode; /* Process Entry */ typedef struct { int p_savedregs[N_SAVED_REGS]; /* saved non-scratch registers */ ProcStatus p_status; /* RUN, BLOCKED, or ZOMBIE */ WaitCode p_waitcode; /* valid only if status==BLOCKED: TTY0_OUT, etc. */ int p_exitval; /* valid only if status==ZOMBIE */ } PEntry;

Process Entry Table(cont’d) /* the process table with four entries loaded with dummy values */ PEntry proctab[] = { {{0,0,0,0,0,0,0}, RUN, TTY1_OUTPUT, 0}, }; proctab[3].p_savedregs[SAVED_ESP] = ESP3; proctab[3].p_savedregs[SAVED_PC] = (int) &ustart3; proctab[3].p_savedregs[SAVED_EFLAGS] = 0x1 << 9; proctab[3].p_savedregs[SAVED_EBP] = 0; proctab[3].p_status = RUN;

debug_log function sprintf(buf, “^%c”, ch); debug_log(buf); stores the report in memory starting at 0x300000 and then outputs them If the program crashes, you can still use Tutor to see the log Tutor> md 300000 use debug_log(“~”) to mark each interrupt debug_log(“e”) for an echo debug_log(“s”) for shutdown Tx interrupts

debug_log function (cont’d) For hw3, add debug_log() for process switches |(0-1) for switching from process 0 to process 1 |(1Z-2) for switching from process 1, now a zombie, to process 2 |(1b-2) for switching from process 1, now blocked, to process 2

Context Switching function: asmswtch.s .globl _asmswtch # asmswtch--process switch # (but we don't need to save C scratch reg's, since they are assumed # to be smashed by calling this anyway) # Call from C: two arguments, pointers to old and new PEntry's: # asmswtch(oldpentryp, newpentryp) # # Stack when reach here: # %esp--> return pc # 4(%esp) oldpentryp # 8(%esp) newpentryp # # PEntry: saved esp # saved ebx # saved esi # saved edi # saved ebp # saved eflags # saved pc -- i.e., saved eip (where this was called from) newentryp oldpentryp return PC High address Low address %esp after Stack %esp before

asmswtch.s (cont’d) newpentryp oldpentryp return PC High address Low address %esp Wait code Proc status Save pc Save eflags Save ebp Save edi Save esi Save ebx Save esp Stack Old Process Entry _asmswtch: movl 4(%esp),%eax movl %esp, (%eax) movl %ebx, 4(%eax) movl %esi, 8(%eax) movl %edi, 12(%eax) movl %ebp, 16(%eax) movl (%esp), %ecx movl %ecx, 24(%eax) pushfl #push old eflags on stack popl 20(%eax)# pop it and store in loc movl 8(%esp), %eax movl (%eax), %esp movl 4(%eax), %ebx movl 8(%eax), %esi movl 12(%eax), %edi movl 16(%eax), %ebp pushl 20(%eax) # new eflags--push stored eflags on stack popfl # restore eflags movl 24(%eax), %ecx movl %ecx,(%esp) # restore top of stack=saved pc ret # return on newly reinstated stack +24 +20 +16 +12 +8 +4 +0

sleep function: sleep() Prototype void sleep(Waitcode event) Block the calling process by setting the process status = BLOCKED and waitcode = event Run the scheduler to start another process Disable interrupt at the beginning and restore interrupt at the end

wakeup function: wakeup() Prototype: void wakeup(Waitcode event) Go through all user processes. If process status = BLOCKED and waitcode = event, then change process status = RUN Disable interrupt at the beginning and restore interrupt at the end

Suggested Steps 1. Make sure your hw2 solution is fully working, or use the provided solution. Note that the provided solution has a "debug_log" service that writes notes to memory, and prints out the log when the kernel shuts down. Add this logging functionality to your own solution if you're using it for hw3. Note that you can add your own entries in the log to figure out what's happening. 2. Write trivial user programs that just kprintf a message each, and the crt0's for them that call mainx, and then do an exit syscall. Write a fake scheduler that just loops through proctab until it finds a status = RUN process and then calls it at ustartx. If there aren't any RUN ones left, bring down the system. Inside sysexit, call the scheduler after marking the process ZOMBIE. This simple system will work because each process only needs to run once. They use the same stack area one after another. Make sure your makefile is right: see that it rebuilds the right things after each edit. (mainx and ustartx where x =1,2,3)

Suggested Steps(cont’d) 3. Now use the supplied asmswtch code to start each process. For each user process, you need to initialize the PEntry's saved-pc to _ustartx, and the saved-eflags to allow interrupts, and the saved-esp to the proper stack. Also the saved-ebx should be 0. In your new fake scheduler, loop through the proctab until you find a RUN user process (1, then 2, then 3) and then call asmswtch with old-process = proc 0, new-process = proc 1, to switch from proc 0 to proc 1, thus running uprog1. Later, when proc 1 exits, sysexit calls the scheduler again, which finds proc 2, and calls asmswtch with pointers for (proc1, proc2) to switch from proc 1 to proc 2, and that runs uprog2. When uprog2 exits, sysexit calls the scheduler... Eventually the scheduler calls asmswtch with (proc3, proc0) to switch back to proc 0 when no more RUN processes exist. Then you can shut down the system using process 0. (Of course you can do just part of this to start, then write a more finished product.) Make sure the user processes are each using their own stack. 4. Add a debug_log call to the scheduler to report on each process switch, for example, "|(2z-3)" for a switch from process 2, a zombie, to process 3.With just kprintf's in your user programs, your debug log should look like this now: |(0-1)|(1z-2)|(2z-3)|(3z-0)

Suggested Steps(cont’d) 5. Add writes of one or two chars each to the three user programs and get this working--this output all fits in the 6-char queue, so no blocking is needed. This should work even though you haven't yet edited tty.c. Make sure the kernel waits for the output to drain while it's shutting down. Also make sure the user processes are running with interrupts enabled and using their appointed stack. You can check IF with get_eflags(), for example. Since the three writes return immediately, all the output will be done in the final kernel wait-for-output, and the debug log will look something like this (for 2 output chars for each process): |(0-1)~|(1z-2)~|(2z-3)|(3z-0)~~~~~s (Possibly more ~s will come earlier.) 6. Write the real scheduler after the class on this subject. Get it working in this too-easy user program environment. Change the code in tty.c to block and unblock at the right moments. Change to a 7-char output from one user program as soon as you want to try out blocking. When that works, try two, then all three with over-6 chars. Then the provided uprog's.

More on hw3 Define kernel global variables using PEntry structs proctab[], *curproc There are 4 entries in proctab[]: for processes 0,1,2,3 Processes 1,2,3 are user processes Process 0 derives from the startup and is always runnable

Major Kernel Functions schedule() : look for a user process to run. If not, run process 0. Call asmswtch. Called from process 0: from startup, sleep and sysexit sleep(event): block the calling process by changing p_status to BLOCKED, p_waitcode to event and then calling schedule() called from ttywrite (to replace the busy wait) wakeup(event): loop through proctab, changing all processes blocked on this event to p_status= RUN. Called from tty output interrupt handler

Interrupts for Major Functions These are all critical codes and should be run with interrupt off (IF=0) For wakeup(), it is only called from the interrupt handler with IF =0. Make sure the wakeup code does not set IF=1 wakeup() does not call schedule(). It just set p_status = RUN

Code Example on Critical Functions int sched(void){ … saved_eflags = get_eflags(); cli; …. asmswtch(…); set_eflags(saved_eflags); } Save a copy of eflags register Restore the eflags register

Schedule() Logic to determine Decision code which process to run Call asmswtch return Provide oldproc, curproc After return, it is running the new process

More Details on sleep() Modify ttywrite in hw2 to include sleep(): if (enqueue(…) = = FULLQUE) sleep(OUTPUT); /* can we enqueue now? Not for sure ! */ Suppose there are 2 processes A, and B that have been sleeping. Then they are unblocked by the wakeup function. If A runs first and it fills up the output queue. B runs sometime later and finds the buffer full. It should go to sleep again. The above code does not work this way. The correct code should look like: while (enqueue(…) = = FULLQUE) sleep(OUTPUT);

More Details on mutex In hw2, we use disabling/enabling interrupt (cli/sti) to protect concurrent modifications to the queue data structures In hw3, we use disabling/enabling interrupts (cli/sti) in sleep(), wakeup(), schedule() Where should we place the cli/sti’s? Look at the following example: while (guarded_enqueue(…) = = FULLQUE) guarded_sleep(OUTPUT); where guarded_xxx is the xxx function surrounded by cli and sti Interrupt occurs here; runs dequeue which wakes up the task; Wakeup will be ignored because the task is going to sleep

Solution to Lost Wakeup Problem Expand the cli/sti pair: cli(); while (enqueue(…) = = FULLQUE) sleep(OUTPUT); sti(); This works because sleep() calls schedule() which runs a new process with the new process’s EFLAGS Need to exercise care when we use the above solution. Look at the following example: cli(); x=1; /* x is a global variable */ while (enqueue(…) = = FULLQUE) sleep(OUTPUT); /* what is value of x here? still =1? Not necessary */ sti();