QUERY REGARDING PARENT AND CHILD PROCESS - operating-system

Can a for loop be preempted in between?
suppose we have a parent and child proces;both have for loop execution
Can one process's for loop be preempted in between so that another process for loop is started?and if so, will it resume afterwards?

This depends obviously on the operating system used and many parameters, e.g. the priority of the processes. But generally a process can be interrupted after each machine instruction. This means it can be interrupted even within a single line of code in a language like C.
If a process has been interrupted, it will normally be resumed with the next machine instruction.

Related

What happens if a process preempts while executing wait and signal operations?

The main reason for using semaphores is to prevent the producer-consumer problem.
But I wonder what would happen if a process gets preempted while executing wait operation and another process also executes wait operation.
Let's take
S value as 1.
What if while executing Wait(), S value is loaded into register reg as 1.
now S value is decremented.
Now reg is 0.
And now if another process wants to execute the wait to access the critical section
it considers S value as 1.
loads reg as 1.
and again decrements.
reg is 0.
Now both processes enter the critical section.
The code for the wait function is
Down(Semaphore S){
S.value=S.value-1;
if(S.value<0)
{
put PCB in suspended list;
sleep;
}
else
return;
}
The code for the signal function is
Signal(Semaphore S){
S.value=S.value+1;
if(S.value<=0)
{
Select a process from suspendend list;
wakeup();
}
}
isn't semaphore variable also a critical section variable as it is common for two or many processes? how can we prevent such race conditions?
You are correct that if the code for semaphore operations is as given above, there is indeed a risk that something bad could happen if a thread gets preempted in the middle of implementing an operation. The reason that this isn’t a problem in practice is that the actual implementations of semaphore operations are a bit more involved than what you gave.
Some implementations of semaphores, for example, will begin by physically disabling the interrupt mechanism on the machine to ensure that the current thread cannot possibly be preempted during execution of the operation. Others are layered on top of other synchronization primitives that use similar techniques to prevent preemption. Others might use other mechanisms besides disabling interrupts that have the same effect of ensuring that the process can’t be halted midway in the middle of performing the needed synchronization, or at least, ensuring that any places where preemption can occur are well-marked and properly thought through.
Hope this helps!

Where does the scheduler run?

