/** @file  ../include/sys/sem.h
@internalComponent
*/

/** @fn  semget(key_t key, int nsems, int semflg)
@param key
@param nsems
@param semflg
@return   The semget call
returns the id of a semaphore set if successful; otherwise, -1
is returned and errno is set to indicate the error.

@code
 SEM_R Read access for user.
 SEM_A Alter access for user.
 ( SEM_R>>3 )
  Read access for group.
 ( SEM_A>>3 )
  Alter access for group.
 ( SEM_R>>6 )
  Read access for other.
 ( SEM_A>>6 )
  Alter access for other.

Note:The 'group' flags (SEM_R >> 3 and SEM_A >> 3) are ignored in Symbian OS.
@endcode
  Based on the values of key and semflg, semget returns the identifier of a newly created or previously existing
set of semaphores. The key
is analogous to a filename: it provides a handle that names an
IPC object.
There are three ways to specify a key: IPC_PRIVATE may be specified, in which case a new IPC object
will be created. An integer constant may be specified.
If no IPC object corresponding
to key is specified and the IPC_CREAT bit is set in semflg, a new one will be created. The ftok function
may be used to generate a key from a pathname.

@code

 The mode of a newly created IPC object is determined by OR 'ing the following constants into the semflg argument: SEM_R Read access for user. SEM_A Alter access for user. ( SEM_R>>3 )  Read access for group. ( SEM_A>>3 )  Alter access for group. ( SEM_R>>6 )  Read access for other. ( SEM_A>>6 )  Alter access for other.
@endcode


 If a new set of semaphores is being created, nsems is used to indicate the number of semaphores the set should contain.
Otherwise, nsems may be specified as 0.

Examples:
@code
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <errno.h>

#define SEM_SET_KEY 1000
#define NO_OF_SEMAPHORES 2

int main(void)
{
    int sem_set_id;
    int perm;
    /*
     * Create 2 semaphores in a set, with access only to
     * the owner
     */
    perm = SEM_R | SEM_A;
    if((sem_set_id = semget(SEM_SET_KEY, NO_OF_SEMAPHORES, IPC_CREAT | perm))
        == -1) {
       printf("Semaphore creation failed with errno %d", errno);
       return -1;
    }
    return 0;
}
@endcode

@code
Note :If the user need to create a semaphore which can be accessed from a different process, the 'other' flags (SEM_R >> 6 and SEM_A >> 6) must be added in parameter of shmflg.
e.g The value of the variable perm used in the above example code should be as below
perm = SEM_R | SEM_A | SEM_R >> 6 | SEM_A >> 6
@endcode

@see semctl()
@see semop()
@see ftok()


 

@publishedAll
@externallyDefinedApi
*/

/** @fn  semop(int semid, struct sembuf *sops, unsigned nsops)
@param semid
@param sops
@param nsops
@return   The semop function returns 0 if successful; otherwise the
value -1 is returned and errno is set to indicate the error.

  The semop system call
atomically performs the array of operations indicated by array on the semaphore set indicated by semid. The length of array is indicated by nops. Each operation is encoded in a struct sembuf ,
which is defined as follows: 

@code
struct sembuf {
        u_short sem_num;        /* semaphore # */
        short   sem_op;         /* semaphore operation */
        short   sem_flg;        /* operation flags */
};
@endcode

 For each element in array, sem_op and sem_flg determine an operation to be performed on semaphore number sem_num in the set.
The values SEM_UNDO and IPC_NOWAIT may be ORed into the sem_flg member in order to modify the behavior of the given operation.

 The operation performed depends as follows on the value of sem_op: When sem_op is positive and the process has alter permission,
the semaphore's value is incremented by sem_op's value.
If SEM_UNDO is specified, the semaphore's adjust on exit value is decremented by sem_op's value.
A positive value for sem_op generally corresponds to a process releasing a resource
associated with the semaphore. The behavior when sem_op is negative and the process has alter permission,
depends on the current value of the semaphore: If the current value of the semaphore is greater than or equal to
the absolute value of sem_op, then the value is decremented by the absolute value of sem_op. If SEM_UNDO is specified, the semaphore's adjust on exit
value is incremented by the absolute value of sem_op. If the current value of the semaphore is less than the absolute value of sem_op, one of the following happens: If IPC_NOWAIT was specified, then semop returns immediately with a return value of EAGAIN. Otherwise, the calling process is put to sleep until one of the following
conditions is satisfied: Some other process removes the semaphore with the IPC_RMID option of semctl .
In this case, semop returns immediately with a return value of EIDRM. The semaphore's
value is greater than or equal to the absolute value of sem_op. When this condition becomes true, the semaphore's value is decremented
by the absolute value of sem_op, the semaphore's adjust on exit value is incremented by the
absolute value of sem_op.

 A negative value for sem_op generally means that a process is waiting for a resource to become
