Using Semaphores

The previous section focused on affecting changes in the semaphore and set attributes, and on obtaining information. This section will cover the aspects of using semaphores to perform the following:

  • Wait operations

  • Notify operations

  • Wait for zero operations

These operations work on the entire set of semaphores or on a subset. You can also operate on individual semaphores in the set according to your application needs.

Semaphore operations are performed by the semop(2) system call. Its function synopsis is as follows:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semop(int semid, struct sembuf array[], unsigned nops);

The argument semid contains the IPC ID of the semaphore set, which is returned by the semget(2) function. The array[] argument contains the set of semaphore operations that are to be performed, while nops indicates how many elements exist in the array[].

The semop(2) function returns 0 when successful. The value -1 is returned when an error code is returned in errno.

Semaphore operations are described in the structure sembuf, which is shown in the following synopsis:

struct sembuf {
    u_short  sem_num;          /* semaphore number */
    short    sem_op;           /* semaphore operation */
    short    sem_flg;          /* operation flags */
};

The member sem_num selects the semaphore number within the set. There is no requirement that semaphores be accessed in any particular order. The member sem_op determines the semaphore operation to be performed. This signed number affects the semaphore as follows:

sem_op < 0 Wait on the semaphore
sem_op = 0 Wait for zero to occur
sem_op > 0 Notify the semaphore

For example, if one semaphore represents bowling balls, you would use the value -1 to obtain one. If you want to obtain four at one time, then you would use -4 as the sem_op value. In this manner, if there were only three available, you would wait until at least four bowling balls became available.

Conversely, to return four bowling balls, your sem_op value would be the value +4. If you were returning only one ball, then +1 would be the sem_op value. This operation may notify other processes that their wait request has now been satisfied.

A process may choose to wait for the zero count to be reached. If you have written an application that monitors the number of free bowling balls available, then a sem_op value of zero would cause the semop(2) call to return only when the count has reached zero. This would then allow your application to warn you that there are now no free bowling balls available.

The sem_flg member allows you to specify additional option flags for each semaphore operation. These include

0 No flags.
IPC_NOWAIT Does not suspend execution of the calling program if this semaphore operation cannot be satisfied. Error EAGAIN is returned if the operation was unsuccessful.
SEM_UNDO Adjusts the undo structure for this semaphore when the operation succeeds.

The IPC_NOWAIT flag allows your application to attempt the operation, but not have its execution suspended if it must wait. While the flag applies to individual semaphores, the returned error EAGAIN indicates that no semaphore operations succeeded, although only one semaphore may have used the IPC_NOWAIT flag.

The SEM_UNDO flag allows you to plan for semaphore recovery, and will be discussed later in the chapter.

Waiting on Semaphores

A wait operation decrements the count of the semaphore counter. If the count reaches zero, then the request suspends the execution of the process (unless the flag SEM_NOWAIT is used for the semaphore(s) in question).

The source module in Listing 24.12 performs all semaphore operations for the ./semop utility program for the -o option.

