A system call is basically a function in the OS code which processes invoke using a special instruction. In this instruction, you specify a system call number, and the CPU looks for the corresponding address in the system call table. Because the OS controls the contents of this table, it determines the locations in its code where processes can jump to. (You wouldn’t want processes to be able to jump to just any address in the OS code.)
Because processes can’t directly talk to the hardware, they need the OS to do it for them, and so they make requests to the OS via system calls.
In a process, the virtual addresses used for the code and call stack are automatically mapped to RAM by the OS, but addresses used for heap memory must be explicitly requested with system calls. When no longer used, a chunk of allocated memory should be “freed” with another system call, thereby allowing the OS to reallocate that memory to your process in a later system call. Failure to free memory can result in requests for more memory eventually being rejected, especially in a long running process.
As a process runs, it transitions back and forth between the state of running—actually executing on a CPU—and waiting to be scheduled. A process may also be put into a blocked state, meaning it is waiting to be unblocked by some circumstance in the OS, at which point it will go back to waiting.
The most common reason a process gets blocked is because it is waiting on I/O. For instance, a process usually blocks when invoking a system call to read a file off a hard drive. This makes sense because, until the data has been read into memory, the process can’t continue, and this may take a long time in CPU terms, time which would be better spent letting other processes use the CPU. When the data is ready, the OS will unblock the process, thus allowing it to continue.