Having just finished a book on comp. architecture, I find myself not completely clarified on where the scheduler is running.
What I'm looking to have clarified is where the scheduler is running - does it have it's own core assigned to run that and nothing else, or is the "scheduler" in fact just a more ambiguous algorithm, that it implemented in every thread being executed - ex. upon preemption of thread, a swithToFrom() command is run?
I don't need specifics according to windows x/linux x/mac os x, just in general.
No the scheduler is not run in it's own core. In fact multi-threading was common long before multi-core CPUs were common.
The best way to see how scheduler code interacts with thread code is to start with a simple, cooperative, single-core example.
Suppose thread A is running and thread B is waiting on an event. thread A posts that event, which causes thread B to become runnable. The event logic has to call the scheduler, and, for the purposes of this example, we assume that it decides to switch to thread B. At this point in time the call stack will look something like this:
thread_A_main()
post_event(...)
scheduler(...)
switch_threads(threadA, threadB)
switch_threads will save the CPU state on the stack, save thread A's stack pointer, and load the CPU stack pointer with the value of thread B's stack pointer. It will then load the rest of the CPU state from the stack, where the stack is now stack B. At this point, the call stack has become
thread_B_main()
wait_on_event(...)
scheduler(...)
switch_threads(threadB, threadC)
In other words, thread B has now woken up in the state it was in when it previously yielded control to thread C. When switch_threads() returns, it returns control to thread B.
These kind of manipulations of the stack pointer usually require some hand-coded assembler.
Add Interrupts
Thread B is running and a timer interrupts occurs. The call stack is now
thread_B_main()
foo() //something thread B was up to
interrupt_shell
timer_isr()
interrupt_shell is a special function. It is not called. It is preemptively invoked by the hardware. foo() did not call interrupt_shell, so when interrupt_shell returns control to foo(), it must restore the CPU state exactly. This is different from a normal function, which returns leaving the CPU state according to calling conventions. Since interrupt_shell follows different rules to those stated by the calling conventions, it too must be written in assembler.
The main job of interrupt_shell is to identify the source of the interrupt and call the appropriate interrupt service routine (ISR) which in this case is timer_isr(), then control is returned to the running thread.
Add preemptive thread switches
Suppose the timer_isr() decides that it's time for a time-slice. Thread D is to be given some CPU time
thread_B_main()
foo() //something thread B was up to
interrupt_shell
timer_isr()
scheduler()
Now, scheduler() can't call switch_threads() at this point because we are in interrupt context. However, it can be called soon after, usually as the last thing interrupt_shell does. This leaves the thread B stack saved in this state
thread_B_main()
foo() //something thread B was up to
interrupt_shell
switch_threads(threadB, threadD)
Add Deferred Service Routines
Some OSses do not allow you to do complex logic like scheduling from within ISRs. One solution is to use a deferred service routine (DSR) which runs as higher priority than threads but lower than interrupts. These are used so that while scheduler() still needs to be protected from being preempted by DSRs, ISRs can be executed without a problem. This reduces the number of places a kernel has to mask (switch off) interrupts to keep it's logic consistent.
I once ported some software from an OS that had DSRs to one that didn't. The simple solution to this was to create a "DSR thread" that ran higher priority than all other threads. The "DSR thread" simply replaces the DSR dispatcher that the other OS used.
Add traps
You may have observed in the examples I've given so far, we are calling the scheduler from both thread and interrupt contexts. There are two ways in and two ways out. It looks a bit weird but it does work. However, moving forward, we may want to isolate our thread code from our Kernel code, and we do this with traps. Here is the event posting redone with traps
thread_A_main()
post_event(...)
user_space_scheduler(...)
trap()
interrupt_shell
kernel_space_scheduler(...)
switch_threads(threadA, threadB)
A trap causes an interrupt or an interrupt-like event. On the ARM CPU they are known as "software interrupts" and this is a good description.
Now all calls to switch_threads() begin and end in interrupt context, which, incidentally usually happens in a special CPU mode. This is a step towards privilege separation.
As you can see, scheduling wasn't built in a day. You could go on:
Add a memory mapper
Add processes
Add multiple Cores
Add hyperthreading
Add virtualization
Happy reading!
Each core is separately running the kernel, and cooperates with other cores by reading / writing shared memory. One of the shared data structures maintained by the kernel is the list of tasks that are ready to run, and are just waiting for a timeslice to run in.
The kernel's process / thread scheduler runs on the core that needs to figure out what to do next. It's a distributed algorithm with no single decision-making thread.
Scheduling doesn't work by figuring out what task should run on which other CPU. It works by figuring out what this CPU should do now, based on which tasks are ready to run. This happens whenever a thread uses up its timeslice, or makes a system call that blocks. In Linux, even the kernel itself is pre-emptible, so a high-priority task can be run even in the middle of a system call that takes a lot of CPU time to handle. (e.g. checking the permissions on all the parent directories in an open("/a/b/c/d/e/f/g/h/file", ...), if they're hot in VFS cache so it doesn't block, just uses a lot of CPU time).
I'm not sure if this is done by having the directory-walking loop in (a function called by) open() "manually" call schedule() to see if the current thread should be pre-empted or not. Or maybe just that tasks waking up will have set some kind of hardware time to fire an interrupt, and the kernel in general is pre-emptible if compiled with CONFIG_PREEMPT.
There's an inter-processor interrupt mechanism to ask another core to schedule something on itself, so the above description is an over-simplification. (e.g. for Linux run_on to support RCU sync points, and TLB shootdowns when a thread on another core uses munmap). But it's true that there isn't one "master control program"; generally the kernel on each core decides what that core should be running. (By running the same schedule() function on a shared data-structure of tasks that are ready to run.)
The scheduler's decision-making is not always as simple as taking the task at the front of the queue: a good scheduler will try to avoid bouncing a thread from one core to another (because its data will be hot in the caches of the core it was last running on, if that was recent). So to avoid cache thrashing, a scheduler algorithm might choose not to run a ready task on the current core if it was just running on a different core, instead leaving it for that other core to get to later. That way a brief interrupt-handler or blocking system call wouldn't result in a CPU migration.
This is especially important in a NUMA system, where running on the "wrong" core will be slower long-term, even once the caches populate.
There are three types of general schedulers:
Job scheduler also known as the Long term scheduler.
Short term scheduler also known as the CPU scheduler.
Medium term scheduler, mostly used to swap jobs so there can be non-blocking calls. This is usually for not having too many I/O jobs or to little.
In an operating systems book it shows a nice automata of the states these schedulers go to and from. Job scheduler puts things from job queue to ready queue, the CPU scheduler takes things from ready queue to running state. The algorithm is just like any other software, it must be run on a cpu/core, it is most likely probably part of the kernel somewhere.
It doesn't make sense the scheduler can be preempted. The jobs inside the queue can be preempted when running, for I/O, etc. No the kernel does not have to schedule itself to allocate the task, it just gets cpu time without scheduling itself. And yes, most likely the data is in probably in ram, not sure if it is worth storing in the cpu cache.

