// Copyright (c) 1999-2002 David Muse
// See the COPYING file for more information.

#ifndef RUDIMENTS_SEMAPHORESET_H
#define RUDIMENTS_SEMAPHORESET_H

#include <rudiments/private/semaphoresetincludes.h>

// Semaphores allow processes to synchronize their activities.
//
// A semaphore is just a number with two primary operations that can be 
// performed on it: signal() and wait()
// 
// The operations are analagous to:
//
// int  semaphore;
//
// void signal() {
//      semaphore++;            // increment the semaphore
// }
//
// void wait() {
//      while (!(semaphore>0)); // wait until the semaphore>0
//      semaphore--;            // decrement the semaphore
// }
//
// The actual signal() and wait() operations are atomic.  There is no chance 
// of another process getting context-switched in and changing the semaphore 
// value between the two lines of code in the wait() process.
//
// Semaphores can be initialized to any number.
// 
// The initial value of the semaphore corresponds to the number of processes
// that will pass directly through their wait() calls without being blocked.
//
// Processes that get blocked calling wait() are placed in a queue.  When 
// another process calls signal(), the process at the head of the queue is 
// unblocked.
//
// A semaphoreset is just a collection of related semaphores.
//
// A semaphoreset is owned by a user and group and has access permissions
// just like a file.

#ifdef RUDIMENTS_NAMESPACE
namespace rudiments {
#endif

class semaphoresetprivate;

class semaphoreset {
        public:
                        semaphoreset();
                                // Creates a semaphore set.
                        ~semaphoreset();
                                // Cleans up and removes the semaphore set
                                // if it was created by create() or 
                                // createOrAttach() below.  If the semaphore
                                // was just attached to, it is not removed.

                bool  supportsTimedSemaphoreOperations();
                                // Returns true if the system supports timed
                                // semaphore operations or false otherwise.

                bool  create(key_t key, mode_t permissions,
                                        int semcount, const int *values);
                                // Creates a semaphore set identified by "key"
                                //      containing "semcount" semaphores.
                                // "key" should be generated using the ftok 
                                //  function. 
                                // "permissions" sets the access permissions
                                //  for the set.
                                // "values" should be an array of starting 
                                //  values for each of the semaphores 
                                //  in the set.
                bool  attach(key_t key, int semcount);
                                // Attaches to an already existing semaphore set
                                // identified by "key", containing "semcount" 
                                // semaphores.
                bool  createOrAttach(key_t key, mode_t permissions,
                                        int semcount, const int *values);
                                // Attempts to create the semaphore set 
                                // identified by "key".  If this fails, it 
                                // attempts to attach to a semaphore set
                                // identified by "key".

                void  dontRemove();
                        // Instructs the destructor not to remove the semaphore
                        // set if it was created during a call to create() or 
                        // createOrAttach() above.  This is useful if an 
                        // application creates a semaphore set then forks and 
                        // wants to delete the semaphore set in the forked 
                        // process but does not want the semaphore removed from
                        // the system.
                bool  forceRemove();
                        // Removes the semaphore set, whether it
                        // was created or attached to.

                int   getId() const;
                        // Returns the internal id for the semaphore set.

                bool  wait(int index);
                        // wait on the "index"'th semaphore in the set
                bool  wait(int index, long seconds, long nanoseconds);
                        // Wait on the "index"'th semaphore in the set until
                        // "seconds" and "nanoseconds" elapse.  Returns false
                        // and sets errno to EAGAIN if a timeout occurs.
                        // Returns false if the system doesn't support timed
                        // semaphore operations.
                bool  signal(int index);
                        // signal on the "index"'th semaphore in the set


                bool  waitWithUndo(int index);
                        // wait on the "index"'th semaphore in the set and
                        // undo the wait when the program exits
                bool  waitWithUndo(int index, long seconds, long nanoseconds);
                        // Wait on the "index"'th semaphore in the set until
                        // "seconds" and "nanoseconds" elapse.  Undo the wait
                        // when the program exits.  Returns false and sets
                        // errno to EAGAIN if a timeout occurs.
                        // Returns false if the system doesn't support timed
                        // semaphore operations.
                bool  signalWithUndo(int index);
                        // signal on the "index"'th semaphore in the set and
                        // undo the signal when the program exits


                bool  setValue(int index, int value);
                        // set the "index"'th semaphore in the set to "value"
                int   getValue(int index);
                        // return the value of the "index"'th 
                        // semaphore in the set


                bool  setUserName(const char *username);
                        // Makes this semaphore set owned by 
                        // the user "username".
                        //   
                        // Note that setUserName() uses the passwdentry class.
                        // If you are using this method in a multithreaded
                        // application, you may need to supply the passwdentry
                        // class a mutex.  See passwdentry.h for more detail.
                bool  setGroupName(const char *groupname);
                        // Makes this semaphore set owned by 
                        // the group "groupname".
                        //   
                        // Note that setGroupName() uses the groupentry class.
                        // If you are using this method in a multithreaded
                        // application, you may need to supply the groupentry
                        // class a mutex.  See groupentry.h for more detail.

                bool  setUserId(uid_t uid);
                        // makes this semaphore set owned by 
                        // the user identified by "uid"
                bool  setGroupId(gid_t gid);
                        // makes this semaphore set owned by 
                        // the group identified by "gid"
                bool  setPermissions(mode_t permissions);
                        // sets the access permissions for this 
                        // semaphore set to "permissions"


                const char    *getUserName();
                        // returns the name of the user that owns this
                        // semaphore set
                        //
                        // Note that this method allocates a buffer
                        // internally and returns it.  The calling program must
                        // deallocate this buffer.
                        //   
                        // Note that getUserName() uses the passwdentry class.
                        // If you are using this method in a multithreaded
                        // application, you may need to supply the passwdentry
                        // class a mutex.  See passwdentry.h for more detail.
                const char    *getGroupName();
                        // returns the name of the group that owns this
                        // semaphore set
                        //
                        // Note that this method allocates a buffer
                        // internally and returns it.  The calling program must
                        // deallocate this buffer.
                        //   
                        // Note that getGroupName() uses the groupentry class.
                        // If you are using this method in a multithreaded
                        // application, you may need to supply the groupentry
                        // class a mutex.  See groupentry.h for more detail.

                uid_t   getUserId();
                        // returns the user id of the user that owns this
                        // semaphore set
                gid_t   getGroupId();
                        // returns the group id of the group that owns this
                        // semaphore set
                mode_t  getPermissions();
                        // returns the access permissions for this
                        // semaphore set


                int   getWaitingForZero(int index);
                        // returns the number of processes that
                        // are waiting for the semaphore to become 0
                int   getWaitingForIncrement(int index);
                        // returns the number of processes that
                        // are waiting for the semaphore to increment

        #include <rudiments/private/semaphoreset.h>

};

#ifdef RUDIMENTS_NAMESPACE
}
#endif

#endif