The OS kernel: Implementing processes and Threads Kernel Definitions and Objects Queue Structures Threads Implementing Processes and Threads Implementing Synchronization and Communication Mechanisms Interrupt Handling
Kernel Definitions and Objects Process and thread management Interrupt and trap handling Resource management Input and output OS kernel: a basic set of objects, primitive operations, data structures, and processes from which the remainder of the system may be constructed
Kernel psps p1p1 pjpj q1q1 pnpn qmqm …… … Interactions with kernel objects A Process Creation Hierarchy
Queue structures Queues in OSs --queue for PCB --queues for hardware managers --queues for synchronization --queues for shared software components Implementations of Queues --single-level queues --priority queues
Implementations of queues Types of queues: --FIFO --priority based Elements of queues Operations related to queues --insert( queue Q, element x) --remove( queue Q, element x) --empty( queue Q) Header or descriptor of queues
Single-Level Queues Circular array Linked list Queue pointer front rear... Occupied portion... header Queue pointer front rear... header null...
Priority queues Fixed-number priorities Queue pointer front rear i N-1...
Binary heap
Threads The normal implementation of processes results in much runtime overhead. To alleviate this problem, multiple “lightweight” scheduling units is implemented within a process. These units share the same resources as there host process
Create a new thread; Initiate or make a thread ready; Destroy or terminate a thread; Delay or terminate a thread Delay or put a thread to sleep for a given amount of time; Synchronize threads through semaphores, events or condition variables; Perform lower-level operations, such as blocking, suspending, or scheduling a thread Operations on threads:
Implementing processes and threads Process and thread descriptors Implementing operations on processes Operations on threads
PCB Identification State vector Processors Status information Creation tree other information
Structure of process descriptor PCB ID Cpu_state Processor_ID memory Open_files Other_resources list type priority parent child... processors resources State vector status Creation_tree Other information
State vector
Status information running Ready_a Ready_s Blocked_a Blocked_s
Implementing operations on processes Create Create(so,mo,pi,pid){ p=Get_New_PCB(); pid=Get_New_PID(); p->ID=pid; p->CPU_State=s0; p->Memory=m0; p->Priority=pi; p->State.Type=“ready_s”; p->Creation_tree.Parent=self; p->Creation_Tree.child=NULL; insert(self->Creation_tree.child,p); insert(RL,p); Scheduler(); }
Suspend suspend(pid){ p=Get_PCB(pid); s=p->Status.Type; if((s==“blocked_a”)||(s==“blocked_s”)) p->status.Type=“block_s”; else p->status.Type=“ready_s”; if(s==“running”){ cpu=p->Processor_ID; p->CPU_State=Interrupt(cpu); Scheduler(); }
Activate Activate(pid){ p=Get_PCB(pid) if(p->Status.Type==“ready_s”){ p->Status.Type=“ready_a”; Scheduler(); } else p->status.Type=“blocked_a”; }
Destroy Destroy(pid){ p=Get_PCB(pid); Kill_Tree(p); Scheduler(); } Kill_Tree(p){ for(each q in p->Creation_Tree.Child) Kill_Tree(q); if(p->Status.Type==“running”){ cpu=p->Processor_ID Interrupt(cpu); } Remove(p->Status.List,p); Release_all(p->Memory); Release_all(p->Other_Resources); Close_all(p->Open_Files); Delete_PCB(p); }
Implementing synchronization and communication mechanisms Semaphores and locks Monitor primitives Clock and time management Communication
General version of the Request/Release Request(res){ if(Free(res)) Allocate(res,self); else{ Block(self,res); Scheduler(); } Release(res){ Deallocate(res,self); if(Process_Blocked_on(res,pr){ Allocate(res,pr); Unblock(pr,res); Scheduler(); }
Semaphores and locks BT : carry appointed bit to CF; BTC : carry appointed bit to CF, and reverse it; BTR : carry appointed bit to CF, and change it to 0; BTS : carry appointed bit to CF, and change it to 1; Bit Test Instruction :
Spin Locks on Binary Semaphores Pb(sb): do TS(R,sb); while(!R);/*wait loop*/ Vb(sb): sb=1;
General Semaphores with spin locks P p(s){ s=s-1; if(s<0){ Pb(delay_s; } V v(s){ s=s+1; if(s<=0) Vb(delay_s); else } Pb(mutex_s); Vb(mutex_s); Pb(mutex_s); Vb(mutex_s);
Avoiding the Busy-Wait P(s){ Inhibit_Interrupts; Pb(mutex_s); s=s-1; if(s<0){ Block(self, Ls); Vb(mutex_s); Enable_Interrupts; Scheduler(); } else{ Vb(mutex_s); Enable_Interrupts; } V(s){ Inhibit_Interrupts; Pb(mutex_s); s=s+1; if(s<=0){ Unblock(q, Ls); Vb(mutex_s); Enable_Interrupts; Scheduler(); } else{ Vb(mutex_s); Enable_Interrupts; }
Primitive and atomic operation Priority Interrupt request Switching tasks on single CPU Switching tasks on multiple CPU
struct semaphore { atomic_t count; int sleepers; wait_queue_head_t wait; #if WAITQUEUE_DEBUG long __magic; #endif }; static inline void down(struct semaphore * sem) { #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif __asm__ __volatile__( "# atomic down operation\n\t" LOCK "decl %0\n\t" /* -- sem->count */ "js 2f\n" "1:\n" LOCK_SECTION_START("") "2:\tcall __down_failed\n\t" "jmp 1b\n" LOCK_SECTION_END :"=m" (sem->count) :"c" (sem) :"memory"); }
asm( ".text\n" ".align 4\n" ".globl __down_failed\n" "__down_failed:\n\t" #if defined(CONFIG_FRAME_POINTER) "pushl %ebp\n\t" "movl %esp,%ebp\n\t" #endif "pushl %eax\n\t" "pushl %edx\n\t" "pushl %ecx\n\t" "call __down\n\t" "popl %ecx\n\t" "popl %edx\n\t" "popl %eax\n\t" #if defined(CONFIG_FRAME_POINTER) "movl %ebp,%esp\n\t" "popl %ebp\n\t" #endif "ret" );
void __down(struct semaphore * sem) { struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); tsk->state = TASK_UNINTERRUPTIBLE; add_wait_queue_exclusive(&sem->wait, &wait); spin_lock_irq(&semaphore_lock); sem->sleepers++; for (;;) { int sleepers = sem->sleepers; /* * Add "everybody else" into it. They aren't * playing, because we own the spinlock. */ if (!atomic_add_negative(sleepers - 1, &sem->count)) { sem->sleepers = 0; break; } sem->sleepers = 1;/* us - see -1 above */ spin_unlock_irq(&semaphore_lock); schedule(); tsk->state = TASK_UNINTERRUPTIBLE; spin_lock_irq(&semaphore_lock); } spin_unlock_irq(&semaphore_lock); remove_wait_queue(&sem->wait, &wait); tsk->state = TASK_RUNNING; wake_up(&sem->wait); }
static inline void spin_lock(spinlock_t *lock) { #if SPINLOCK_DEBUG __label__ here; here: if (lock->magic != SPINLOCK_MAGIC) { printk("eip: %p\n", &&here); BUG(); } #endif __asm__ __volatile__( spin_lock_string :"=m" (lock->lock) : : "memory"); } #define spin_lock_string \ "\n1:\t" \ "lock ; decb %0\n\t" \ "js 2f\n" \ LOCK_SECTION_START("") \ "2:\t" \ "cmpb $0,%0\n\t" \ "rep;nop\n\t" \ "jle 2b\n\t" \ "jmp 1b\n" \ LOCK_SECTION_END
#define spin_lock_irq(lock)do { local_irq_disable(); spin_lock(lock); } while (0)
Monitor primitives Body of each procedure: p(mutex); procedure_body; if(urgentcnt) V(urgent); else V(mutex); C.wait: condcnt_c=condcnt_c+1; if(urgentcnt) V(urgent); else V(mutex); P(condsem_c) condcnt_c=condcnt-1; C.signal: if(condcnt_c){ urgentcnt=urgentcnt+1; V(condsem_c); P(urgent); urgentcnt=urgentcnt-1; }
Clock and Time Management Wall clock timer -- Update_clock -- Get_Time -- SetClock(tnew) Countdown Timers -- Set_Timer(tdel) -- Delay(tdel) Delay(tdel){ Set_timer(tdel); P(delsem); } -- TimeOut() TimeOut( ){ V(delsem): }
Implementing logical timers Logical timer -- tn=Create_LTimer(); -- Destroy_LTimer(tn); -- SetLTimer(tn,tdel);
Using a Priority Queue with Absolute Wakeup Times Hardware timers Wall-clockcountdown Timer queue TQ a p1115p2135p3140p4150 b p1115p2135p3138p4140 TQ p5150
Using a Priority Queue with Time Differences Hardware timers countdown 12 Timer queue TQ a p115p220p35p410 b p115p220p33p42 TQ p510
Communication primitives Generic form of message-passing primitives -- send(p,m) -- receive(q, m) Two issues must be resolved -- how does the sender know that sbuf has been copied and may be reused? -- how does the system know that the contents of rbuf are no longer needed by the receiver and may be overwritten? Solutions -- blocking -- nonblocking (system buffers)
Interrupt Handling Interrupt concept -- an event occurring at an unpredictable time that forces a transfer of control out of the normal processing sequence of a computer -- the purpose of interrupt handling is to remove the notion of asynchronous events from higher levels of the kernel, the OS, and applications Common operations on interrupts -- enable -- disable -- inhibit
More uniform abstract model of interrupt handling Hardware device interrupt monitor Fn() IH() P Fn()... Init c.wait... c.signal OS call c