Systemverilog spawned processes execute after parent executes blocking statement

This paper titled Systemverilog Event Regions Race Avoidance & Guidelines submits an example that contradicts the Systemverilog IEEE 1800-2012 LRM:
...when forking background processes, it is often very useful to allow
newly created subprocesses a chance to start executing before
continuing the execution of the parent process. This is easily
accomplished with the following code:
program test;
initial begin
fork
process1;
process2;
process3;
join_none
#0;
// parent process continue
end
endprogram
However IEEE Systemverilog LRM IEEE 1800-2012 states:
"join_none. The parent process continues to execute concurrently with
all the processes spawned by the fork. The spawned processes do not
start executing until the parent thread executes a blocking statement
or terminates."
Which is it?
There is no contradiction here. Look at it this way:
join_none. The parent process continues to execute concurrently with all the processes spawned by the fork. The spawned processes do not start executing until the parent thread executes a blocking statement or terminates.
We are being told that the forked processes do not start immediately. They wait for the parent process, which spawned them, to yield (by either terminating or by encountering a blocking statement). The fork statement basically schedules the processes. The scheduler gets a chance to start executing them only when the already running thread (parent process) yields.
The first example you quoted, suggests that you give a chance to the spawned processes to start executing. To do so it asks you to introduce a #0 statement. When the parent process encounters #0, a blocking statement, it yields. The spawned processes therefor get a chance to start executing.

OS: does the process scheduler runs in separate process

I have few doubts about how operating system works.
Scheduler: Does the scheduler runs in a separate process(like any other process). What exactly happens at the time of swapping in new process(i know the processor registers and memory tables are updated, my question is how they are updated. Can we write a program to update the registers(sc, pc) to point to a different process).
The process schedule could feasibly run in a separate process, but such a design would be very inefficient since you would have to swap from one process to the scheduling process (which would then have to make several system calls to the kernel) and then back to the new process, as opposed to just placing the scheduler in the kernel where you will not need system calls nor need to swap contexts more than once. Therefore, the scheduler is generally in the exclusive realm of the kernel.
Here are the steps that occur:
The scheduler determines which process will run in the next time slot (through various different algorithms).
The scheduler tells the Memory Managing Unit (MMU) to use the page table for the next process to run (this is done by setting a register to point to the table).
The scheduler programs the Programmable Interrupt Timer (PIT) to generate an interrupt after N clock cycles.
The scheduler restores the state of the registers from when the process was last running (or sets them to default values for new processes)
The scheduler jumps to the address of the last instruction that was not executed in the process.
After N clock cycles, an interrupt occurs and the operating system recognizes it as caused by the PIT, which is registered to be handled by the scheduler.
The scheduler saves the state of the registers (including stack pointer, etc) and grabs the program counter of where the interrupt occured (and saves it as the address to jump to next time around) and then goes back to step 1.
This is just one example of how it can be done, and many of the low level details are architecture specific. Essentially all the registers (the program state) can be saved to any place in RAM (say a linked list of structures that represent processes each having space for the registers, etc) and the virtual address space (defined by page tables) can be arbitrarily swapped out.
So essentially your question:
"Can we write a program to update the registers to point to a different process?"
is simply stated, yet the answer is correct. We sure can.