Code Listing 24.12. semop.c—Source Module That Performs semop(2) Operations
1:   /* ctlsem.c */
2:
3:   #include "semop.h"
4:
5:   void
6:   ctl_semop(
7:     int optch,
8:     const char *optarg,
9:     int sems[],
10:    int array[],
11:    int flags[],
12:    int n) {
13:      int z;
14:      int x;                                  /* Iterator */
15:      int semx;                               /* Semaphore number */
16:      struct sembuf ops[MAX_NSET];
17:
18:      for ( x=0; x<n; ++x ) {
19:          ops[x].sem_num = semx = sems[x];    /* Semaphore # */
20:          ops[x].sem_op = array[x];           /* Semaphore operation */
21:          if ( semx >= 0 && semx < n_sem )
22:              ops[x].sem_flg = semx < n_sem   /* In range ? */
23:                  ? flags[semx]               /* Semaphore flags */
24:                  : 0;                        /* else use zero */
25:      }
26:
27:      z = semop(semid,ops,n);
28:      if ( z == -1 ) {
29:          fprintf(stderr,"%s: -%c %s
",strerror(errno),optch,optarg);
30:          exit(1);
31:      }
32:
33:      printf("  -%c %s =>",optch,optarg);
34:
35:      for ( x=0; x<n; ++x )
36:          printf(" { %d,%+d,%s} ",
37:              ops[x].sem_num,
38:              ops[x].sem_op,
39:              ops[x].sem_flg ? "SEM_UNDO" : "0");
40:      putchar('
'),
41:
42:      fflush(stdout);
43:  }

The ctl_semop() function receives the list of semaphores to act upon in the argument sems[] (line 9). The array[] argument contains the list of semaphore operations to perform. The argument flags[] (line 11) contains a list of flags in semaphore set order, while the last argument n indicates how many operations there are to perform.

The semaphore operations array is declared in line 16, named ops[]. The loop in lines 18–25 populates this structured array. Line 19 assigns the semaphore number within the set. Line 20 assigns the semaphore operation. Line 21 makes certain that the semaphore number is in range, and then retrieves the flags value and assigns it to the sem_flg member.

Once the ops[] array is ready, it is passed to the semop(2) function in line 27, along with the count value n. Lines 33–42 display the operation performed for the benefit of the utility program.

The ./semop utility program uses the following format for specifying semaphore operations, after the initial -o option:

<semaphore_number>=<semaphore_op>[{ u|U} ]

To wait for 4 bowling balls, using semaphore 0, with no SEM_UNDO, the following option would be given:

-o 0=-4u

Or you can rely on the current "flags" value, and specify

-o 0=-4

To combine operations, separate them by commas:

-o 0=-4,2=-1U,1=-1

This option specifies to wait with count 4 on semaphore 0 using its current flags value, wait with count 1 on semaphore 2 using SEM_UNDO and wait with count 1 on semaphore 1 with its current flags value.

Flags for each semaphore are maintained by the utility and default to 0 (no SEM_UNDO). This can be checked using the -R option:

$ ./semop -k0xFEEDF00D -a -R
  -a 0xFEEDF00D => IPC ID 196608
  There are 3 semaphores in this set.
  -R : key    0xFEEDF00D
  -R : IPC ID 196608
  -R : 0 has no SEM_UNDO
  -R : 1 has no SEM_UNDO
  -R : 2 has no SEM_UNDO
$

Once SEM_UNDO has been applied to a semaphore, the utility program remembers this until you disable it again by a following -u option or semaphore -o operation using the trailing u.

For the following examples, initialize your semaphores as shown here:

$ ./semop -k0xFEEDF00D -a -V10,5,11 -G
  -a 0xFEEDF00D => IPC ID 196608
  There are 3 semaphores in this set.
  -V 10,5,11
  -G : semaphore # 0 = 10
  -G : semaphore # 1 = 5
  -G : semaphore # 2 = 11
$

The semaphore values should be 10, 5, and 11 for semaphores 0, 1, and 2, respectively. The -G option permits you to check the current value of the semaphores.

The following wait operations will request 3 from semaphore 0, and 2 from semaphore 1, and leave semaphore 2 as it is (do not use SEM_UNDO here):

$ ./semop -k0xFEEDF00D -a -o 0=-3,1=-2 -G
  -a 0xFEEDF00D => IPC ID 196608
  There are 3 semaphores in this set.
  -o 0=-3,1=-2 => { 0,-3,0}  { 1,-2,0}
  -G : semaphore # 0 = 7
  -G : semaphore # 1 = 3
  -G : semaphore # 2 = 11
$

The -o option requests a semop(2) call, while the final -G option shows us the final results. Notice how semaphore 0 was decremented by 3, and semaphore 1 was decremented by 2 as requested. The display shows in { } the semaphore operations that were submitted to semop(2).

Open a second terminal session, and try the following semaphore wait:

$ x/semop -k0xFEEDF00D -a -o 0=-6,1=-4 -G
  -a 0xFEEDF00D => IPC ID 196608
  There are 3 semaphores in this set.

If your semaphore values match what was shown in the previous example, your utility program should appear to hang here. This happens because you have requested 4 from semaphore 1, but its current count is 3. While that application waits, in another terminal session, execute the following:

$ ./semop -k0xFEEDF00D -a -o 1=+2
  -a 0xFEEDF00D => IPC ID 196608
  There are 3 semaphores in this set.
  -o 1=+2 => { 1,+2,0}
$

When this command executes, semaphore 1 is notified with a count of +2 putting the semaphore count up to 5 from the current value of 3. The value 5 will satisfy the other request, so your waiting process is able to return from semop(2) successfully, as shown below:

$ ./semop -k0xFEEDF00D -a -o 0=-6,1=-4 -G
  -a 0xFEEDF00D => IPC ID 196608
  There are 3 semaphores in this set.
  -o 0=-6,1=-4 => { 0,-6,0}  { 1,-4,0}
  -G : semaphore # 0 = 1
  -G : semaphore # 1 = 1
  -G : semaphore # 2 = 11
$

Notifying Semaphores

Adding a count to the semaphore notifies the semaphore list. The UNIX kernel maintains a list of all processes that are waiting for notification. Recall that the semctl(2) operation GETNCNT returns the number of processes on this list. When a notify occurs, the entire list of processes is re-tested to see if the semaphore operation for that process can succeed.

Warning

Applications that have a large number of processes waiting on a given semaphore may suffer system performance problems. Each notify operation on a semaphore awakens each process to re-test the semaphore. With a high number of processes and swapping, this can create poor system performance.

When possible, design your application so that only a few processes will wait on a given semaphore.


The preceding section showed a simple notify. You can also notify multiple semaphores at once, as shown here:

$ ./semop -k0xFEEDF00D -a -o 2=1,0=3 -G
  -a 0xFEEDF00D => IPC ID 196608
  There are 3 semaphores in this set.
  -o 2=1,0=3 => { 2,+1,0}  { 0,+3,0}
  -G : semaphore # 0 = 4
  -G : semaphore # 1 = 1
  -G : semaphore # 2 = 12
$

This example adds +1 to semaphore 2 (the + sign does not have to be entered), and +3 to semaphore 0. The -G option reports the final results.

Waiting for Zero

Processes that want to be notified when the semaphore count reaches zero can specify 0 for the semaphore operation. Note, however, that this operation is different from other operations because it is just a snapshot notification. By the time the execution returns from a zero notification, another process may have notified the semaphore again.

The ./semop command can wait for a zero count by specifying the 0 for the semaphore operation:

$ ./semop -k0xFEEDF00D -a -o 1=0
  -a 0xFEEDF00D => IPC ID 196608
  There are 3 semaphores in this set.

This process will appear to hang until you perform enough waits to bring the semaphore count to 0 for semaphore 1 of this set.

Semaphore Undo Processing

Semaphore counts manage a count of a particular resource. To keep this count accurate, each wait on a semaphore must eventually be matched by a corresponding notify. For example, if you have 30 bowling balls managed by one semaphore, eventually when no bowling balls are in use, the count must increase back to 30. Otherwise, your application will lose track of its resources.

When a process runs, however, an unexpected abort or exit can occur. If your bowling ball reservation program performed a semaphore wait for 4 balls and then aborted, your semaphore count will be left short by 4 balls. You would need to manually tweak the semaphore using the ./semop utility to recover from this problem.

The UNIX kernel maintains SEM_UNDO structures for each process. This permits a process to clean up its semaphore faux pas. The use of SEM_UNDO must, however, be explicitly requested as a flag in sem_flg of the semaphore operation. When SEM_UNDO is enabled, each semaphore wait causes a corresponding SEM_UNDO count to be incremented. Each notify is tracked by a negative SEM_UNDO count. If the program should exit before restoring the semaphores used with SEM_UNDO, these recovery values are applied to the semaphores upon process termination.

For example, assume the following initial semaphore states

$ ./semop -k0xFEEDF00D -a -V30,20,6 -G
  -a 0xFEEDF00D => IPC ID 196608
  There are 3 semaphores in this set.
  -V 30,20,6
  -G : semaphore # 0 = 30
  -G : semaphore # 1 = 20
  -G : semaphore # 2 = 6
$

There are 30 bowling balls, 20 pairs of bowling shoes, and 6 bowling alleys. Now run a semaphore wait operation, requesting 4 bowling balls, 4 pairs of shoes, and 1 bowling alley, with the SEM_UNDO flag enabled (using -U):

$ ./semop -k0xFEEDF00D -a -U -o 0=-4,1=-4,2=-1 -G
  -a 0xFEEDF00D => IPC ID 196608
  There are 3 semaphores in this set.
  -U : 0 uses SEM_UNDO
  -U : 1 uses SEM_UNDO
  -U : 2 uses SEM_UNDO
  -o 0=-4,1=-4,2=-1 => { 0,-4,SEM_UNDO}  { 1,-4,SEM_UNDO}  { 2,-1,SEM_UNDO}
  -G : semaphore # 0 = 26
  -G : semaphore # 1 = 16
  -G : semaphore # 2 = 5
$

The -U option sets SEM_UNDO as the default for all semaphore operations. Notice how the wait operation successfully returned, and the -G option reported the final counts of 26, 16, and 5 for the semaphores. However, now check the semaphores again with the -G option:

$ ./semop -k0xFEEDF00D -a -G
  -a 0xFEEDF00D => IPC ID 196608
  There are 3 semaphores in this set.
  -G : semaphore # 0 = 30
  -G : semaphore # 1 = 20
  -G : semaphore # 2 = 6
$

The counts have been restored after the prior ./semop process terminated. This was done by the UNIX kernel because the SEM_UNDO counts were being maintained. Think of SEM_UNDO keeping opposite counts for each semaphore operation.

If a wait operation of -4 is performed, +4 is added to the SEM_UNDO value. If a notify of +3 is performed, the value -3 is added to the SEM_UNDO value (subtracting 3). If these were the last operations performed, the final SEM_UNDO value at process termination would be +1, requiring the kernel to perform a notify of +1 to restore the semaphore.

As convenient as the SEM_UNDO feature may be, it is not always wise to use it. When a binary semaphore is being used to lock a shared memory table, for example, is it wise to have the table unlocked when the lock holding process aborts? The aborting process may have left the shared memory table in an unusable state. It may be preferable to have other processes hang rather than proceed. In this manner, the administrator can take corrective action and restart the application from a known and trusted state.

The semop Utility Program

The next few listings complete the source listings for the utility program semop. Listing 24.13 lists the main program.

Code Listing 24.13. main.c—The Main Program Source Listing for the semop Utility
1:   /* main.c */
2:
3:   #include "semop.h"
4:
5:   int semid = -1;             /* No default IPC ID */
6:   int n_sem = 3;              /* Default # semaphores in a set */
7:
8:   /*
9:    * semop utility main program :
10:   *
11:   * Use './semop -h'for help.
12:   */
13:  int
14:  main(int argc,char **argv) {
15:      int z;                      /* Option character/status */
16:      int x;                      /* Iterator */
17:      int rc = 0;                 /* Return code */
18:      int n;                      /* # of values in array */
19:      key_t key = 0xFEEDF00D;     /* Default IPC key */
20:      int sems[MAX_NSET];         /* Array of semaphore numbers */
21:      int array[MAX_NSET];        /* Array of integer values */
22:      int flags[MAX_NSET];        /* Flags for each semaphore */
23:      unsigned long ul;           /* unsigned value */
24:      const char cmdopts[] = "hk:ac:i:o:sm:dg:Gv:V:p:Pn:z:uURx:y:";
25:
26:      for ( x=0; x<MAX_NSET; ++x )
27:          flags[x] = 0;           /* Initialize with no SEM_UNDO */
28:
29:      while ( !rc && (z = getopt(argc,argv,cmdopts)) != -1 )
30:          switch ( z ) {
31:          case 'h':              /* -h           ; usage info */
32:              usage();
33:              return 0;
34:
35:          case 'k':              /* -k IPCkey[,n] ; IPC Key, n_sem */
36:              if ( cvt2ulong(optarg,&ul) )
37:                  goto badcvt;
38:              key = (key_t) ul;
39:              break;
40:
41:          case 'a':              /* -a           ; access set */
42:              get_set(z,key,0);   /* Locate IPC ID */
43:              ctl_stat(z,-1);     /* Just fill sembuf & fix n_sem */
44:              printf("  There are %d semaphores in this set.
",
45:                  n_sem);
46:              break;
47:
48:          case 'c':              /* -c n         ; create set */
49:              if ( cvt2ulong(optarg,&ul) )
50:                  goto badcvt;
51:              n_sem = (int)ul;
52:              get_set(z,key,1);   /* Create set */
53:              ctl_stat(z,0);      /* Just fill sembuf */
54:              printf("  -c %d : Created semaphore set -k 0x%08lX
",
55:                  n_sem,(long)key);
56:              break;
57:
58:          case 'i':              /* -i IPCID     ; IPC ID     */
59:              if ( cvt2ulong(optarg,&ul) )
60:                  goto badcvt;
61:              semid = (int) ul;
62:              ctl_stat(z,-1);     /* Just report failure */
63:              printf("  -i %d : There are %d semaphores in this set.
",
64:                  semid,n_sem);
65:              break;
66:
67:          case 'o':              /* -o m[,n[,o]] ; semop(2)   */
68:              if ( (n = cvt2semops(optarg,sems,array,flags)) < 1 )
69:                  goto badcvt;
70:              ctl_semop(z,optarg,sems,array,flags,n);
71:              break;
72:
73:          case 's':              /* -s           ; IPC_STAT   */
74:              ctl_stat(z,1);
75:              break;
76:
77:          case 'm':              /* -m mode      ; IPC_SET    */
78:              if ( cvt2ulong(optarg,&ul) )
79:                  goto badcvt;
80:              ctl_chmod(z,(mode_t)ul);
81:              break;
82:
83:          case 'x':              /* -x userid    ; IPC_SET    */
84:              ctl_chown(z,optarg);
85:              break;
86:
87:          case 'y':              /* -g group     ; IPC_SET    */
88:              ctl_chgrp(z,optarg);
89:              break;
90:
91:          case 'd':              /* -d           ; IPC_RMID   */
92:              ctl_rmid(z);
93:              break;
94:
95:          case 'g':              /* -g n         ; IPC_GETVAL */
96:              if ( cvt2ulong(optarg,&ul) )
97:                  goto badcvt;
98:              ctl_getval(z,(int)ul);
99:              break;
100:
101:         case 'G':              /* -G           ; IPC_GETALL */
102:             ctl_getall(z);
103:             break;
104:
105:         case 'v':              /* -v n=x       ; IPC_SETVAL */
106:             if ( (n = cvt2array(optarg,array,"=")) != 2 )
107:                 goto badcvt;
108:             ctl_setval(z,array[0],array[1]);
109:             break;
110:
111:         case 'V':              /* -V m,n,o     ; IPC_SETALL */
112:             if ( (n = cvt2array(optarg,&array[0],",")) != n_sem )
113:                 goto badcvt;
114:             ctl_setall(z,array);
115:             break;
116:
117:         case 'p':              /* -p n         ; GETPID */
118:             if ( cvt2ulong(optarg,&ul) )
119:                 goto badcvt;
120:             ctl_get(z,GETPID,(int)ul);
121:             break;
122:
123:         case 'P':
124:             for ( x=0; x<n_sem; ++x )
125:                 ctl_get('p',GETPID,x);
126:             break;
127:
128:         case 'n':              /* -n           ; GETNCNT */
129:             if ( cvt2ulong(optarg,&ul) )
130:                 goto badcvt;
131:             ctl_get(z,GETNCNT,(int)ul);
132:             break;
133:
134:         case 'z':              /* -z           ; GETZCNT */
135:             if ( cvt2ulong(optarg,&ul) )
136:                 goto badcvt;
137:             ctl_get(z,GETZCNT,(int)ul);
138:             break;
139:
140:         case 'u':              /* -u           ; No SEM_UNDO */
141:             for ( x=0; x<n_sem; ++x )
142:                 flags[x] &= ~SEM_UNDO;
143:             report(z,key,flags);
144:             break;
145:
146:         case 'U':              /* -U           ; SEM_UNDO   */
147:             for ( x=0; x<n_sem; ++x )
148:                 flags[x] |= SEM_UNDO;
149:             report(z,key,flags);
150:             break;
151:
152:         case 'R':
153:             report(z,key,flags);
154:             break;
155:
156:         default  :              /* Unknown option */
157:             rc = 1;
158:         }
159:
160:     /*
161:      * Command line arguments are ignored :
162:      */
163:     for ( ; optind < argc; ++optind, rc=2 )
164:         printf("Ignored argument '%s'
",argv[optind]);
165:
166:     return rc;
167:
168:     /*
169:      * Bad numeric conversion :
170:      */
171: badcvt:
172:     fprintf(stderr,"Bad numeric: -%c %s
",z,optarg);
173:     return 1;
174: }

The loop in lines 26 and 27 initializes the flags for the semaphore set to 0. The -U option ORs in the flag SEM_UNDO to all members of the flags[] array, whereas the -u option removes this flag. The -o option individually enables and disables the SEM_UNDO flag, as you find convenient to do. With no trailing u or U specified in a semaphore operation, the default is taken from the current value in the flags[] array.

The remainder of the main program is the getopt(3) loop starting in line 29. Each option invokes the semaphore operation as it is encountered. Command-line arguments are ignored, and warnings of this are issued in lines 163 and 164. It is easy to forget a hyphen.

Listing 24.14 shows the programming used to perform the various string-to-numeric conversions. These functions support the semaphore option argument parsing operations.

Code Listing 24.14. convrt.c—The Source Listing for Conversions for the semop Utility
1:   /* convrt.c */
2:
3:   #include "semop.h"
4:
5:   /*
6:    * Convert string to unsigned long (any radix) :
7:    */
8:   int
9:   cvt2ulong(const char *str,unsigned long *ulp) {
10:      char *ep;
11:      unsigned long ul;
12:
13:      ul = strtoul(str,&ep,0);
14:      if ( *ep != 0 )
15:          return -1;      /* Failed */
16:
17:      if ( ulp )
18:          *ulp = ul;
19:      return 0;           /* Success */
20:  }
21:
22:  /*
23:   * Parse and convert up to n_sem values to array :
24:   */
25:  int
26:  cvt2array(const char *str,int array[],const char *delim) {
27:      char *cp;                       /* Token pointer */
28:      int n = 0;                      /* # of values extracted */
29:      int m = *delim == '='? 2 : n_sem; /* only 2 if using '='*/
30:      unsigned long ul;               /* converted ulong value */
31:
32:      for ( cp=(char *)str; n<m && *cp; ++n ) {
33:          ul = strtoul(cp,&cp,0);     /* Convert to ulong */
34:          if ( *cp && !strchr(delim,*cp) )
35:              return -1;              /* Failed conversion */
36:          array[n] = (int)ul;         /* Save ulong value in array */
37:          if ( *cp )
38:              ++cp;                   /* Skip delimiter */
39:      }
40:
41:      return n;                       /* Return # of values */
42:  }
43:
44:  /*
45:   * -o 0=-1u,2=-3U,1=1
46:   *
47:   * Translates to:
48:   *
49:   *  Semaphore 0 does a wait of 1, with no SEM_UNDO
50:   *  Semaphore 2 does a wait of 3, with SEM_UNDO
51:   *  Semaphore 1 does a notify of 1, with current SEM_UNDO flag
52:   */
53:  int
54:  cvt2semops(const char *str,int sems[],int array[],int flags[]) {
55:      int x = 0;
56:      int semx;                       /* Semaphore index */
57:      char *ep = (char *)str;
58:      unsigned long ul;
59:      long lg;
60:
61:      for ( x=0; *ep && x<n_sem; ++x ) {
62:          /*
63:           * Extract the semaphore # :
64:           */
65:          ul = strtoul(ep,&ep,0);
66:          if ( *ep != '=')
67:              return -1;              /* Bad format */
68:          semx = sems[x] = (int) ul;  /* Semaphore # */
69:          ++ep;                       /* Skip '='*/
70:
71:          /*
72:           * Extract the Semaphore operation :
73:           */
74:          lg = strtol(ep,&ep,0);
75:          if ( *ep != 0 && *ep != ','&& *ep != 'u'&& *ep != 'U')
76:              return -1;              /* Bad format */
77:          array[x] = (int) lg;        /* Semaphore operation */
78:
79:          /*
80:           * Process optional trailing 'u'|'U'for flags[] :
81:           */
82:          if ( *ep == 'u') {
83:              flags[semx] &= ~SEM_UNDO;/* Remove SEM_UNDO */
84:              ++ep;                   /* Skip 'u'*/
85:          } else if ( *ep == 'U') {
86:              flags[semx] |= SEM_UNDO;/* Add SEM_UNDO */
87:              ++ep;                   /* Skip 'U'*/
88:          }
89: 
90:          /*
91:           * Check current delimiter :
92:           */
93:          if ( *ep != 0 ) {
94:              if ( *ep != ',')
95:                  return -1;          /* Bad format */
96:              ++ep;                   /* Skip delimiter */
97:          }
98:      }    
99:
100:     return x;
101: }

Listing 24.15 shows the module that performs the reporting when the -R option is used.

Code Listing 24.15. report.c—The -R Reporting Function of the semop Utility
1:   /* report.c */
2:
3:   #include "semop.h"
4:
5:   /*
6:    * Report SEM_UNDO status :
7:    */
8:   void
9:   report(int optch,key_t key,int flags[]) {
10:      int x;
11:
12:      if ( optch == 'R') {
13:          /*
14:           * This report only performed for -R option :
15:           */
16:          printf("  -%c : key    0x%08lX
",optch,(long)key);
17:          printf("  -%c : IPC ID %d
",optch,semid);
18:      }
19:
20:      for ( x=0; x<n_sem; ++x )
21:          printf("  -%c : %d %s SEM_UNDO
",
22:              optch,
23:              x,
24:              flags[x] & SEM_UNDO ? "uses" : "has no");
25:              fflush(stdout);
26:      fflush(stdout);
27:  }

Finally, Listing 24.16 shows the usage() function for completeness.

Code Listing 24.16. usage.c—The usage() Function for the semop Utility Program
1:   /* usage.c */
2:
3:   #include "semop.h"
4:
5:   /*
6:    * Display usage instructions :
7:    */
8:   void
9:   usage(void) {
10:
11:      puts("Usage:  semop [options]");
12:      puts("Options:");
13:      puts("	-k key	IPC Key for -a or -c option.");
14:      puts("	-a		Access existing set based on -k key");
15:      puts("	-c n		Create set of n semaphores using -k key");
16:      puts("	-i ID		Access existing set by IPC ID");
17:      puts("	-o <sops>	semop(n) for wait/zero/notify");
18:      puts("	-s		semctl(IPC_STAT)");
19:      puts("	-m mode		semctl(IPC_SET) with new permissions");
20:      puts("	-x userid	semctl(IPC_SET) with new userid");
21:      puts("	-y group	semctl(IPC_SET) with new group");
22:      puts("	-d		semctl(IPC_RMID)");
23:      puts("	-g n		semctl(GETVAL) for semaphore n");
24:      puts("	-G		semctl(GETALL)");
25:      puts("	-v n=x		semctl(SETVAL) set semaphore n to x");
26:      puts("	-V m,n,o	semctl(SETALL)");
27:      puts("	-p n		semctl(GETPID) for semaphore n");
28:      puts("	-P		Report semctl(GETPID) for all semaphores");
29:      puts("	-n x		semctl(GETNCNT) for semaphore x");
30:      puts("	-z x		semctl(GETZCNT) for semaphore x");
31:      puts("	-u		No SEM_UNDO (default)");
32:      puts("	-U		Use SEM_UNDO");
33:      puts("	-R		Report SEM_UNDO flags");
34:      puts("
<sops> :");
35:      puts("	<semaphore#>=<semop>[{ u|U} ],...");
36:      puts("where:");
37:      puts("	<semaphore#>	Is the semaphore # (starting from zero)");
38:      puts("	<semop>		Semaphore operation: -n, 0 or +n");
39:      puts("			Negative waits, Postive notifies");
40:      puts("			while zero waits for zero.");
41:      puts("	u		Do not use SEM_UNDO");
42:      puts("	U		Apply SEM_UNDO");
43:      puts("	Example: -o 0=-4U,2=+1u,1=2");
44:  }

That completes the source code listings for the semop utility program.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.218.230