next up previous contents
Next: 5.1.2.4 Shuttles and Traps Up: 5.1.2 Shuttles Previous: 5.1.2.2 Processor contexts

5.1.2.3 Run state

Shuttles may also wait on abstract system resources due to some reason (eg. a shuttle might want to block until a portal message be sent to it). When a shuttle goes to sleep it should call block. Later on, someone else may call unblock to unblock it.

Another effect of calling block is that (even if no event is ever raised) the shuttle will be ignored by its processor until a subsequent call to unblock is performed. The Processor where the shuttle is running checks the blocked flag and ignores the shuttle if it is set. The blocked flag means unable to run and can be used not only to block a shuttle, but also during shuttle initialization, during shuttle dismantling, etc. It should not be confused with the more abstract blocked state used in traditional process abstractions.

<Other public methods of off_Shtl. >+= (<-U) [<-D->]
// Checks/Sets if this shuttle is unable to run (blocked).
inline boolean_t is_blocked(void) const;
void block(void);
void unblock(void);

We use one of the available resource flags to maintain the blocked flag.

<off_Shtl::is_blocked implementation. >= (U->)
// Checks if this shuttle is unable to run (blocked).
inline boolean_t off_Shtl::is_blocked(void)const { return r_flags&OFF_SF_BLK; }

<off_Shtl::block and unblock implementation. >= (U->)
// Set this shuttle to unable/able to run.
void off_Shtl::block(void)   
{ 
  r_flags |= OFF_SF_BLK; 
  if (get_id()==off_Shtl::self()->get_id())
    off_Processor::self()->new_quantum();
}
void off_Shtl::unblock(void) { r_flags &= ~OFF_SF_BLK; } 

We have to defined the new flag.

<Off shuttle flag bits. >+= (U->) [<-D->]
const unsigned8_t OFF_SF_BLK = 0x20; // Unable to run?
Defines OFF_SF_BLK (links are to index).

Shuttles might be clever and donate their processor time to the shuttle which would unblock them. In that case they should use yield instead of block.

<Other public methods of off_Shtl. >+= (<-U) [<-D->]
// Yields quanta to s.
// (Or reclaims quanta when yield(get_id()).)
err_t yield(const off_shtl_id_t &s);

// Is this shuttle yieldig?
inline boolean_t is_yielding(void) const;

//Who is this shuttle yielding to?
inline const off_shtl_id_t &yields_to(void) const;

We use a flag to record the fact that we are yielding and another member to keep the identifier of the shuttle we are yielding to.

<Other private members of off_Shtl. >+= (<-U) [<-D->]
off_shtl_id_t s_yield;          // We are yielding to this guy.

It is initially set to a null value.

<Initialize other aggregate members of off_Shtl. >+= (<-U) [<-D]
s_yield(OFF_SHTL_NULL)

<off_Shtl::is_yielding implementation. >= (U->)
// Is this shuttle yieldig?
inline boolean_t off_Shtl::is_yielding(void) const 
{
 return r_flags & OFF_SF_YLD; 
}

We have to defined the new flag.

<Off shuttle flag bits. >+= (U->) [<-D->]
const unsigned8_t OFF_SF_YLD = 0x40; // Is yielding?
Defines OFF_SF_YLD (links are to index).

<off_Shtl::yields_to implementation. >= (U->)
//Who is this shuttle yielding to?
inline const off_shtl_id_t &off_Shtl::yields_to(void) const 
{ 
  return (is_yielding())? s_yield : get_id();
}

To yield the processor time we set the yield flag (or clear it when yielding to ourselves). Besides, if we are running on the yielding shuttle the processor has to be notified that the current quantum is to be yield.

<off_Shtl::yield implementation. >= (U->) [D->]
// Yields quanta to s.
// (Or reclaims quanta when yield(get_id()).)
err_t off_Shtl::yield(const off_shtl_id_t &s)
{
  if (s == get_id()) {
    r_flags &= ~OFF_SF_YLD;
  }
  else {
    r_flags |= OFF_SF_YLD;
    s_yield=s;
    if (off_Shtl::self() == this){
      return switch_to(nd.get_shtl() + s);
    }
  }
  return EOK;
}

<Off shuttle implementation dependencies. >= (U->)
#include <node/Node.h>          // for nd

The call to switch_to locates the given shuttle and performs a context switch to it. We will see later how it works.

<Other public methods of off_Shtl. >+= (<-U) [<-D->]
// Context switches to another shuttle. 
err_t switch_to(off_Shtl *s);

Another variant of yield just relinquishes the processor.

<Other public methods of off_Shtl. >+= (<-U) [<-D->]
// Yields to any other one. 
void yield(void);

<off_Shtl::yield implementation. >+= (U->) [<-D]
// Yields to any other one. 
void off_Shtl::yield(void)
{
  off_Processor::self()->new_quantum();
}

Shuttles must not run at the same time on more than one processor. To ensure it, running shuttles are flagged and such a flag is checked by every processor before switching to a new shuttle. These new methods do the job:

<Other public methods of off_Shtl. >+= (<-U) [<-D->]
// Checks/Sets if this shuttle is running.
inline boolean_t is_running(void) const;
inline void run(void);
inline void stop(void);

Again, we use another bit in the resource flags.

<off_Shtl::is_running et al. implementation. >= (U->)
// Checks/Sets if this shuttle is running.
inline boolean_t off_Shtl::is_running(void) const 
{ 
  return r_flags&OFF_SF_RUN; 
}
inline void off_Shtl::run(void) { r_flags |= OFF_SF_RUN; }
inline void off_Shtl::stop(void) { r_flags &= ~OFF_SF_RUN; }

We have to defined the new flag.

<Off shuttle flag bits. >+= (U->) [<-D]
const unsigned8_t OFF_SF_RUN = 0x80; // Is running?
Defines OFF_SF_RUN (links are to index).

When a shuttle is created, it is always blocked, not yielding and not running until explicitly unblocked.

<Initialize hardwired properties with those of proto. >+= (<-U) [<-D]
block();            // We start blocked,
yield(get_id());        //  yielding to ourselves
stop();             //  and not running. 

We must complete get_prop and set_prop now.

<case to return predefined property p value in get_prop. >+= (<-U) [<-D]
case OFF_SHTLP_RUNS:
   return (is_blocked()) ?  OFF_PRTL_NULL: get_id() ;
case OFF_SHTLP_YLDS:
   return (is_yielding())?  yields_to()  : OFF_SHTL_NULL;

<case to set predefined property p value val in set_prop. >+= (<-U) [<-D]
case OFF_SHTLP_RUNS:
   if (val == OFF_PRTL_NULL)
     block();
   else
     unblock();
   break;
case OFF_SHTLP_YLDS:
   yield(val);


next up previous contents
Next: 5.1.2.4 Shuttles and Traps Up: 5.1.2 Shuttles Previous: 5.1.2.2 Processor contexts
Francisco J. Ballesteros
1998-05-25