What is exactly saved and restored in a context switch between two threads
This is rather a complex question since the answer(s) are dependent on many things:
At a minimum the in use general purpose registers and program counter register will need to be saved (assuming the common design of most current CISC/RISC style general purpose CPUs).
Note that attempting to do only the minimal amount of effort in relation to a context switch is a topic of some academic interest
Linux obviously has more info available on this in the public domain though my references may be a little out of date.
There is a ‘task_struct’ which contains a large number of fields relating to the task state as well as the process that the task is for.
One of these is the ‘thread_struct’
/* CPU-specific state of this task */
- struct thread_struct thread;
holds information about cache TLS descriptors, debugging registers,
fault info, floating point, virtual 86 mode or IO permissions.
Each architecture defines it's own thread_struct which identifies the registers and other values saved on a switch.
This is further complicated by the presence of rename registers which allow multiple in flight instructions (either via superscalar or pipeline related architectural designs). The restore phase of a context swicth will likely rely on the CPU's pipeline being restored in a initially empty state such the the instructions which had not yet been retired in the pipeline have no effect and thus can be ignored. This makes the design of the CPU that much harder.
The difference between a process and a thread is that the process switch (which always means a thread switch in all main stream operating systems) will need to update memory translation information, IO related information and permission related structures.
These will mainly be pointers to the more rich data structures so will not be a significant cost in relation to the thread context switch.