how dispatcher works?

I have recently started my OS course. As far as i know the work of dispatcher is to save the context of current process and load context of process to be run next. But how does it do that? When a process is preempted then as soon as dispatcher will be loaded and executed ( as it is also a program ) the context of previous process in registers, PSW etc will be lost. How is it going to save the context before loading itself ?
The simple answer is that modern processors offer architectural extensions providing for several banks of registers that can be swapped in hardware, so up to X tasks get to retain their full set of registers.
The more complex answer is that the dispatcher, when triggered by an interrupt, receives the full register set of the program that was running at the time of interrupt (with the exception of the program counter, which is presumably propagated through a mutually-agreed-upon 'volatile' register or some such). Thus, the dispatcher must be carefully written to store the current state of register banks as its first operation upon being triggered. In short, the dispatcher itself has no immediate context and thus doesn't suffer from the same problem.
Here is an attempt at a simple description of what goes on during the dispatcher call:
The program that currently has context is running on the processor. Registers, program counter, flags, stack base, etc are all appropriate for this program; with the possible exception of an operating-system-native "reserved register" or some such, nothing about the program knows anything about the dispatcher.
The timed interrupt for dispatcher function is triggered. The only thing that happens at this point (in the vanilla architecture case) is that the program counter jumps immediately to whatever the PC address in the BIOS interrupt is listed as. This begins execution of the dispatcher's "dispatch" subroutine; everything else is left untouched, so the dispatcher sees the registers, stack, etc of the program that was previously executing.
The dispatcher (like all programs) has a set of instructions that operate on the current register set. These instructions are written in such a way that they know that the previously executing application has left all of its state behind. The first few instructions in the dispatcher will store this state in memory somewhere.
The dispatcher determines what the next program to have the cpu should be, takes all of its previously stored state and fills registers with it.
The dispatcher jumps to the appropriate PC counter as listed in the task that now has its full context established on the cpu.
To (over)simplify in summary; the dispatcher doesn't need registers, all it does is write the current cpu state to a predetermined memory location, load another processes' cpu state from a predetermined memory location, and jumps to where that process left off.
Does that make it any clearer?
It doesn't generally get loaded in such a way that you lose the information on the current process.
Often, it's an interrupt that happens in the context of the current process.
So the dispatcher (or scheduler) can save all relevant information in a task control block of some sort before loading up that information for the next process.
This includes the register contents, stack pointer and so on.
It's worth noting that the context of the next process includes its state of being in the dispatcher interrupt itself so that, when it returns from the interrupt, it's to a totally different process.
Dispatcher module gives control of the CPU to the process selected by the short-term scheduler; this involves:
switching context,
switching to user mode,
jumping to the proper location in the user program to restart that program
The operating system's principal responsibility is controlling the execution of processes. This includes determining the pattern for execution and allocating resources to the processes.
A process may be in one of the two states :
Running or
Not Running
When the OS creates a new process, it creates a process control block for the process and enters that process into the system into the Not Running state. The process exists is known to OS and is waiting for an opportunity to execute.
From time to time, the currently running processes will be interrupted and the dispatcher portion of the OS will select some other processes to run.
During execution when the process is devoid of resources, it gets blocked. Provided those resources it re-enters the ready state and then into running state. This transition from ready to running state is done by dispatcher. Dispatcher dispatches the process.