Main Page   Class Hierarchy   Compound List   File List   Header Files   Compound Members   File Members  

vrpn_Mutex.h

This is the verbatim text of the vrpn_Mutex.h include file.
#ifndef VRPN_MUTEX_H
#define VRPN_MUTEX_H


#include "vrpn_Shared.h"  // for timeval and timeval manipulation functions
#include "vrpn_Connection.h"  // for vrpn_HANDLERPARAM


// Every time a Mutex_Remote connects to a Mutex_Server, the server assigns
// a unique ID to the remote.
// HACK - because vrpn doesn't let us unicast within a multicast (multiple-
// connection server) (in any clean way), or identify at a MC server which
// connection a message came in over, this code is fragile - it depends
// on the fact that vrpn_Connection only allows one connection to be made
// before triggering the got_connection callback.  If connections were somehow
// batched, or we multithreaded vrpn_Connection, this would break.

class vrpn_Mutex {

  public:

    vrpn_Mutex (const char * name, vrpn_Connection * = NULL);
    virtual ~vrpn_Mutex (void) = 0;

    void mainloop (void);

  protected:

    vrpn_Connection * d_connection;

    vrpn_int32 d_myId;
    vrpn_int32 d_requestIndex_type;
    vrpn_int32 d_requestMutex_type;
    vrpn_int32 d_release_type;
    vrpn_int32 d_releaseNotification_type;
    vrpn_int32 d_grantRequest_type;
    vrpn_int32 d_denyRequest_type;
    vrpn_int32 d_initialize_type;

    void sendRequest (vrpn_int32 index);
    void sendRelease (void);
    void sendReleaseNotification (void);
    void sendGrantRequest (vrpn_int32 index);
    void sendDenyRequest (vrpn_int32 index);

};

class vrpn_Mutex_Server : public vrpn_Mutex {

  public:

    vrpn_Mutex_Server (const char * name, vrpn_Connection * = NULL);
    virtual ~vrpn_Mutex_Server (void);

  protected:

    enum state { HELD, FREE };

    state d_state;

    vrpn_int32 d_remoteIndex;

    static int handle_requestIndex (void *, vrpn_HANDLERPARAM);
    static int handle_requestMutex (void *, vrpn_HANDLERPARAM);
    static int handle_release (void *, vrpn_HANDLERPARAM);

    static int handle_gotConnection (void *, vrpn_HANDLERPARAM);
    static int handle_dropLastConnection (void *, vrpn_HANDLERPARAM);
};

class vrpn_Mutex_Remote : public vrpn_Mutex {

  public:

    vrpn_Mutex_Remote (const char * name, vrpn_Connection * = NULL);
    virtual ~vrpn_Mutex_Remote (void);


    // ACCESSORS


    vrpn_bool isAvailable (void) const;
    vrpn_bool isHeldLocally (void) const;
    vrpn_bool isHeldRemotely (void) const;


    // MANIPULATORS


    void request (void);

    void release (void);

    void addRequestGrantedCallback (void * userdata, int (*) (void *));
    void addRequestDeniedCallback (void * userdata, int (*) (void *));
    void addTakeCallback (void * userdata, int (*) (void *));
    void addReleaseCallback (void * userdata, int (*) (void *));

  protected:

    void requestIndex (void);

    enum state { OURS, REQUESTING, AVAILABLE, HELD_REMOTELY};

    state d_state;
    vrpn_int32 d_myIndex;
    vrpn_bool d_requestBeforeInit;

    static int handle_grantRequest (void *, vrpn_HANDLERPARAM);
    static int handle_denyRequest (void *, vrpn_HANDLERPARAM);
    static int handle_releaseNotification (void *, vrpn_HANDLERPARAM);

    static int handle_initialize (void *, vrpn_HANDLERPARAM);

    static int handle_gotConnection (void *, vrpn_HANDLERPARAM);

    void triggerGrantCallbacks (void);
    void triggerDenyCallbacks (void);
    void triggerTakeCallbacks (void);
    void triggerReleaseCallbacks (void);

    struct mutexCallback {
      int (* f) (void *);
      void * userdata;
      mutexCallback * next;
    };

    mutexCallback * d_reqGrantedCB;
    mutexCallback * d_reqDeniedCB;
    mutexCallback * d_takeCB;
    mutexCallback * d_releaseCB;
};







// Known bugs -

