/* getxcnt.c */
#include <stdio.h>
#include <stdlib.h> 
#include <sys/sem.h> 
#include <sys/stat.h> 
#include <unistd.h>

int main(void) { 
    int semid, semncnt, semzcnt;
    pid_t pid;
    union semun { 
        int val; 
        struct semid_ds *buf; 
        unsigned short  *array; 
    } arg; 

    /* initialize semaphore 0 <- 0, 1 <- 1 */
    unsigned short array[] = {0, 1};

    /* semaphore operations (child process)
     * sops[0]: decrement semaphore 0
     * sops[1]: wait for value of semaphore 1 to be 0
     */
    struct sembuf sops[] = {{0, -1, 0}, {1, 0, 0}};

    /* create a set of 2 semaphores */
    if ((semid = semget(IPC_PRIVATE, 2, IPC_CREAT|S_IRUSR|S_IWUSR)) == -1) { 
        perror("semget"); 
        exit(EXIT_FAILURE); 
    } 

    arg.array = array;

    if (semctl(semid, 0, SETALL, arg) == -1) { 
        perror("semctl SETVAL"); 
        exit(EXIT_FAILURE); 
    }

    if ((pid = fork()) == -1) {
        perror("fork");
        exit(EXIT_FAILURE); 
    } else if (pid == 0) {
        /* child process executes semop() */        
        if (semop(semid, sops, sizeof(sops)/sizeof(sops[0])) == -1) {
            perror("semop");
            exit(EXIT_FAILURE);
        }
        fprintf(stderr, "child process should not get here...\n");
        exit(EXIT_FAILURE);
    }

    /* give child process a chance to execute semop() */
    sleep(1);

    if ((semncnt = semctl(semid, 0, GETNCNT)) == -1) {
        perror("semctl GETNCNT");
        exit(EXIT_FAILURE);
    }
    if ((semzcnt = semctl(semid, 1, GETZCNT)) == -1) {
        perror("semctl GETZCNT");
        exit(EXIT_FAILURE);
    }

    printf("semncnt 0: %d\n", semncnt);
    printf("semzcnt 1: %d\n", semzcnt);

    /* clean up */
    if (semctl(semid, 0, IPC_RMID) == -1) {
        perror("semctl IPC_RMID");
        exit(EXIT_FAILURE);
    }

    return 0;
}
