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

#ifndef SEMAPHORESET_H
#define SEMAPHORESET_H

#include <pwd.h>
#include <grp.h>
#include <sys/types.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.

class semaphoreset {
	public:
			semaphoreset();
				// Creates a semaphore set.
		virtual	~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.

		int	create(key_t key, mode_t permissions, 
					int semcount, 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.
		int	attach(key_t key, int semcount);
				// Attaches to an already existing semaphore set
				// identified by "key", containing "semcount" 
				// semaphores.
		int	createOrAttach(key_t key, mode_t permissions, 
						int semcount, 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.
		int	forceRemove();
			// Removes the semaphore set, whether it
			// was created or attached to.

		void	showErrors();
			// errors will be printed to stderr
		void	dontShowErrors();
			// errors will not be printed to stderr

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

		int	wait(int index);
			// wait on the "index"'th semaphore in the set
		int	signal(int index);
			// signal on the "index"'th semaphore in the set


		int	waitWithUndo(int index);
			// wait on the "index"'th semaphore in the set and
			// undo the wait when the program exits
		int	signalWithUndo(int index);
			// signal on the "index"'th semaphore in the set and
			// undo the signal when the program exits


		int	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


		int	setUserName(char *username);
			// makes this semaphore set owned by 
			// the user "username"
		int	setGroupName(char *groupname);
			// makes this semaphore set owned by 
			// the group "groupname"
		int	setUserId(ushort uid);
			// makes this semaphore set owned by 
			// the user identified by "uid"
		int	setGroupId(ushort gid);
			// makes this semaphore set owned by 
			// the group identified by "gid"
		int	setPermissions(mode_t permissions);
			// sets the access permissions for this 
			// semaphore set to "permissions"


		char	*getUserName();
			// returns the name of the user that owns this
			// semaphore set
		char	*getGroupName();
			// returns the name of the group that owns this
			// semaphore set
		unsigned short	getUserId();
			// returns the user id of the user that owns this
			// semaphore set
		unsigned short	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

	private:
		#include <rudiments/private/semaphoreset.h>

};

#endif