available. When sem_op is zero and the process has read permission,
one of the following will occur: If the current value of the semaphore is equal to zero
then semop can return immediately. If IPC_NOWAIT was specified, then semop returns immediately with a return value of EAGAIN. Otherwise, the calling process is put to sleep until one of the following
conditions is satisfied: Some other process removes the semaphore with the IPC_RMID option of semctl .
In this case, semop returns immediately with a return value of EIDRM. The semaphore's value becomes zero.

 For each semaphore a process has in use, an "adjust on exit"
value is maintained, as alluded to earlier.
When a process
exits, either voluntarily or involuntarily, the adjust on exit value
for each semaphore is added to the semaphore's value.
This can
be used to insure that a resource is released if a process terminates
unexpectedly.

Examples:
@code
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>

void File_Update(char* path, int val)
{
    struct sembuf sem_op;
    FILE* fp;
    /*
     * Wait on the semaphore till the value is non-negative.
     */
    sem_op.sem_num = 0;
    sem_op.sem_op = -1;
    sem_op.sem_flg = 0;
    semop(sem_set_id, &sem;_op, 1);
    /*
     * If we are here, then We have locked the semaphore,
     * and are assured exclusive access to file.
     * We can now manipulate the file
     */
    fp = fopen(path, "w");
    if (fp) {
        fprintf(fp, "%d", val);
        fclose(fp);
    }
    /*
     * Increase the value of the semaphore by 1 so that others blocked on
     * this semaphore get awakened.
     */
    sem_op.sem_num = 0;
    sem_op.sem_op = 1;
    sem_op.sem_flg = 0;
    semop(sem_set_id, &sem;_op, 1);
}

@endcode
@see semctl()
@see semget()


Bugs:

 The semop system call
may block waiting for memory even if IPC_NOWAIT was specified. 

 

@publishedAll
@externallyDefinedApi
*/

/** @fn  semctl(int semid, int semnum, int cmd, ...)
@param semid
@param semnum
@param cmd
@param ...
@return   On success, when cmd is one of GETVAL, GETPID, GETNCNT or GETZCNT, semctl returns the corresponding value; otherwise, 0 is returned.
On failure, -1 is returned, and errno is set to indicate the error.

@code
 IPC_STAT Fetch the semaphore sets struct semid_ds ,
 storing it in the memory pointed to by arg.buf .
 IPC_SET Changes the sem_perm.uid, sem_perm.gid, and sem_perm.mode members of the semaphore sets struct semid_ds to match those of the struct pointed to by arg.buf.
 IPC_RMID Immediately removes the semaphore set from the system.
 The calling
 processe'ss uid must equal the semaphore sets sem_perm.uid or sem_perm.cuid,
 GETVAL Return the value of semaphore number semnum.
 SETVAL Set the value of semaphore number semnum to arg.val. Outstanding adjust on exit values for this semaphore in any process
 are cleared.
 GETPID Return the pid of the last process to perform an operation on
 semaphore number semnum.
 GETNCNT Return the number of processes waiting for semaphore number semnum's value to become greater than its current value.
 GETZCNT Return the number of processes waiting for semaphore number semnum's value to become 0.
 GETALL Fetch the value of all of the semaphores in the set into the
 array pointed to by arg.array.
 SETALL Set the values of all of the semaphores in the set to the values
 in the array pointed to by arg.array. Outstanding adjust on exit values for all semaphores in this set,
 in any process are cleared.

@endcode
  The semctl system call
performs the operation indicated by cmd on the semaphore set indicated by semid. A fourth argument, a union semun arg ,
is required for certain values of cmd. For the commands that use the arg argument, union semun is defined as follows: 
@code
union semun {
        int     val;            /* value for SETVAL */
        struct  semid_ds *buf;  /* buffer for IPC_STAT & IPC_SET */
        u_short *array;         /* array for GETALL & SETALL */
};
@endcode

 Commands are performed as follows: 
 
 @code
 
IPC_STAT Fetch the semaphore sets struct semid_ds ,
storing it in the memory pointed to by arg.buf . 
IPC_SET Changes the sem_perm.uid, sem_perm.gid, and sem_perm.mode members of the semaphore sets struct semid_ds to match those of the struct pointed to by arg.buf. 
IPC_RMID Immediately removes the semaphore set from the system.

@endcode

The calling process's uid must equal the semaphore sets sem_perm.uid or sem_perm.cuid, GETVAL Return the value of semaphore number semnum. SETVAL Set the value of semaphore number semnum to arg.val. Outstanding adjust on exit values for this semaphore in any process
are cleared. 

@code

