How to ensure data integrity in General Purpose Registers (GPR registers) given their limited number (for x86 their number is 6),and on the other hand that they are used simultaneously by all processes?
-
$\begingroup$ They aren't really used simultaneously. When a context switch occurs, they are saved and subsequently restored. $\endgroup$– Yuval FilmusCommented Apr 5, 2018 at 17:29
-
$\begingroup$ IIRC, x86 currently is somewhere close to 200 (per CPU core). There are 6 names, but the association between register and register names is dynamic. $\endgroup$– MSaltersCommented Apr 6, 2018 at 8:02
1 Answer
Their integrity is maintained by several features working in conjunction.
For synchronous code execution, function calls, i.e. invocations, generally require some management. This management is named the calling convention. Both caller and callee must agree on the same convention or else things break. (It is possible for one caller and callee to agree, then have that callee, now play caller to call someone else, using an alternate calling convention they both agree upon. This works but might make stack unwinding more complex for the debugger, or for error handling/exceptions.) The calling convention dictates how parameters are passed (registers & stack), how return values are passed back, and certain registers don't participate in the invocation and are particularly designated for retaining their original caller-defined values across the call — meaning that if the callee want to use those designated registers it has to save them first, and then restore them before returning.
For asynchronous code execution of threads/processes, either the hardware provides multiple CPUs or the software is time-slicing the CPUs, or both.
If the hardware provides multiple CPUs (whether by hyperthreading or full blown CPUs), it provides sufficient register sets for all the CPUs, so it provides a copy of the necessary processor state for each provided processors. Some of the computation units may be shared (e.g. in hyperthreading), but the register state is duplicated.
When software (e.g. operating system) does time-slicing, it uses a clock or other interrupt to suspend one thread's operation, and resume another thread (that had may have been previously suspended in a similar manner).
The interrupt mechanism itself requires cooperation between hardware and software. Generally speaking, the hardware provides the minimal features necessary, and leave the rest up to software — although on more modern processors, some features the software could do are taken over by the hardware so that operating systems don't require as much customization for new CPUs.
The interrupt mechanism was invented around the time of the DEC PDP-1 processor, ~1959, and was then called Sequence Break System. Before that, processors ran mostly batch jobs and did I/O synchronously. With the introduction of the interrupt mechanism, the processor can be signaled by an external connector to take an unscheduled branch to an interrupt handler aka interrupt service routine. At every sequence point in the processors execution where it could service an interrupt, some hardware is checking that external pin to see if an interrupt is being requested. A clock is one device that regularly interrupts, I/O devices also interrupt. When an interrupt handler runs the hardware must preserve, minimally, any (register) state of the thread that it destroys in switching to the interrupt service routine, for example, the PC, since starting interrupt service routine is effected by making the CPU take an (unscheduled) branch. This could be done by having two PC registers (one main one and a shadow one for remembering the old PC at time of interrupt) or by using some prearranged memory location to store the PC of the interrupted code. Depending on the processor architecture some other shadow registers may be provided, like an alternate stack pointer. These things would make the interrupt handler easier to program (though the initial handler still would have to be written in assembly, not even C). Once the handler is running, it will save any other state for the interrupted thread, so that it can do some work using the CPU in a rather normal way, and still resume the interrupted thread later — maybe much later, after first giving some other threads a time slice.
Have a look at this answer for more information on the subject of interrupts.
See also MultiThreading on Single Core, and here Interrupts vs. Exceptions