/* $Id: Mutex.h,v 2.3 1999/09/08 20:06:26 v2kea318 Exp $

$Log: Mutex.h,v $
 * Revision 2.3  1999/09/08  20:06:26  v2kea318
 * Added the os_do_destroy() abstract method which will determine if we are
 * to destroy the mutex.
 *
 * Revision 2.2  1999/09/07  17:05:59  v2kea318
 * The destroy method is not virtual.
 *
 * Revision 2.1  1999/09/07  17:02:02  v2kea318
 * Redesigned the class to be operating system independant, with OS
 * specific code handled by abstract methods.  A factor method is added
 * which will construct the correct mutex type for the given operating
 * system.
 *
 * Revision 1.5  1999/08/09  15:10:01  v2kea318
 * Make the initialize method private.  Since this is done automatically
 * in the constructor, there's no need for the user to do it.
 *
 * Revision 1.4  1999/08/06  21:12:37  v2kea318
 * Initialize the mutex on construction.  Add an initd flag to indicate that
 * the mutex is already init'd.
 *
 * Revision 1.3  1999/07/30  21:17:15  v2kea318
 * Use my local Pthread.h file.
 *
 * Revision 1.2  1999/07/30  21:14:50  v2kea318
 * Moved most code to a .cc file.
 *
 * Revision 1.1  1999/05/13  15:13:18  v2kea318
 * Initial revision
 *
***************************************************************************

Define an abstract class to represent a mutex.  The class destructor
will automatically release a locked mutex; the user must explicitly
destroy it.  Derived classes will implement the mutex object according
to the native representation on each operating system, e.g. PosixMutex
will implement the Mutex with the POSIX mutex.  A static factory method
is provided which will construct the appropriate derived class.

***************************************************************************/

#ifndef MLIBSPP_MUTEX_H
#define MLIBSPP_MUTEX_H

#include <string>

class Mutex {
public:
  // constructors.
  Mutex() : attrs(0) {};
  Mutex(const Mutex& m) : attrs(m.attrs) {}

  // assignment operator.
  Mutex& operator = (const Mutex& m);
  
  // destructor.
  virtual ~Mutex() { if (locked()) release(); }

protected:
  // is the mutex locked?
  bool locked() const { return attrs & lkd; }
  
public:
  // grap the mutex.
  void grab();

  // release the mutex.
  void release();

  // destroy the mutex.
  void destroy();

  // factory method.
  static Mutex* new_mutex();
  
protected:
  // OS specific code to implement the Mutex.
  virtual void os_grab() = 0;
  virtual void os_release() = 0;
  virtual void os_destroy() = 0;
  virtual bool os_do_destroy() = 0;  // do we destroy the mutex?

private:
  void mark_locked() { attrs |= lkd; };
  void mark_unlocked() { attrs &= ~lkd; }

private:
  char attrs;
  enum { lkd  = 0x01 };
};
    
#endif