//   The constructor that takes a Connection as an argument will incorrectly
// identify its IP address as the machine's default rather than the address
// used by the Connection.  This should not cause any errors in the protocol,
// but will bias the tiebreaking algorithm.  The same constructor will use
// the wrong port number;  without this information the tiebreaking algorithm
// fails.  Oops.  Use only one mutex per Connection for now.

// Possible bugs -

//   If on startup somebody else is holding the mutex we'll think it's
// available.  However, if we request it they'll deny it to us and
// we won't break.
//   If sites don't execute the same set of addPeer() commands, they may
// implicitly partition the network and not get true mutual exclusion.
// This could be fixed by sending an addPeer message.
//   If sites execute addPeer() while the lock is held, or being requested,
// we'll break.
//   - To fix:  send messages, but defer all executions of addPeer until the
// lock is released.  If we want to be really careful here, on getting an
// addPeer message when we think the lock is available we should request
// the lock and then (if we get it) release it immediately, without
// triggering any user callbacks.  Sounds tough to code?

// Handling more than 2 sites in a mutex requires multiconnection servers.
// It's been tested with 1-3 sites, and works fine.

// This is an O(n^2) network traffic implementation;
// for details (and how to fix if it ever becomes a problem),
// see the implementation notes in vrpn_Mutex.C.



class vrpn_PeerMutex {

  public:

    vrpn_PeerMutex (const char * name, int port,
                    const char * NICaddress = NULL);

    ~vrpn_PeerMutex (void);


    // ACCESSORS


    vrpn_bool isAvailable (void) const;
    vrpn_bool isHeldLocally (void) const;
    vrpn_bool isHeldRemotely (void) const;

    int numPeers (void) const;


    // MANIPULATORS


    void mainloop (void);

    void request (void);

    void release (void);


    void addPeer (const char * stationName);


    void addRequestGrantedCallback (void * userdata, int (*) (void *));
    void addRequestDeniedCallback (void * userdata, int (*) (void *));
    void addTakeCallback (void * userdata, int (*) (void *));
    void addReleaseCallback (void * userdata, int (*) (void *));



  protected:


    enum state { OURS, REQUESTING, AVAILABLE, HELD_REMOTELY};

    char * d_mutexName;

    state d_state;

    int d_numPeersGrantingLock;

    vrpn_Connection * d_server;
    vrpn_Connection ** d_peer;

    int d_numPeers;
    int d_numConnectionsAllocated;

    vrpn_uint32 d_myIP;
    vrpn_uint32 d_myPort;
    vrpn_uint32 d_holderIP;
    vrpn_int32 d_holderPort;

    vrpn_int32 d_myId;
    vrpn_int32 d_request_type;
    vrpn_int32 d_release_type;
    vrpn_int32 d_grantRequest_type;
    vrpn_int32 d_denyRequest_type;
    //vrpn_int32 d_losePeer_type;

    static int handle_request (void *, vrpn_HANDLERPARAM);
    static int handle_release (void *, vrpn_HANDLERPARAM);
    static int handle_grantRequest (void *, vrpn_HANDLERPARAM);
    static int handle_denyRequest (void *, vrpn_HANDLERPARAM);

    static int handle_losePeer (void *, vrpn_HANDLERPARAM);

    void sendRequest (vrpn_Connection *);
    void sendRelease (vrpn_Connection *);
    void sendGrantRequest (vrpn_Connection *, vrpn_uint32 IPnumber,
                           vrpn_uint32 PortNumber);
    void sendDenyRequest (vrpn_Connection *, vrpn_uint32 IPnumber,
                          vrpn_uint32 PortNumber);

    void triggerGrantCallbacks (void);
    void triggerDenyCallbacks (void);
    void triggerTakeCallbacks (void);
    void triggerReleaseCallbacks (void);

    void checkGrantMutex (void);

    void init (const char * name);

    struct mutexCallback {
      int (* f) (void *);
      void * userdata;
      mutexCallback * next;
    };

    mutexCallback * d_reqGrantedCB;
    mutexCallback * d_reqDeniedCB;
    mutexCallback * d_takeCB;
    mutexCallback * d_releaseCB;

    struct peerData {
      vrpn_uint32 IPaddress;
      vrpn_uint32 port;
      vrpn_bool grantedLock;
    };

    peerData * d_peerData;

    vrpn_PeerMutex (const char * name, vrpn_Connection * c);

};


#endif  // VRPN_MUTEX_H



Generated at Fri Sep 13 15:04:20 2002 for vrpn by doxygen 1.0.0 written by Dimitri van Heesch, © 1997-1999