next up previous contents
Next: 2.3.3.2 Kernel bureaucracy Up: 2.3.3 Synchronizing system resources Previous: 2.3.3 Synchronizing system resources

2.3.3.1 Locks

The access pattern to system objects in system call is:

1.
Call make_available() to bring any needed remote object here.
2.
Having the required objects in the local node, lock them.
3.
Perform the operation (which should now be non-blocking) and return.

We use simple read-write spin locks to lock resources.

<Off lockable objects. >= (U->)
// Objects that can be locked. 
//
class off_Lockable {
private:
  rw_spin_lock_t l_lock;         // The lock.
  <Other private methods of off_Lockable. >
public:
  off_Lockable(void) { rw_spin_lock_init(&l_lock);}

  // Is the lock set?
  inline boolean_t is_locked(void) const {
    return rw_spin_lock_locked(&l_lock); 
  }

  // How many readers?
  inline natural_t get_rd_count(void) 
  { return rw_spin_lock_get_readers(&l_lock); }
  // Any writer?
  inline boolean_t get_wr_count(void)
  { return rw_spin_lock_has_writer(&l_lock); }

  // Spin (un)lock on this. 
  inline void r_lock(void);
  inline void r_unlock(void);
  inline void w_lock(void);
  inline void w_unlock(void);

  <Other public methods of off_Lockable. >
};

Defines off_Lockable (links are to index).

The implementation is a machine dependent read-write spin lock provided by the OSKit2.8. On non SMP systems if a resource is found locked, the processor is relinquished.

<off_Lockable::lock and unlock implementation. >= (U->)
// Spin (un)lock on this. 
inline void off_Lockable::r_lock(void)  { 
  while (!rw_spin_read_try_lock(&l_lock)){
#ifdef __NOSMP__
    lock_yield();
#endif
    while(rw_spin_lock_has_writer(&l_lock)) // to get ro bus access. (cheaper)
      ;
  }
}
inline void off_Lockable::r_unlock(void){ rw_spin_read_unlock(&l_lock);}
inline void off_Lockable::w_lock(void)  { 
  while(!rw_spin_write_try_lock(&l_lock)){
#ifdef __NOSMP__
    lock_yield();
#endif 
   while(rw_spin_lock_locked(&l_lock)) // to get ro bus access. (cheaper)
      ;
  }
}
inline void off_Lockable::w_unlock(void){ rw_spin_write_unlock(&l_lock);}

<Other private methods of off_Lockable. >= (<-U)
// Yields the processor instead of spinning for a lock. 
void lock_yield(void);

<off_Lockable::lock_yield implementation. >= (U->)
// Yields the processor instead of spinning for a lock. 
void off_Lockable::lock_yield(void)
{
  off_Shtl::self()->yield();
}

<Off Lockable implementation dependencies. >= (U->)
#include <shtl/Shtl.h>          // for yield.

Another bunch of methods are provided to inhibit interrupts while the lock is held. To allow nesting, the user keeps the locking state so that it could be reset to a previous value.

<Other public methods of off_Lockable. >= (<-U)
// Spin (un)lock on this maintaning the previous interrupt-enabling state.
inline void r_lock(off_lock_state_t &state) 
     { rw_spin_read_lock_irqsave(&l_lock,state); }
inline void r_unlock(off_lock_state_t old_state) 
     { rw_spin_read_unlock_irqrestore(&l_lock,old_state);}
inline void w_lock(off_lock_state_t &state) 
     { rw_spin_write_lock_irqsave(&l_lock,state); }
inline void w_unlock(off_lock_state_t old_state) 
     { rw_spin_write_unlock_irqrestore(&l_lock,old_state);}

where

<Off lock state data type. >= (U->)
typedef register_t off_lock_state_t;

Defines off_lock_state_t (links are to index).

The implementation depends both on the \oskit{} spin lock implementation and on the interrupt inhibiting spin lock implementation (described below).

<Off Lockable dependencies. >= (U->)
#include <flux/types.h>         // for boolean_t natural_t et al.
#include <flux/machine/rw_spin_lock.h> // spin locks.

\subsubsection{Locks \cpp{} source files}

The Lockable implementation goes into files named klib/Lockable.h and klib/lockable.C. Because none of the code is ever seen outside the kernel, we include the code only when the __KERNEL__ symbol has been defined.

<Lockable.h*>=
<Read the literate code instead warning. >
#ifndef __OFF_LOCKABLE_H
#define  __OFF_LOCKABLE_H 1

<Off Lockable dependencies. >

#ifdef __KERNEL__
<Off lock state data type. >
<Off lockable objects. >

<off_Lockable::lock and unlock implementation. >
#endif // __KERNEL__

#endif // __OFF_LOCKABLE_H

<Lockable.C*>=
<Read the literate code instead warning. >

#include <klib/Lockable.h>      // Exported interface. 
<Off Lockable implementation dependencies. >

<off_Lockable::lock_yield implementation. >



Francisco J. Ballesteros
1998-05-25