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

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

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

    if ((semid = semget(IPC_PRIVATE, 1, IPC_CREAT|S_IRUSR|S_IWUSR)) == -1) { 
        perror("semget"); 
        exit(EXIT_FAILURE); 
    } 

    fprintf(stderr, "semid: %d\n", semid);

    /* initialize semaphore 0 to 2 */
    arg.val = 2;

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

    if ((pid = fork()) == -1) {
        perror("fork");
        exit(EXIT_FAILURE); 
    } else if (pid == 0) {
        sleep(1); /* Allow parent to call semop() first */
        
        /* decrement semaphore by 1 */
        if (semop(semid, sops, 1) == -1) {
            perror("semop");
            exit(EXIT_FAILURE);
        }
        fprintf(stderr, "child process finished semop() (sem_op: -1)\n");
        exit(EXIT_SUCCESS);
    }

    alarm(5); /* terminate if semop() hasn't completed in 5 seconds */
              /* (remove the semaphore set with "ipcrm -s SEMID") */

    if (semop(semid, sops, sizeof(sops)/sizeof(sops[0])) == -1) { 
        perror("semop"); 
        exit(EXIT_FAILURE); 
    } 

    fprintf(stderr, "semop() completed\n");

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

    return 0;
}
