|
|
``semctl system call example'' is a menu-driven program. It allows all possible combinations of using the semctl system call to be exercised.
From studying this program, you can observe the method of passing arguments and receiving return values. The user-written program requirements are pointed out.
This program begins (lines 5-9) by including the required header files as specified by the semctl(2) manual page. Note that in this program errno is declared as an external variable, and therefore the sys/errno.h header file does not have to be included.
Variable, structure, and union names have been
chosen to be as close as possible to
those in the synopsis.
Their declarations are self explanatory.
These names
make the program more readable and are perfectly
valid since they are local to the program.
The variables declared for this program and what they are used for are as follows:
Note that the semid_ds data structure in this program (line 14) uses the data structure located in the sys/sem.h header file of the same name as a template for its declaration.
Note that the semvals array is declared to have 25 elements (0 through 24). This number corresponds to the maximum number of semaphores allowed per set (SEMMSL), a system-tunable parameter.
Now that all of the required declarations have been presented for this program, this is how it works.
First, the program prompts for a valid semaphore set identifier, which is stored in the semid variable (lines 24-26). This is required for all semctl system calls.
Then, the code for the desired control command must be entered (lines 17-42), and the code is stored in the cmd variable. The code is tested to determine the control command for subsequent processing.
If the GETVAL control command is selected (code 1), a message prompting for a semaphore number is displayed (lines 48, 49). When it is entered, it is stored in the semnum variable (line 50). Then, the system call is performed, and the semaphore value is displayed (lines 51-54). Note that the arg argument is not required in this case, and the system call will simply ignore it. If the system call is successful, a message indicates this along with the semaphore set identifier used (lines 197, 198); if the system call is unsuccessful, an error message is displayed along with the value of the external errno variable (lines 194, 195).
If the SETVAL control command is selected (code 2), a message prompting for a semaphore number is displayed (lines 55, 56). When it is entered, it is stored in the semnum variable (line 57). Next, a message prompts for the value to which the semaphore is to be set; it is stored as the arg.val member of the union (lines 58, 59). Then, the system call is performed (lines 60, 62). Depending upon success or failure, the program returns the same messages as for GETVAL above.
If the GETPID control command is selected (code 3), the system call is made immediately since all required arguments are known (lines 63-66), and the PID of the process performing the last operation is displayed. Note that the arg argument is not required in this case, and the system call will simply ignore it. Depending upon success or failure, the program returns the same messages as for GETVAL above.
If the GETNCNT control command is selected (code 4), a message prompting for a semaphore number is displayed (lines 67-71). When entered, it is stored in the semnum variable (line 73). Then, the system call is performed and the number of processes waiting for the semaphore to become greater than its current value is displayed (lines 73-76). Note that the arg argument is not required in this case, and the system call will simply ignore it. Depending upon success or failure, the program returns the same messages as for GETVAL above.
If the GETZCNT control command is selected (code 5), a message prompting for a semaphore number is displayed (lines 77-80). When it is entered, it is stored in the semnum variable (line 81). Then the system call is performed and the number of processes waiting for the semaphore value to become equal to zero is displayed (lines 82-85). Depending upon success or failure, the program returns the same messages as for GETVAL above.
If the GETALL control command is selected (code 6), the program first performs an IPC_STAT control command to determine the number of semaphores in the set (lines 87-93). The length variable is set to the number of semaphores in the set (line 93). The arg.array union member is set to point to the semvals array where the system call is to store the values of the semaphore set (line 96). Now, a loop is entered which displays each element of the arg.array from zero to one less than the value of length (lines 98-104). The semaphores in the set are displayed on a single line, separated by a space. Depending upon success or failure, the program returns the same messages as for GETVAL above.
If the SETALL control command is selected (code 7), the program first performs an IPC_STAT control command to determine the number of semaphores in the set (lines 107-110). The length variable is set to the number of semaphores in the set (line 113). Next, the program prompts for the values to be set and enters a loop which takes values from the keyboard and initializes the semvals array to contain the desired values of the semaphore set (lines 115-121). The loop puts the first entry into the array position for semaphore number zero and ends when the semaphore number that is filled in the array equals one less than the value of length. The arg.array union member is set to point to the semvals array from which the system call is to obtain the semaphore values. The system call is then made (lines 122-125). Depending upon success or failure, the program returns the same messages as for GETVAL above.
If the IPC_STAT control command is selected (code 8), the system call is performed (line 129), and the status information returned is printed out (lines 130-141); only the members that can be set are printed out in this program. Note that if the system call is unsuccessful, the status information of the last successful one is printed out. In addition, an error message is displayed, and the errno variable is printed out (line 194).
If the IPC_SET control command is selected (code 9), the program gets the current status information for the semaphore set identifier specified (lines 145-149). This is necessary because this example program provides for changing only one member at a time, and the semctl system call changes all of them. Also, if an invalid value happened to be stored in the user memory area for one of these members, it would cause repetitive failures for this control command until corrected. The next thing the program does is to prompt for a code corresponding to the member to be changed (lines 150-156). This code is stored in the choice variable (line 157). Now, depending upon the member picked, the program prompts for the new value (lines 158-181). The value is placed into the appropriate member in the user memory area data structure, and the system call is made (line 184). Depending upon success or failure, the program returns the same messages as for GETVAL above.
If the IPC_RMID control command (code 10) is selected, the system call is performed (lines 186-188). The semaphore set identifier along with its associated data structure and semaphore set is removed from the UNIX operating system. Depending upon success or failure, the program returns the same messages as for the other control commands.
The example program for the semctl system call follows. We suggest that you name the source program file semctl.c and the executable file semctl.
1 /*This is a program to illustrate 2 *the semaphore control, semctl(), 3 *system call capabilities. 4 */5 /*Include necessary header files.*/ 6 #include <stdio.h> 7 #include <sys/types.h> 8 #include <sys/ipc.h> 9 #include <sys/sem.h>
10 /*Start of main C language program*/ 11 main() 12 { 13 extern int errno; 14 struct semid_ds semid_ds; 15 int c, i, length; 16 int uid, gid, mode; 17 int retrn, semid, semnum, cmd, choice; 18 ushort semvals[25]; 19 union semun { 20 int val; 21 struct semid_ds *buf; 22 ushort *array; 23 } arg;
24 /*Enter the semaphore ID.*/ 25 printf("Enter the semid = "); 26 scanf("%d", &semid);
27 /*Choose the desired command.*/ 28 printf("\nEnter the number for\n"); 29 printf("the desired cmd:\n"); 30 printf("GETVAL = 1\n"); 31 printf("SETVAL = 2\n"); 32 printf("GETPID = 3\n"); 33 printf("GETNCNT = 4\n"); 34 printf("GETZCNT = 5\n"); 35 printf("GETALL = 6\n"); 36 printf("SETALL = 7\n"); 37 printf("IPC_STAT = 8\n"); 38 printf("IPC_SET = 9\n"); 39 printf("IPC_RMID = 10\n"); 40 printf("Entry = "); 41 scanf("%d", &cmd);
42 /*Check entries.*/ 43 printf ("\nsemid =%d, cmd = %d\n\n", 44 semid, cmd);
45 /*Set the command and do the call.*/ 46 switch (cmd) 47 {
48 case 1: /*Get a specified value.*/ 49 printf("\nEnter the semnum = "); 50 scanf("%d", &semnum); 51 /*Do the system call.*/ 52 retrn = semctl(semid, semnum, GETVAL, arg); 53 printf("\nThe semval = %d", retrn); 54 break; 55 case 2: /*Set a specified value.*/ 56 printf("\nEnter the semnum = "); 57 scanf("%d", &semnum); 58 printf("\nEnter the value = "); 59 scanf("%d", &arg.val); 60 /*Do the system call.*/ 61 retrn = semctl(semid, semnum, SETVAL, arg); 62 break; 63 case 3: /*Get the process ID.*/ 64 retrn = semctl(semid, 0, GETPID, arg); 65 printf("\nThe sempid = %d", retrn); 66 break; 67 case 4: /*Get the number of processes 68 waiting for the semaphore to 69 become greater than its current 70 value.*/ 71 printf("\nEnter the semnum = "); 72 scanf("%d", &semnum); 73 /*Do the system call.*/ 74 retrn = semctl(semid, semnum, GETNCNT, arg); 75 printf("\nThe semncnt = %d", retrn); 76 break;
77 case 5: /*Get the number of processes 78 waiting for the semaphore 79 value to become zero.*/ 80 printf("\nEnter the semnum = "); 81 scanf("%d", &semnum); 82 /*Do the system call.*/ 83 retrn = semctl(semid, semnum, GETZCNT, arg); 84 printf("\nThe semzcnt = %d", retrn); 85 break;
86 case 6: /*Get all of the semaphores.*/ 87 /*Get the number of semaphores in 88 the semaphore set.*/ 89 arg.buf = & semid_ds; 90 retrn = semctl(semid, 0, IPC_STAT, arg); 91 if(retrn == -1) 92 goto ERROR; 93 length = arg.buf->sem_nsems; 94 /*Get and print all semaphores in the 95 specified set.*/ 96 arg.array = semvals; 97 retrn = semctl(semid, 0, GETALL, arg); 98 for (i = 0; i < length; i++) 99 { 100 printf("%d", semvals[i]); 101 /*Separate each 102 semaphore.*/ 103 printf(" "); 104 } 105 break;
106 case 7: /*Set all semaphores in the set.*/ 107 /*Get the number of semaphores in 108 the set.*/ 109 arg.buf = & semid_ds; 110 retrn = semctl(semid, 0, IPC_STAT, arg); 111 if(retrn == -1) 112 goto ERROR; 113 length = arg.buf->sem_nsems; 114 printf("Length = %d\n", length); 115 /*Set the semaphore set values.*/ 116 printf("\nEnter each value:\n"); 117 for(i = 0; i < length ; i++) 118 { 119 scanf("%d", &c); 120 semvals[i] = c; 121 } 122 /*Do the system call.*/ 123 arg.array = semvals; 124 retrn = semctl(semid, 0, SETALL, arg); 125 break;
126 case 8: /*Get the status for the semaphore set.*/ 127 /*Get and print the current status values.*/ 128 arg.buf = & semid_ds; 129 retrn = semctl(semid, 0, IPC_STAT, arg); 130 printf ("\nThe USER ID = %d\n", 131 arg.buf->sem_perm.uid); 132 printf ("The GROUP ID = %d\n", 133 arg.buf->sem_perm.gid); 134 printf ("The operation permissions = 0%o\n", 135 arg.buf->sem_perm.mode); 136 printf ("The number of semaphores in set = %d\n", 137 arg.buf->sem_nsems); 138 printf ("The last semop time = %d\n", 139 arg.buf->sem_otime); 140 printf ("The last change time = %d\n", 141 arg.buf->sem_ctime); 142 break;
143 case 9: /*Select and change the desired 144 member of the data structure.*/ 145 /*Get the current status values.*/ 146 arg.buf = & semid_ds; 147 retrn = semctl(semid, 0, IPC_STAT, arg.buf); 148 if(retrn == -1) 149 goto ERROR; 150 /*Select the member to change.*/ 151 printf("\nEnter the number for the\n"); 152 printf("member to be changed:\n"); 153 printf("sem_perm.uid = 1\n"); 154 printf("sem_perm.gid = 2\n"); 155 printf("sem_perm.mode = 3\n"); 156 printf("Entry = "); 157 scanf("%d", &choice); 158 switch(choice){
159 case 1: /*Change the user ID.*/ 160 printf("\nEnter USER ID = "); 161 scanf ("%d", &uid); 162 arg.buf->sem_perm.uid = uid; 163 printf("\nUSER ID = %d\n", 164 arg.buf->sem_perm.uid); 165 break;
166 case 2: /*Change the group ID.*/ 167 printf("\nEnter GROUP ID = "); 168 scanf("%d", &gid); 169 arg.buf->sem_perm.gid = gid; 170 printf("\nGROUP ID = %d\n", 171 arg.buf->sem_perm.gid); 172 break;
173 case 3: /*Change the mode portion of 174 the operation 175 permissions.*/ 176 printf("\nEnter MODE in octal = "); 177 scanf("%o", &mode); 178 arg.buf->sem_perm.mode = mode; 179 printf("\nMODE = 0%o\n", 180 arg.buf->sem_perm.mode); 181 break; 182 default: /* Invalid Input */ 183 exit(-1); 184 } 185 /*Do the change.*/ 186 retrn = semctl(semid, 0, IPC_SET, arg); 187 break; 188 case 10: /*Remove the semid along with its 189 data structure.*/ 190 retrn = semctl(semid, 0, IPC_RMID, arg); 191 break; 192 default: /* Invalid Input */ 193 exit(-1); 194 } 195 /*Perform the following if the call is unsuccessful.*/ 196 if(retrn == -1) 197 { 198 ERROR: 199 printf ("\nThe semctl call failed!, error number = %d\n", errno); 200 exit(0); 201 } 202 printf ("\n\nThe semctl system call was successful\n"); 203 printf ("for semid = %d\n", semid); 204 exit (0); 205 }
semctl system call example