Buffer heads to track page mappings -> block num
[akaros.git] / Documentation / processes.txt
index 47a7e90..42f620a 100644 (file)
@@ -170,9 +170,11 @@ TLS/TCB descriptor and the floating point/silly state (if applicable) in the
 user-thread control block, and do whatever is needed to signal vcore0 to run the
 _S context when it starts up.  One way would be to mark vcore0's "active thread"
 variable to point to the _S thread.  When vcore0 starts up at
 user-thread control block, and do whatever is needed to signal vcore0 to run the
 _S context when it starts up.  One way would be to mark vcore0's "active thread"
 variable to point to the _S thread.  When vcore0 starts up at
-_start/hart_entry() (like all vcores), it will see a thread was running there
-and restart it.  This will need to have some special casing for the FP/silly
-state.
+_start/vcore_entry() (like all vcores), it will see a thread was running there
+and restart it.  The kernel will migrate the _S thread's silly state (FP) to the
+new pcore, so that it looks like the process was simply running the _S thread
+and got notified.  Odds are, it will want to just restart that thread, but the
+kernel won't assume that (hence the notification).
 
 In general, all cores (and all subsequently allocated cores) start at the elf
 entry point, with vcoreid in eax or a suitable arch-specific manner.  There is
 
 In general, all cores (and all subsequently allocated cores) start at the elf
 entry point, with vcoreid in eax or a suitable arch-specific manner.  There is
@@ -180,13 +182,13 @@ also a syscall to get the vcoreid, but this will save an extra trap at vcore
 start time.
 
 Future proc_runs(), like from RUNNABLE_M to RUNNING_M start all cores at the
 start time.
 
 Future proc_runs(), like from RUNNABLE_M to RUNNING_M start all cores at the
-entry point, including vcore0.  The saving of a _S context to vcore0's notif_tf only happens on
-the transition from _S to _M (which the process needs to be aware of for a
-variety of reasons).  This also means that userspace needs to handle vcore0
-coming up at the entry point again (and not starting the program over).  This is
-currently done in sysdeps-ros/start.c, via the static variable init.  Note there
-are some tricky things involving dynamically linked programs, but it all works
-currently.
+entry point, including vcore0.  The saving of a _S context to vcore0's notif_tf
+only happens on the transition from _S to _M (which the process needs to be
+aware of for a variety of reasons).  This also means that userspace needs to
+handle vcore0 coming up at the entry point again (and not starting the program
+over).  This is currently done in sysdeps-ros/start.c, via the static variable
+init.  Note there are some tricky things involving dynamically linked programs,
+but it all works currently.
 
 When coming in to the entry point, whether as the result of a startcore or a
 notification, the kernel will set the stack pointer to whatever is requested
 
 When coming in to the entry point, whether as the result of a startcore or a
 notification, the kernel will set the stack pointer to whatever is requested
@@ -219,29 +221,40 @@ from _S to _M: at the entry point.
 
 2.4.4: Yielding
 --------------
 
 2.4.4: Yielding
 --------------
-This will get revised soon, to account for different types of yields.
-
-Yielding gives up a core.  In _S mode, it will transition from RUNNING_S to
-RUNNABLE_S.  The context is saved in env_tf.  A yield will *not* transition
-from _M to _S.
-
-In _M mode, this yields the calling core.  The kernel will rip it out of your
-vcore list.  A process can yield its cores in any order.  The kernel will
-"fill in the holes of the vcoremap" when for any future newcores (e.g., proc A
-has 4 vcores, yields vcore2, and then asks for another vcore.  The new one
-will be vcore2).
-
-When you are in _M and yield your last core, it is an m_yield.  This
-completely suspends all cores, like a voluntary preemption.  When the process
-is run again, all cores will come up at the entry point (including vcore0 and
-the calling core).  This isn't implemented yet, and will wait on some work
-with preemption.
-
-We also need a type of yield (or a flag) that says the process is just giving
-up the core temporarily, but actually wants the core and does not want
-resource requests to be readjusted.  For example, in the event of a preemption
+sys_yield()/proc_yield() will give up the calling core, and may or may not
+adjust the desired number of cores, subject to its parameters.  Yield is
+performing two tasks, both of which result in giving up the core.  One is for
+not wanting the core anymore.  The other is in response to a preemption.  Yield
+may not be called remotely (ARSC).
+
+In _S mode, it will transition from RUNNING_S to RUNNABLE_S.  The context is
+saved in env_tf.
+
+In _M mode, this yields the calling core.  A yield will *not* transition from _M
+to _S.  The kernel will rip it out of your vcore list.  A process can yield its
+cores in any order.  The kernel will "fill in the holes of the vcoremap" for any
+future new cores requested (e.g., proc A has 4 vcores, yields vcore2, and then
+asks for another vcore.  The new one will be vcore2).  When any core starts in
+_M mode, even after a yield, it will come back at the vcore_entry()/_start point.
+
+Yield will normally adjust your desired amount of vcores to the amount after the
+calling core is taken.  This is the way a process gives its cores back.
+
+Yield can also be used to say the process is just giving up the core in response
+to a pending preemption, but actually wants the core and does not want resource
+requests to be readjusted.  For example, in the event of a preemption
 notification, a process may yield (ought to!) so that the kernel does not need
 notification, a process may yield (ought to!) so that the kernel does not need
