home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!mcsun!news.funet.fi!hydra!klaava!torvalds
- From: torvalds@klaava.Helsinki.FI (Linus Benedict Torvalds)
- Newsgroups: comp.os.linux
- Subject: Re: A technical question on CONTEXT (TASK) SWITCHING by the Kernel
- Keywords: task switch, context switch, task state segment, kernel
- Message-ID: <1992Aug21.072548.10633@klaava.Helsinki.FI>
- Date: 21 Aug 92 07:25:48 GMT
- References: <1992Aug20.164928.24749@ramsey.cs.laurentian.ca>
- Organization: University of Helsinki
- Lines: 80
-
- In article <1992Aug20.164928.24749@ramsey.cs.laurentian.ca> ron@ramsey.cs.laurentian.ca (Ron Prediger [Velociraptor]) writes:
- >Here is another technical question about the Linux kernel. Context
- >switching in particular.
-
- Ok, more answers...
-
- > #define switch_to(n) {\
- > struct {long a,b;} __tmp;\
-
- This just fools gcc to get 8 bytes of space on the stack, so that we
- don't have to get them anywhere else..
-
- > __asm__("cmpl %%ecx,_current\n\t"\
- > "je 1f\n\t
-
- %ecx is set up with the task we want to switch to when we enter the
- inline assembly statement, so this is obviosuly testing whether we are
- trying to switch to the current task, in which case nothing is done.
- Besides being an obvious optimization, I don't think the 386 allows a
- tss-jump to the current task (but not having my books around me, I can't
- check).
-
- > "movw %%dx, %1\n\t"\
-
- This just moves %dx (which contains the tss-selector) into the word at
- __tmp+4. So ___tmp looks like this:
-
- __tmp+0: undefined long
- __tmp+4: tss-selector word
- __tmp+6: undefined word
-
- > "xchgl %%ecx,_current\n\t"\
-
- This exchanges %ecx and 'current' - %ecx will contain the task we are
- now executing in, and 'current' will contain the task we are just about
- to jump to.
-
- > "ljmp %0\n\t"\
-
- This does the actual task switch: we do an indirect long-jump to __tmp.
- This is also the reason we updated just the word at __tmp+4: a long jump
- to a new tss-selector will ignore all other values. It will
- automatically jump to the place indicated by the tss segment.
-
- > "cmpl %%ecx,_last_task_used_math\n\t"\
-
- Yes, this looks illogical: we just did an unconditional jump, and this
- should never be reached. Right? Wrong. The ljmp will return once some
- other task does it's own ljmp to this task. Now %ecx contains the
- current task, so we check if this is the task that used the math
- coprocessor last...
-
- > "jne 1f\n\t"\
- > "clts\n"\
-
- ...in which case we can clear the TS flag, giving better
- math-performance. Due to these three lines, linux never saves math state
- unnecessarily.
-
- > "1:"\
- > "::"m" (*&__tmp.a),"m" (*&__tmp.b), \
-
- This just sets up %0 - pointing to '__tmp', and %1, pointing to
- '__tmp+4'.
-
- > "d" (_TSS(n)), "c" ((long) task[n]) \
-
- %dx contains the tss-descriptor for the task we want to switch to, and
- %ecx contains the task-pointer of the task we want to switch to.
-
- > :"cx");\
-
- And this just tells gcc that %ecx is changed by the inline-asm.
-
- That's it: 8 lines of assembly does the linux context switch with
- math-state optimizations. Note that newer sources should have a cli-sti
- pair around the "xchg %%ecx,_current ; ljmp %0", so that 'current' is
- always up-to-date, even when running under interrupts.
-
- Linus
-