GETPID Return the pid of the last process to perform an operation on
semaphore number semnum. 
GETNCNT Return the number of processes waiting for semaphore number semnum's value to become greater than its current value. 
GETZCNT Return the number of processes waiting for semaphore number semnum s value to become 0. 
GETALL Fetch the value of all of the semaphores in the set into the
array pointed to by arg.array. 
SETALL Set the values of all of the semaphores in the set to the values
in the array pointed to by arg.array. Outstanding adjust on exit values for all semaphores in this set,
in any process are cleared.

@endcode

 The struct semid_ds
is defined as follows: 
@code
struct semid_ds {
        struct  ipc_perm sem_perm;      /* operation permission struct */
        struct  sem *sem_base;  /* pointer to first semaphore in set */
        u_short sem_nsems;      /* number of sems in set */
        time_t  sem_otime;      /* last operation time */
        long    sem_pad1;       /* SVABI/386 says I need this here */
        time_t  sem_ctime;      /* last change time */
                                /* Times measured in secs since */
                                /* 00:00:00 GMT, Jan. 1, 1970 */
        long    sem_pad2;       /* SVABI/386 says I need this here */
        long    sem_pad3[4];    /* SVABI/386 says I need this here */
};
@endcode

Examples:
@code
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <errno.h>

#define SEM_SET_KEY 1000
#define NO_OF_SEMAPHORES 2

int main(void)
{
    int sem_set_id;
    union semun sem_val;
    /*
     * Create 2 semaphores in a set, with access only to
     * the owner
     */
    if((sem_set_id = semget(SEM_SET_KEY, NO_OF_SEMAPHORES, IPC_CREAT | 0600))
        == -1) {
       printf("Semaphore creation failed with errno %d", errno);
       return -1;
    }
    /*
     * Initialize the first semaphore in our set to 1
     */
    sem_val.array = NULL;
    sem_val.buf = NULL;
    sem_val.val = 1;
    if(semctl(sem_set_id, 0, SETVAL, sem_val) == -1) {
       printf("Could not initialize first semaphore (errno %d)", errno);
       return -1;
    }
    /*
     * Initialize the second semaphore in our set to 0
     */
    sem_val.val = 0;
    if(semctl(sem_set_id, 1, SETVAL, sem_val) == -1) {
       printf("Could not initialize second semaphore (errno %d)", errno);
       return -1;
    }
    /*
     * Delete the semaphore set
     */
    if(semctl(sem_set_id, NO_OF_SEMAPHORES, IPC_RMID) == -1) {
       printf("Could not delete semaphore set (errno %d)", errno);
       return -1;
    }
    return 0;
}

@endcode
@see semget()
@see semop()


 

@publishedAll
@externallyDefinedApi
*/



/** @struct semid_ds

Contains following members,

@publishedAll
@externallyDefinedApi
*/

/** @var semid_ds::sem_perm
operation permission struct
*/

/** @var semid_ds::sem_base
pointer to first semaphore in set
*/

/** @var semid_ds::sem_nsems
number of sems in set
*/

/** @var semid_ds::sem_otime
last operation time
*/

/** @var semid_ds::sem_pad1
SVABI or 386 says I need this here 
*/

/** @var semid_ds::sem_ctime
last change time
*/

/** @var semid_ds::sem_pad2
SVABI or 386 says I need this here
*/

/** @var semid_ds::sem_pad3
SVABI or 386 says I need this here
*/


/** @struct sembuf

semop's sops parameter structure

@publishedAll
@externallyDefinedApi
*/

/** @var sembuf::sem_num
semaphore X
*/

/** @var sembuf::sem_op
semaphore operation
*/

/** @var sembuf::sem_flg
operation flags
*/

/** @struct sem

sem includes following members,

@publishedAll
@externallyDefinedApi
*/

/** @var sem::semval
semaphore value
*/

/** @var sem::sempid
process ID of last operation
*/

/** @var sem::semncnt
number of processes waiting for semval to become greater than current value 
*/

/** @var sem::semzcnt
number of processes waiting for semval to become 0 
*/


/** @def GETNCNT

commands for semctl. Return the value of semncnt.

@publishedAll
@externallyDefinedApi
*/

/** @def GETPID

commands for semctl. Return the value of sempid

@publishedAll
@externallyDefinedApi
*/

/** @def GETVAL

commands for semctl. Return the value of semval.

@publishedAll
@externallyDefinedApi
*/

/** @def GETALL

commands for semctl. Return semvals into arg.array 

@publishedAll
@externallyDefinedApi
*/

/** @def GETZCNT

commands for semctl. Return the value of semzcnt.

@publishedAll
@externallyDefinedApi
*/

/** @def SETVAL

commands for semctl. Set the value of semval to arg.val.

@publishedAll
@externallyDefinedApi
*/

/** @def SETALL

commands for semctl. Set semvals from arg.array.

@publishedAll
@externallyDefinedApi
*/


