CS644 User-Kernel Transitions

Diagrams from Class 9, thanks to Weiwei Gong:

Process executing over time:


ex. pid = getpid();

syscall that does i/o often has to wait(block)

 

 

Another way to go UàK: an interrupt happens (between two instructions)

 

 

Added notes:

These pictures are OK for both Xinu and UNIX/Linux, but some details are different in the two cases:

·         syscall instruction: trap type instruction on UNIX/Linux, plain call instruction for Xinu

·         return from kernel execution: iret instruction for interrupt handler return and UNIX/Linux syscall on x86, but Xinu uses plain ret instruction for syscall return

 

Xinu use of stacks:

·         Kernel stack grows on top of user stack starting from a syscall in user code.

·         Interrupt stack grows on top of user or kernel stack.

·         This all works because a process is only making progress in one activity at a time: a system call in execution means the user code is not making progress, an interrupt means the underlying user and/or kernel code is not making progress. When the interrupt is done, the underlying activity resumes.

 

UNIX/Linux:

·         Each thread has a kernel stack separate from its user stack

·         Interrupt stack may be separate or grow on top of kernel stack

 

 

Xinu Examples using hw2 solution (thanks to Truong Tran)

 

Case of plain user stack: worker calls lckwait, a user function:

Breakpoint 1, lckwait (lock={mutex = 86, users = 0x109010}) at lock.c:54

54        return wait(lock.mutex);

(gdb) where

#0  lckwait (lock={mutex = 86, users = 0x109010}) at lock.c:54

#1  0x100ace in worker (c=66 'B', lockp=0x3fd7dc) at test1.c:67

(gdb) c

Continuing.

 

Case of kernel stack growing on top of user stack, from syscall wait:

Breakpoint 2, enqueue (item=47, tail=223) at ../sys/queue.c:18

18              tptr = &q[tail];

(gdb) where

#0  enqueue (item=47, tail=223) at ../sys/queue.c:18

#1  0x102879 in wait (sem=86) at ../sys/wait.c:28        <--syscall “wait”

#2  0x1008f8 in lckwait (lock={mutex = 86, users = 0x109010}) at lock.c:54

#3  0x100ace in worker (c=66 'B', lockp=0x3fd7dc) at test1.c:67  <---worker process

(gdb) b putc

Breakpoint 3 at 0x102aa2: file ../sys/putc.c, line 17.

(gdb) c

Continuing.

 

Case of kernel stack growing on top of user stack, from syscall putc

Breakpoint 3, putc (descrp=0, ch=108 'l') at ../sys/putc.c:17

17              if (isbaddev    (descrp) )

(gdb) where

#0  putc (descrp=0, ch=108 'l') at ../sys/putc.c:17        <--syscall “putc”

#1  0x100be9 in _doprnt (

    fmt=0x100923 "ockkill: see lock.users = %d, nusers = %d\n", args=0x3fd7c0,

    func=0x102a94 <putc>, farg=0) at doprnt.c:44

#2  0x100b9f in printf (

    fmt=0x100922 "lockkill: see lock.users = %d, nusers = %d\n", args=0)

    at printf.c:15

#3  0x100974 in lckkill (lock={mutex = 86, users = 0x109010}, nusers=2) at lock.c:79

#4  0x100a87 in main (argc=0, argv=0x102d70) at test1.c:55   <---main process start

#5  0x101948 in startmain () at ../sys/main.c:18   <--kernel sets up user main

 

(gdb) b clkint

Breakpoint 6 at 0x100752

(gdb) c

Continuing.

 

Case of interrupt stack on top of user stack: clock interrupt during printf execution

Breakpoint 6, 0x100752 in clkint () at ../sys/initialize.c:201

201     }

(gdb) where

#0  0x100752 in clkint () at ../sys/initialize.c:201

#1  0x100be9 in _doprnt (fmt=0x100925 "kkill: see lock.users = %d, nusers = %d\n",

    args=0x3fd7c0, func=0x102a94 <putc>, farg=0) at doprnt.c:44

#2  0x100b9f in printf (

    fmt=0x100922 "lockkill: see lock.users = %d, nusers = %d\n", args=0)

    at printf.c:15

#3  0x100974 in lckkill (lock={mutex = 86, users = 0x109010}, nusers=2) at lock.c:79

#4  0x100a87 in main (argc=0, argv=0x102d70) at test1.c:55

#5  0x101948 in startmain () at ../sys/main.c:18