This is too broad a topic to discuss thoroughly, but here are some basics.
Primarily, two things can stop a process: an interrupt from outside the process and certain instructions, which I will call trap instructions, from inside the process. In either case, the behavior of the computer processor is largely similar:
- Whenever a process is executing, the processor is continually reading instructions from memory, executing those instructions, and maintaining information about the process, including what the address of the next instruction to execute is and a variety of registers containing data for the process.
- When either an interrupt or one of the trap instructions occurs, the processor saves the address of the next instruction and possibly some other data for the process, sets some internal processor state to be in a privileged mode, and transfers control to (starts executing instructions at) a special address.
That address may be different for interrupts and traps, and it may be different for different interrupts and different traps. Whatever it is, the operating system has placed special software at that address. It is software that “handles” the interrupt or trap (or that jumps to software that does it).
That software saves the data that is in the processor for the process that was interrupted or that trapped. It stores it in some data structures the operating system maintains for each process.
Now the process is not executing any more. The operating system is executing, and the process will not execute again unless the operating system restores the data for that process from the data structures to the processor registers and then transfers control back to the process’ instructions. This is done via some special return-from-interrupt or return-from-trap instruction that does that last bit of restoring processor state for the process, so that it can resume execution where it left off.
So, the way the operating systems blocks a process is simply not to resume execution of it. To the operating system, processes are largely data that it manipulates, and it chooses what to do with that data.
When a process attempts to read from a socket, it calls a routine that includes a trap instruction. That routine sets up some data saying that the process would like to read from a socket, and then it executes the trap instruction. The trap causes the process to stop executing and the kernel to start executing. The trap handler in the kernel looks at the data passed by the routine and sees it is a request to read a socket. It calls some other software for that. If that software sees there is no data available for the socket, it will simply leave the process suspended, and it will return to other software in the kernel.
Then the kernel generally will see if it has any other processes ready to run. If it does, it will choose one of them and start running it. If it does not, it will put the processor in a low-power mode to wait for an interrupt.
At some time in the future, some data may arrive for the socket. A network device might generate an interrupt to the processor, or some other process might call a routine to send data. In whatever way the system gets the data, when the software that manages the socket sees it has new data, it will check whether it has a process waiting for data from the socket. If it does, it will tell the kernel that process no longer needs to wait. If nothing else is blocking the process, it will be ready to run. When the kernel decides it is that process’ turn to use the processor again (or a processor, if several are available), it will resume the process as described above.
You cannot generally implement these procedures yourself in user code. They require privileged access to the hardware. Operating systems typically provide ways for processes to communicate, and you could implement things similar to this using system calls that do that communication.