Upload
letu
View
216
Download
0
Embed Size (px)
Citation preview
MTE 241 – Project Overview Real-time Operating System
RTX
Thomas Reidemeister
Deliverables
• Software design document (SDD)– Outlining the design of your RTX
• Demo– Demonstrate various features from requirements
• Final report– Describe changes to your design (SDD vs. Demo)
– Lessons learned
• Hard- and softcopy submissions (except code)
Functional Overview
6. Timing Process
Basic Requirements & Assumptions
Basic Requirements:• Non-preemptive scheduling• Managing processes that are only created once• Fixed priority scheduling• Message-based inter-process communication (IPC)
(asynchronous, messages are sent in envelopes)• Memory management (i.e. allocation, deallocation of message
envelopes)
Simplifying Assumptions:• All processes are known (at start-up; know each other)• Processes are non-malicious
1. Processor Management: Process States
1. Processor Management: Process Data
Process control block (PCB):• Needed for each process• Describes status and context of
process
current_process variable:• OS must know, which process
currently executes• … must be private• … always refers to PCB of
currently executing process
1. Processor Management: Process Switching
Process switching:1. Remove currently executing process from CPU2. Select next process to execute using scheduler3. Invoke context switch to new process• Hint: use private process_switch() routine
Context switching:1. Save context of currently executing process2. Update current_process to new process3. Set state of new process to executing4. Restore context of current_process5. Execute current_process• Hint: use private context_switch(new_proc) routine
2. Scheduling
Requirements:• Priority-based scheduling• Each process has assigned priority
– Highest priority process executes first– First-come-first-serve for processes of same priority
Procedure:
1. process_switch() invokes scheduler
2. Scheduler selects highest-priority ready process
3. context_switch(new_proc) lets the selected process execute
2. Scheduling: Ready Queues for Four Process Priorities
2. Scheduling: Designing Queues
• Queues are linked lists (remove first, append last)
• Use consistent private interface functions to interface the ready queues:– rpq_enqueue(PCB):
Enqueues PCB on appropriate ready queue based on its priority– rpq_dequeue():
Dequeues highest priority ready process
• TA advice:– Also promote reuse for individual queue functionality
– You will need it in a lot of places
– enqueue(queue, item): append item to queue
– Item = dequeue(queue): remove first item from queue
2. Scheduling: Null Process
• CPU must execute something• What to do when ready queues are empty?
– Possible solution: NULL process
– Make sure that the ready queue is never empty– NULL has lowest priority and is always ready to run
• Basic examplevoid null_process() {
while(1) {release_processor();
}}
2. Scheduling: release_processor()
release_processor() primitive must be included in the public RTX API
Basic Procedure:
1. Set current_process to state READY
2. rpq_enqueue(current_process)put current_process in ready queues
3. process_switch() invokes scheduler and context-switches to the new process
3. Initialization
What operations need to be carried out at start-up?• Initialize all “hardware” = Linux environment, incl.
– helper processes (… emulating IO devices)
– Memory mapped files for I/O (… emulating hardware buffers)– Signals and –handling (… emulating hardware interrupts)
• Create all kernel data structures– PCBs (status=ready), queues…– Place PCBs into respective queues
– Start first ready process (i.e. process_switch())
3. Initialization: Initialization Table
How does RTX know which processes to create?
Initialization Table:• Array of records• Each record contains
spec of its processand additional datastructures
• Hint: Use array ofstruct (C) or objects (C++)– You can adjust it more easily
4. Inter Process Communication (IPC)
Requirements:• Message-based, asynchronous IPC• Messages are carried in “envelopes”
Procedure:• Process writes into envelope• Process invokes public API functionsend_message(proc_id, envelope)
• Other process invokes public API function env = receive_message() and blocks if no message is available
4. IPC: Message Envelopes
Message envelopes are managed by kernel:
• Create appropriate number of envelopes during init
• Process allocates envelope using public API function request_message_env()
• Process deallocates envelope using public API function release_message_env(env) when not longer needed
4. IPC: Envelope Management
Where do the envelopes come from?• Need to allocate at start-up, preferably in an
empty-envelope-queue
• What if queue empty?– Process becomes blocked on resource– Design needs blocked-on-envelope queue for such PCBs
4. IPC: request_msg_env ()
request_msg_env() {atomic(on);while (free_env_Q is empty) {
put process object/PCB on blocked_env_Qset process state to blocked_on_env
process_switch();
***restart here when proc. executes eventually
}env -> reference to de-queued envelopeatomic(off); return env;
}
4. IPC: release_msg_env(msg)
release_msg_env(msg) {atomic(on);put env onto free_env_Qif ( blocked_env_Q not empty) {
dequeue one of the blocked processesset its state to ready and enqueue it…
…on ready process queue}atomic(off);
}• Invoking process never blocks• How does this interact with request_msg_env()?
4. IPC: Exchanging Messages
Requirement: messaged-based, asynchronous IPC
Design decisions:• Non-blocking send
• Blocking receive
Issues:• How do we handle multiple messages sent to a
process?• How does kernel track such messages?
4. IPC: Waiting Messages for Process
Idea: each process has a queue of waiting messages• Extend PCB as follows
4. IPC: receive_message()
receive_message() {atomic(on);while ( current_process’s msg_queue is empty) {
set state of current_process to blocked_on_receiveprocess_switch( );
*** return here when this process executes again}
env -> dequeued envelope from the process’ message queueatomic(off);return env;
}• When no messages available, process will block!• Issue: Where should the blocked processes go?
– Hint: no need for a queue, process will be unblocked by the next message send…
4. IPC: send_message(pid, env)
send_message( target_pid, env) : {atomic(on);set sender_procid, destination_procid…
…fields in envtarget_proc -> convert target_pid …
…to process obj/PCB refenqueue env onto the msg_queue of target_proc
if ( target_proc.state is blocked_on_receive) { set target_proc state to readyrpq_enqueue( target_proc );
}atomic(off);
}
• Send never blocks!• Send performs check if target_pid is blocked, if yes, it is
unblocked and put into the ready state
5. Interrupt Handling & Atomicity
Interrupt = HW message, usually requiring short latency and quick service
• Interrupts invoke pre-registered procedures that “interrupt” currently executing code
• Risks to RTX:– Inconsistencies– Corruption of kernel data structures– Unpredictable Execution
Atomicity = uninterruptible execution• Your kernel primitives must be atomic to avoid such
risks• Idea: define kernel function atomic(on/off)
5. Interrupt Handling: atomic(on/off)
• atomic(on) – Enables atomic functionality (by disabling interrupts) – First statement in each primitive
• atomic(off)– Disables atomic functionality (by enabling interrupts)– Last statement in each primitive (i.e. before return statement)
• Issue: Your primitives may call other atomic primitives– Hint: Introduce extra field atomic_count that increments on “ON”
and decrements on “OFF”
– Whenever atomic_count > 0, atomicity must be enabled
5. Interrupt Handling: Design Issues
Issues:
• Does interrupt-handling code run as part of kernel?
• Are interrupt-handlers interruptible?• Interrupts may change state for some blocked
processes• Linux and “interrupts”?
5. Interrupt Handling: Sequence
Interrupt Handler: Design
Requirement: Interrupt handler must interact with RTX.
Design: i-process
• i-process is scheduled by interrupt handler– Hint: we do not want so see direct calls to the i-process routine– The i-process has separate kernel data structures (stack etc)
• Is always ready to run, but not in ready queue
• i-process never blocks when invoking a kernel primitive
• Each i-process has a PCB
5. Interrupt Handler: Exampleinterrupt_handler {
set the state of current process to interruptedsave_proc = current_process
select interrupt sourceA:
context_switch (i_proc_A)break
…Z:
context_switch (i_proc_Z);break
end select
//code to save context of interrupt handler (i_process)current_process = save_proc;context_switch (save_proc);//perform a return from exception sequence//this restarts the original process before i_handler
}
5. Linux, Interrupts and Atomicity
• Project runs on Linux (already handles all interrupts of the hardware)
• Interrupt handling:– Simulate hardware devices using processes– Simulate interrupts using “signals”– (Hardware) interrupt handlers are signal handlers
• Atomicity usually achieved by “kernel mode” and specialized hardware support (… wait for Chapter 3 in lecture) … BUT– No access to “kernel mode” for Linux user processes
(i.e., trap instruction)– Hence, no need for software interrupt handlers
(i.e., SWI, trap table etc.)– Atomicity achieved by “atomic(on/off)” routine, discussed earlier
6. Timing Service as I-Process Example
Timing service is fundamental in RTX
Two design parts
• Interface design: – public request_delay(…) routine– Expiry notification by messages
• Internal design:– Related i-process to handle timer interrupt– Service request: user processes can send message to timing
service– Timeout notification: i-process send message back to user
process
6. Timing Service: request_delay
• API function sends timeout request as message to timing i-process and waits for a message from i-proc.
– Message contains timeout request– Request format:
6. Timing Service: Design
• Timing service i-process receives message with service request (non blocking!!!)
• After expiration time the timing i-process sends original message back
• Timeout service maintains requests in sorted list:
6. Timing Service: i-process
At each clock tick (i.e. interrupt), the timeout process:• Increments current_time• Invokes receive() to see new requests
(non-blocking!)• If any new requests, it adds them to the list
• Checks if any timing requests have been expired– If yes, send the notification back to the requestor
6. Timing I-Process Example
timeout_i_process:{ env = receive(); //to get pending requests while (env is not null) { //code to insert the envelope into the timeout_list
env = receive(); //see if any more requests }
if (timeout_list is not empty) { while (head_of_timeout_list.expiry_time <= cur_time) { env = timeout_list.dequeue(); target_pid = env.source_pid; env.source_pid = timeout_i_process_pid; send( target_pid, env ); //return envelope } }}
Tips
• Start early!• Do not live with “broken windows”
– Bad designs, wrong decisions, poor code
• Keep your code/design DRY - Do not Repeat Yourself– promote reuse of functionality
• Do not assume, prove it– Assertive programming (built your own ASSERT macro)– Use debugger for testing
(dump of data structures, test boundary cases)– Prototype for evaluating different designs (i.e., if time permits)– Clearly document any assumptions in SDD
• Use automation– Script unit tests (shell, maybe unit test frameworks)– Builds (Makefiles)
• Organize your team around functionality and strengths– Be honest about your strengths and weaknesses
• “The palest ink is better than the best memory.”– Built documentation in– Use comments
• Be proud of your work!
What is Next
• How to write software design documents (SDD)– What do we want to see– Ways to document code
• Selected problems from course book, potentially– Chapter 1: 3-10– Chapter 2: 3, 5, 11
– Chapter 3: 1, 2, 3, 4
• Code samples for certain project aspects, potentially– Function pointers– Linux process invocation– Signal handling– setjmp / longjmp
References
MTE241-related• MTE 241 Lecture Notes, R. Seviora, 2010• MTE 241 Project Description, P. Dasiewicz, 2010• “An Example Design of a Non-Preemptive Realtime
Kernel”, P. Dasiewicz, v1.03
Other:• ECE354 tutorial slides, Irene Huang