160 likes | 263 Views
A very simple kernel. ITV Multiprogramming and Real-Time Programs Anders P. Ravn May 2009. A kernel specification. /* kernel.h Interface to a lightweight kernel that implements concurrent processes and a release primitive `pause'. Anders P. Ravn, DTU, Denmark 24 April 1998
E N D
A very simple kernel ITV Multiprogramming and Real-Time Programs Anders P. Ravn May 2009
A kernel specification /* kernel.h Interface to a lightweight kernel that implements concurrent processes and a release primitive `pause'. Anders P. Ravn, DTU, Denmark 24 April 1998 apr@it.dtu.dk */ typedef void (*Program)(void); /* A program text is a function without parameters*/ typedef void * Thread; /* identifier for a process */ extern Thread create(Program p,unsigned int stacksize); /* creates a process with a stackof the specified size and starts it executing theprogram. If there is insufficientmemory, the result is NULL */ extern void pause(void); /* release the processor */
Multiprogramming #include ”kernel.h” void process() { /* do something */ pause(); /* do something */ } void main() { Thread p1, p2; p1 = create(&process,2000); /* p1 is started */ p2 = create(&process,1000); /* p2 is started */ /* the kernel will see to it that main is left when both p1 and p2 has exited */ }
A kernel implementation I typedef unsigned long Register; typedef struct x {struct x* next; Register esp;} Threaddescriptor; static Threaddescriptor* ready; /* queue of threads linked cyclically; ready points to last, the first is current */ #define current ready->next ready: current esp1 esp2 esp3
A kernel implementation II void pause() { Register sp; __asm__(”pushal movl %%esp,%sp"); /* sp -> |saved registers ... | eip return from call */ DISABLE; /* scheduling */ current->esp = sp; ready = current; sp = current->esp; __asm__(" movl %sp,%%esp popal" ); ENABLE; } stack1 stack2 ready: current esp1 esp2 esp3
A kernel implementation III pause: pushl %ebp movl %esp,%ebp pushal movl %esp,%ecx sp = esp movl ready,%eax movl (%eax),%edx current->esp movl %ecx,4(%edx) = sp movl %edx,ready ready = current movl (%edx),%edx movl 4(%edx),%ecx sp = current->esp movl %ecx,%esp popal leave ret
A kernel implementation IV pause: pushal movl ready,%eax movl (%eax),%edx current->esp movl %esp,4(%edx) = esp movl %edx,ready ready = current movl (%edx),%edx movl 4(%edx),%esp esp = current->esp popal ret
Critical regions void enter_crit(Gate g) /* enter critical region */ {}; void leave_crit(Gate g) /* leave critical region */ {}; void init_crit(Gate g) {}; extern void await(Gate g, Boolean *b) /* wait in a critical region for a condition b to become true */ {while (!*b) { // leave_crit pause(); // enter crit } };
Stop Process void stop(void) {/* called implicitly when a process exits its program Entry: esp -> | ... | dummy must not be used ebp -> | old ebp | <- stack before entry to stop */ Register dummy; Proc thisp; Register cursp; thisp = current; if (thisp == initproc) {/* set up for final exit from multiprogramming esp -> | saved registers | ... ebp = saved ebp saved ebp -> | final.oldebp ebp -> | final.eip | ... */ __asm__(" pushal movl %%esp,%0" : "=g" (cursp) ); ((SavedRegisters *)cursp)->ebp = (Register)ebp; initproc->esp = cursp; *(ebp+1) = final.eip; *ebp = final.oldebp; }; DISABLE /* remove current process */ #if TEST printf("Stop process %x\n",current); #endif current = thisp->next; if (head == thisp) {head = NULL; #if TEST printf("Stop kernel\n"); #endif /* exit for final program, prepared above */ cursp = initproc->esp;} else /* activate current */ cursp = current->esp; __asm__(" movl %0,%%esp popal" : : "g" (cursp) ); ENABLE return;};
Stop Process II thisp = current; if (thisp == initproc) {/* set up for final exit from multiprogramming esp -> | saved registers | ... ebp = saved ebp saved ebp -> | final.oldebp ebp -> | final.eip | ... */ __asm__(" pushal movl %%esp,%0" : "=g" (cursp) ); ((SavedRegisters *)cursp)->ebp = (Register)ebp; initproc->esp = cursp; *(ebp+1) = final.eip; *ebp = final.oldebp; };
Stop Process III DISABLE /* remove current process */ current = thisp->next; if (head == thisp) {head = NULL; /* exit for final program, prepared above */ cursp = initproc->esp;} else /* activate current */ cursp = current->esp; __asm__(" movl %0,%%esp popal" : : "g" (cursp) ); ENABLE return;};
Create Process #define descriptor sizeof(Processdescriptor) #define overhead descriptor +sizeof(SavedRegisters) +2*sizeof(ReturnInfo) #define stopentry (Register) &stop Thread create(Program p,unsigned int stacksize) {Proc newp; Register *sp, bp; if ((head == NULL) && ((newp = (Proc)malloc(descriptor)) != NULL) ) { /* At this point, the process state is as follows: esp -> | ... ... ebp -> | old ebp old frame pointer | eip return from call of create ... old ebp -> | old2 ebp | eip return from call of initial process | ... stack of caller */
Create Process II /* save call of initial process in "final" initialize return to call "stop" on final exit */ __asm__(" movl %%ebp,%0" : "=g" (ebp) ); (Register) ebp = *ebp; final.oldebp = *ebp; final.eip = *(ebp+1); *(ebp+1) = stopentry; /* save identity of initial process */ initproc = newp; DISABLE /* enter process descriptor in queue */ head = newp->next = newp; ENABLE };
Create Process III if ( ( newp = (Proc)malloc(stacksize+overhead)) != NULL) { /* create new process The state when activated shall be: newp -> | next ProcessDescriptor | sp ... sp-> | saved registers fp -> | 0 sfp-> | p entry return address when activated | stopentry exit address | <- newp+stacksize+overhead immediately when p is entered, we have: ebp = 0 esp-> | stopentry exit address | <- newp+stacksize+overhead */ sp = (Register*)((unsigned int)newp+stacksize+overhead); *(--sp) = stopentry; *(--sp) = (Register)p; *(--sp) = 0; bp = (Register)sp; (Register)sp -= sizeof(SavedRegisters); ((SavedRegisters *)sp)->old_esp = ((SavedRegisters *)sp)->ebp = bp; newp->esp = (Register)sp; DISABLE newp->next = current; current = newp; head = newp; ENABLE #if TEST printf("Created new process\nhead %x %x %x %x esp %x ebp %x\n", head, head->next, (head->next)->next, ((head->next)->next)->next,sp,bp); #endif (Register)sp = bp; #if TEST printf("-> ... %x %x %x\n", *sp,*(sp+1),*(sp+2)); #endif }; return (Thread) newp; };
Create Process IV sp = (Register*)((unsigned int)newp+stacksize+overhead); *(--sp) = stopentry; *(--sp) = (Register)p; *(--sp) = 0; bp = (Register)sp; (Register)sp -= sizeof(SavedRegisters); ((SavedRegisters *)sp)->old_esp = ((SavedRegisters *)sp)->ebp = bp; newp->esp = (Register)sp; DISABLE newp->next = current; current = newp; head = newp; ENABLE (Register)sp = bp; }; return (Thread) newp; };
Create Process #define descriptor sizeof(Processdescriptor) #define overhead descriptor+sizeof(SavedRegisters)+2*sizeof(ReturnInfo) #define stopentry (Register) &stop Thread create(Program p,unsigned int stacksize) {Proc newp; Register *sp, bp; if ((head == NULL) && ((newp = (Proc)malloc(descriptor)) != NULL) ) { /* At this point, the process state is as follows: esp -> | ... ... ebp -> | old ebp old frame pointer | eip return from call of create ... old ebp -> | old2 ebp | eip return from call of initial process | ... stack of caller */ /* save call of initial process in "final" initialize return to call "stop" on final exit */ __asm__(" movl %%ebp,%0" : "=g" (ebp) ); (Register) ebp = *ebp; final.oldebp = *ebp; final.eip = *(ebp+1); *(ebp+1) = stopentry; /* save identity of initial process */ initproc = newp; DISABLE /* enter process descriptor in queue */ head = newp->next = newp; ENABLE #if TEST printf("Initial process created\nhead %x current %x ebp %x final %x %x\n", head,current, ebp, final.oldebp, final.eip); #endif }; if ( ( newp = (Proc)malloc(stacksize+overhead)) != NULL) { /* create new process The state when activated shall be: newp -> | next ProcessDescriptor | sp ... sp-> | saved registers fp -> | 0 sfp-> | p entry return address when activated | stopentry exit address | <- newp+stacksize+overhead immediately when p is entered, we have: ebp = 0 esp-> | stopentry exit address | <- newp+stacksize+overhead */ sp = (Register*)((unsigned int)newp +stacksize + overhead); *(--sp) = stopentry; *(--sp) = (Register)p; *(--sp) = 0; bp = (Register)sp; (Register)sp -= sizeof(SavedRegisters); ((SavedRegisters *)sp)->old_esp = ((SavedRegisters *)sp)->ebp = bp; newp->esp = (Register)sp; DISABLE newp->next = current; current = newp; head = newp; ENABLE #if TEST printf("Created new process\nhead %x %x %x %x esp %x ebp %x\n", head, head->next, (head->next)->next, ((head->next)->next)->next,sp,bp); #endif (Register)sp = bp; #if TEST printf("-> ... %x %x %x\n", *sp,*(sp+1),*(sp+2)); #endif }; return (Thread) newp; };