No event will ever occur while a process is running!
When a process is woken by an event, it runs to completion ("end process") or an explicit "wait" statement, and goes to sleep. This takes, notionally, ZERO time. Which means that if you have loops in your process, they are effectively unrolled completely, and when you synthesise, you will generate enough hardware to run EVERY iteration in parallel. Also, any procedures, functions etc, take zero time - unless they contained an explicit "wait" statement (in which case the process suspends at the "wait", as if the procedure had been inlined).
Throughout this process, all signals have the value they originally had when the process woke up, and any signal assignments are stored up, to happen later. (Variables update immediately; later statements in the process see the new value).
When the process suspends (at "wait" or "end process"), nothing happens until ALL the other processes also suspend. (But remember they all take zero time!). If a process suspends at "end process" it will restart from the beginning when its sensitivity list wakes it up. If it suspends at an explicit "wait", that "wait" will specify an event or future time, which will restart it after the "Wait". (NOTES: 1 : do not mix the sensitivity list and Wait styles in the same process! 2: Wait Until some event is synthesisable (though some tools may object) ; Wait for some time is simulation only)
THEN all the signal assignments are performed. Since all processes are asleep, this eliminates all race conditions and timing hazards. Some of these assignments (like '1' to a clock) will cause events to be scheduled on processes sensitive to them.
After all the signal assignments are done, the time steps forward one infinitely short tick (called a delta cycle), and then all the processes with scheduled events are woken.
This continues until a delta cycle occurs in which NO new events are scheduled, and finally the simulation can advance by a real time step.
Thus
process(clk)
begin
if rising_edge(clk) then
A <= B;
B <= A;
end if;
end process;
is hazard-free in VHDL.
If you ever need to use Verilog, be aware that some of this happens differently there, and you cannot rely on the same level of predictability in simulation results.
In synthesis, of course, we generate hardware which will take some real time to execute this process. However, the synthesis and back-end tools (place and route) guarantee to either obey this model faithfully, or fail and report why they failed. For example, they will add up all the real delays and verify that the sum is less than your specified clock period. (Unless you have set the clock speed too high!).
So the upshot is, as long as the tools report success (and you are setting the timing constraints like clock speed correctly) you can pretend the above "zero time" model is true, and the real hardware behaviour will match the simulation. Guaranteed, barring tool bugs!