-to waste effort with full preemption.
+to waste effort with full preemption.  This is done by passing in a bool
+(being_nice), which signals the kernel that it is in response to a preemption.
+The kernel will not readjust the amt_wanted, and if there is no preemption
+pending, the kernel will ignore the yield.
+
+There may be an m_yield(), which will yield all or some of the cores of an MPC,
+remotely.  This is discussed farther down a bit.  It's not clear what exactly
+it's purpose would be.
+
+We also haven't addressed other reasons to yield, or more specifically to wait,
+such as for an interrupt or an event of some sort.
 
 2.4.5: Others
 --------------
 
 2.4.5: Others
 --------------
@@ -447,6 +460,22 @@ and then execute a return.  If an IPI arrives before the "function return", then
 when that context gets restarted, it will run the "return" with the appropriate
 value on the stack still.
 
 when that context gets restarted, it will run the "return" with the appropriate
 value on the stack still.
 
+There is a further complication.  The kernel can send an IPI that the process
+wanted, but the vcore did not get truly interrupted since its notifs were
+disabled.  There is a race between checking the queue/bitmask and then enabling
+notifications.  The way we deal with it is that the kernel posts the
+message/bit, then sets notif_pending.  Then it sends the IPI, which may or may
+not be received (based on notif_enabled).  (Actually, the kernel only ought to
+send the IPI if notif_pending was 0 (atomically) and notif_enabled is 1).  When
+leaving the transition stack, userspace should clear the notif_pending, then
+check the queue do whatever, and then try to pop the tf.  When popping the tf,
+after enabling notifications, check notif_pending.  If it is still clear, return
+without fear of missing a notif.  If it is not clear, it needs to manually
+notify itself (sys_self_notify) so that it can process the notification that it
+missed and for which it wanted to receive an IPI.  Before it does this, it needs
+to clear notif_pending, so the kernel will send it an IPI.  These last parts are
+handled in pop_ros_tf().
+
 4.3: Preemption Specifics
 -------------------------------
 When a vcore is preempted, the kernel takes whatever context was running (which
 4.3: Preemption Specifics
 -------------------------------
 When a vcore is preempted, the kernel takes whatever context was running (which
@@ -461,15 +490,16 @@ trapframe.  The reason is that a preemption can come in at any time (such as
 right after returning from a preemption).
 
 To maintain this invariant, when the kernel starts a vcore, it will run the
 right after returning from a preemption).
 
 To maintain this invariant, when the kernel starts a vcore, it will run the
-context that is in the preempt trapframe if the "preempt_tf_sorted" (name will
-change) flag is not set.  A process needs to be careful of a race here.  If
-they are trying to deal with a preempt trapframe (must be from another vcore,
-btw), the kernel could start to run that trapframe (in case it is granting a
-core request / proc_startcore()ing).  When the kernel prepares to use the
-trapframe (which it will do regardless of userspace activities), it will up
-the flag/counter.  If the process notices a change in that flag, it ought to
-abort its operation.  It can up the counter on its own when it no longer wants
-the kernel to run that context (this means it can get clobbered).
+context that is in the preempt trapframe if the "preempt_tf_valid" seq_ctr is
+not set.  A process needs to be careful of a race here.  If they are trying to
+deal with a preempt trapframe (must be from another vcore, btw), the kernel
+could start to run that trapframe (in case it is granting a core request /
+proc_startcore()ing).  When the kernel prepares to use the trapframe (which it
+will do regardless of userspace activities), it will up the seq_ctr.  We use a
+seq_ctr (mostly just a counter) to avoid ABA-related issues.  If the process
+notices a change in that flag, it ought to abort its operation.  It can up the
+counter on its own when it no longer wants the kernel to run that context (this
+means the preempt_tf can get clobbered).
 
 4.4: Other trickiness
 -------------------------------
 
 4.4: Other trickiness
 -------------------------------
@@ -526,17 +556,17 @@ hardware interrupts (on x86, at least).
 There will be cases where the trapframe in the preempt_tf slot is actually a
 notification handler, which was running on the transition stack of that
 particular vcore.  Userspace needs to be careful about restarting contexts
 There will be cases where the trapframe in the preempt_tf slot is actually a
 notification handler, which was running on the transition stack of that
 particular vcore.  Userspace needs to be careful about restarting contexts
-that were on those cores.  They can tell by examining the stack pointer to see
-if it was on a transition stack.  Alternatively, if notifications are masked,
-it is also likely they in a notification handler.  The real concern is the
-transition stack.  If a vcore is processing on the transition stack of another
-vcore, there is a risk that the vcore comes back up and starts clobbering the
-transition stack.
-
-To avoid this, userspace should allocate a new transition stack and switch the
+that were on those cores on different cores.  They can tell by examining the
+stack pointer to see if it was on a transition stack.  Alternatively, if
+notifications are masked, it is also likely they in a notification handler.  The
+real concern is the transition stack.  If a vcore is processing on the
+transition stack of another vcore, there is a risk that the vcore comes back up
+and starts clobbering the transition stack.
+
+To avoid this, userspace could allocate a new transition stack and switch the
 target vcore to use that new stack (in procdata).  The only time (for now)
 that the kernel cares about a transition stack is when it is popping a tf on a
 target vcore to use that new stack (in procdata).  The only time (for now)
 that the kernel cares about a transition stack is when it is popping a tf on a
-new or freshly notified vcore.
+new or freshly notified vcore.  Something similar will need to be done with TLS.
 
 This all should be a rare occurance, since the vcore should see the
 preempt_pending when it starts its notification and yield, instead of being
 
 This all should be a rare occurance, since the vcore should see the
 preempt_pending when it starts its notification and yield, instead of being
@@ -549,6 +579,10 @@ also may need only one trapframe slot).  Userspace probably cannot guarantee
 that, so we'll have to deal with it.  Avoiding the deadlock on a spinlock is
 much more reasonable (and we can provide the locking function).
 
 that, so we'll have to deal with it.  Avoiding the deadlock on a spinlock is
 much more reasonable (and we can provide the locking function).
 
