Next: semstat: A semtool companion Up: semtool: An interactive semaphore Previous: Examples

#### The Source

    /*****************************************************************************
      Excerpt from "Linux Programmer's Guide - Chapter 6"
      (C)opyright 1994-1995, Scott Burkett
      *****************************************************************************
      MODULE: semtool.c
      *****************************************************************************
      A command line tool for tinkering with SysV style Semaphore Sets

      *****************************************************************************/

     #include <stdio.h>
     #include <ctype.h>
     #include <stdlib.h>
     #include <sys/types.h>
     #include <sys/ipc.h>
     #include <sys/sem.h>

     #define SEM_RESOURCE_MAX        1       /* Initial value of all semaphores */

     void opensem(int *sid, key_t key);
     void createsem(int *sid, key_t key, int members);
     void locksem(int sid, int member);
     void unlocksem(int sid, int member);
     void removesem(int sid);
     unsigned short get_member_count(int sid);
     int getval(int sid, int member);
     void dispval(int sid, int member);
     void changemode(int sid, char *mode);
     void usage(void);

     int main(int argc, char *argv[])
     {
             key_t key;
             int   semset_id;

             if(argc == 1)
                     usage();

             /* Create unique key via call to ftok() */
             key = ftok(".", 's');

             switch(tolower(argv[1][0]))
             {
                     case 'c': if(argc != 3)
                                     usage();
                               createsem(&semset_id, key,  atoi(argv[2]));
                               break;
                     case 'l': if(argc != 3)
                                     usage();
                               opensem(&semset_id, key);
                               locksem(semset_id, atoi(argv[2]));
                               break;
                     case 'u': if(argc != 3)
                                     usage();
                               opensem(&semset_id, key);
                               unlocksem(semset_id, atoi(argv[2]));
                               break;
                     case 'd': opensem(&semset_id, key);
                               removesem(semset_id);
                               break;
                     case 'm': opensem(&semset_id, key);
                               changemode(semset_id, argv[2]);
                               break;
                      default: usage();

             }

             return(0);
     }

     void opensem(int *sid, key_t key)
     {
             /* Open the semaphore set - do not create! */

             if((*sid = semget(key, 0, 0666)) == -1)
             {
                     printf("Semaphore set does not exist!\n");
                     exit(1);
             }

     }

     void createsem(int *sid, key_t key, int members)
     {
             int cntr;
             union semun semopts;

             if(members > SEMMSL) {
                     printf("Sorry, max number of semaphores in a set is %d\n",
                             SEMMSL);
                     exit(1);
             }

             printf("Attempting to create new semaphore set with %d members\n",
                                     members);

             if((*sid = semget(key, members, IPC_CREAT|IPC_EXCL|0666))
                             == -1)
             {
                     fprintf(stderr, "Semaphore set already exists!\n");
                     exit(1);
             }

             semopts.val = SEM_RESOURCE_MAX;

             /* Initialize all members (could be done with SETALL) */
             for(cntr=0; cntr<members; cntr++)
                     semctl(*sid, cntr, SETVAL, semopts);
     }

     void locksem(int sid, int member)
     {
             struct sembuf sem_lock={ 0, -1, IPC_NOWAIT};

             if( member<0 || member>(get_member_count(sid)-1))
             {
                     fprintf(stderr, "semaphore member %d out of range\n", member);
                     return;
             }

             /* Attempt to lock the semaphore set */
             if(!getval(sid, member))
             {
                     fprintf(stderr, "Semaphore resources exhausted (no lock)!\n");
                     exit(1);
             }

             sem_lock.sem_num = member;

             if((semop(sid, &sem_lock, 1)) == -1)
             {
                     fprintf(stderr, "Lock failed\n");
                     exit(1);
             }
             else
                     printf("Semaphore resources decremented by one (locked)\n");

             dispval(sid, member);
     }

     void unlocksem(int sid, int member)
     {
             struct sembuf sem_unlock={ member, 1, IPC_NOWAIT};
             int semval;

             if( member<0 || member>(get_member_count(sid)-1))
             {
                     fprintf(stderr, "semaphore member %d out of range\n", member);
                     return;
             }

             /* Is the semaphore set locked? */
             semval = getval(sid, member);
             if(semval == SEM_RESOURCE_MAX) {
                     fprintf(stderr, "Semaphore not locked!\n");
                     exit(1);
             }

             sem_unlock.sem_num = member;

             /* Attempt to lock the semaphore set */
             if((semop(sid, &sem_unlock, 1)) == -1)
             {
                     fprintf(stderr, "Unlock failed\n");
                     exit(1);
             }
             else
                     printf("Semaphore resources incremented by one (unlocked)\n");

             dispval(sid, member);
     }

     void removesem(int sid)
     {
             semctl(sid, 0, IPC_RMID, 0);
             printf("Semaphore removed\n");
     }

     unsigned short get_member_count(int sid)
     {
             union semun semopts;
             struct semid_ds mysemds;

             semopts.buf = &mysemds;

             /* Return number of members in the semaphore set */
             return(semopts.buf->sem_nsems);
     }

     int getval(int sid, int member)
     {
             int semval;

             semval = semctl(sid, member, GETVAL, 0);
             return(semval);
     }

     void changemode(int sid, char *mode)
     {
             int rc;
             union semun semopts;
             struct semid_ds mysemds;

             /* Get current values for internal data structure */
             semopts.buf = &mysemds;

             rc = semctl(sid, 0, IPC_STAT, semopts);

             if (rc == -1) {
                     perror("semctl");
                     exit(1);
             }

             printf("Old permissions were %o\n", semopts.buf->sem_perm.mode);

             /* Change the permissions on the semaphore */
             sscanf(mode, "%ho", &semopts.buf->sem_perm.mode);

             /* Update the internal data structure */
             semctl(sid, 0, IPC_SET, semopts);

             printf("Updated...\n");

     }

     void dispval(int sid, int member)
     {
             int semval;

             semval = semctl(sid, member, GETVAL, 0);
             printf("semval for member %d is %d\n", member, semval);
     }

     void usage(void)
     {
             fprintf(stderr, "semtool - A utility for tinkering with semaphores\n");
             fprintf(stderr, "\nUSAGE:  semtool4 (c)reate <semcount>\n");
             fprintf(stderr, "                 (l)ock <sem #>\n");
             fprintf(stderr, "                 (u)nlock <sem #>\n");
             fprintf(stderr, "                 (d)elete\n");
             fprintf(stderr, "                 (m)ode <mode>\n");
             exit(1);
     }