+Another thing to keep in mind is that userspace probably won't want to restart a
+notification handler on a different core.  It's conceivable that they want to
+take a regular user thread and context and restart it, not a transition context.
+
 4.4.4: Userspace Yield Races
 -------------------------------
 Imagine a vcore realizes it is getting preempted soon, so it starts to yield.
 4.4.4: Userspace Yield Races
 -------------------------------
 Imagine a vcore realizes it is getting preempted soon, so it starts to yield.
@@ -563,9 +597,9 @@ yield and simply return to userspace.
 4.4.5: Userspace m_yield
 -------------------------------
 There are a variety of ways to implement an m_yield (yield the entire MCP).
 4.4.5: Userspace m_yield
 -------------------------------
 There are a variety of ways to implement an m_yield (yield the entire MCP).
-We could have a "no niceness" yield - just immediately preempt, but there is a danger of the
-locking business.  We could do the usual delay game, though if userspace is
-requesting its yield, arguably we don't need to give warning. 
+We could have a "no niceness" yield - just immediately preempt, but there is a
+danger of the locking business.  We could do the usual delay game, though if
+userspace is requesting its yield, arguably we don't need to give warning. 
 
 Another approach would be to not have an explicit m_yield call.  Instead, we
 can provide a notify_all call, where the notification sent to every vcore is
 
 Another approach would be to not have an explicit m_yield call.  Instead, we
 can provide a notify_all call, where the notification sent to every vcore is