Semaphore Control

The semget system call (Table 7.3) is used to create or gain access to a set of semaphores. The semcti system call allows the user to perform a variety of generalized control operations on the system semaphore structure, on the semaphores as a set, and on individual semaphores. Additional manipulative operations on specific semaphores within a set are covered in the following section on semaphore operations (Section 7.4).

Table 7.3. Summary of the semcti System Call.

<sys/types.h> Manual Section 2

int semctl(int semid, int semnum, int cmd, union semun arg);

Success Failure Sets errno

Return 0 or the value requested -1 Yes

The semcti system call takes four arguments. The first argument, semid, is a valid semaphore identifier that was returned by a previous semget system call. The second argument, semnum, is the number of semaphores in the semaphore set. In most cases, this value is greater than 0 but less than the system limit. However, we will see occasions when the value for semnum is set to 0. These occasions arise when we ask semcti to perform an operation for which the number of semaphores in the set is not relevant. The third argument to semcti, cmd, is an integer command value (usually expressed as one of the symbolic constants found in the header files <sys/ipc.h> or <sys/sem.h>). As discussed in detail in Section 7.3.1, "Semaphore Control Details," the cmd value directs semcti to take one of several control actions. Each action requires specific access permissions to the semaphore control structure (i.e., read or alter). The fourth argument to semcti, arg, is a union of type semun. Given the action specified by

Include File(s)

Summary the preceding cmd argument, the data in arg can be one of any of the following four values:

1. An integer used with SETVAL to indicate a specific value for a particular semaphore within the semaphore set.

2. A reference to a semid_ds structure where information is returned when IPC_STAT or IPC_SET is specified.

3. A reference to an array of type unsigned short integers; the array is used either to initialize the semaphore set (such as when stipulating SETALL) or as a return location when specifying GETALL.

4. A reference to a seminfo structure when IPCJNFO is requested.

In some versions of UNIX the definition of the semun union is found in the include files required by semcti. However, technically the user should define the union. To this end, the manual page for semcti contains the following cryptic reference.

#if defined(_GNU_LIBRARY_) && !defined(_SEM_SEMUN_UNDEFINED)

/* union semun is defined by including <sys/sem.h> 7 #else

/* according to X/OPEN we have to define it ourselves 7 union semun {

intval; /* value for SETVAL */ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET 7 unsigned short int *array; /* array for GETALL, SETALL 7 struct seminfo *_buf; /* buffer for IPCJNFO 7

#endif

This sequence of preprocessor directives determines whether the programmer defines the semun union. If_GNUJJBRARY_has been defined (is nonzero), and

_SEM_SEMUN_UNDEFINED has not been defined, the definition of the union semun is found in the include file <sys/sem.h>. Otherwise, the user defines the union. To be safe, this set of preprocessor directives should be placed at the top any program that will make use of the fourth argument of the semcti call. Its omission may cause the semcti system call to fail, returning the value EFAULT (bad address). Further, when specifying arg as the fourth argument to semcti, the value for arg should be explicitly assigned (e.g., arg.buf=ptr_to_my_structure). This assignment must be done prior to the calling ofsemcti (see Program 7.3).

7.3.1 Semaphore Control Details

The following cmd values cause semcti to act upon the system semaphore structure (semid_ds):

• IPC_STAT— Return the current values of the semid_ds structure for the indicated semaphore identifier. The returned information is stored in a user-generated structure referenced by the fourth argument to semcti. To specify IPC_STAT, the process must have read permission for the semaphore set associated with the semaphore identifier.

• IPC_SET— Modify a restricted number of members in the semid_ds structure. The members sem_perm.uid, sem_perm.gid and sem_perm.mode (in the permissions structure within semid_ds) can be changed if the effective ID of the accessing process is that of the superuser or is the same as the ID value stored in sem_perm.cuid or sem_perm.uid. To make these changes, a structure of the type semid_ds must be allocated. The appropriate members' values are then assigned, and a reference to the modified structure is passed as the fourth argument to the semcti system call.

• IPC_RMID— Remove the semaphore set associated with the semaphore identifier.

When specifying IPC_STAT, IPC_SET, or IPC_RMID, the value for semnum (the number of semaphores in the set) is not considered and can be set to 0.

The following cmd values cause semcti to act upon the entire set of semaphores:

• GETALL— Return the current values of the semaphore set. The values are returned via the array reference passed as the fourth argument to semcti. The user is responsible for allocating the array of the proper size and type prior to passing its address to semcti. Read permission for the semaphore set is required to specify GETALL. When specifying GETALL, the argument semnum is ignored.

• SETALL— Initialize all semaphores in a set to the values stored in the array referenced by the fourth argument to semcti. Again, the user must allocate the initializing array and assign values prior to passing the address of the array to semcti. The process must have alter access for the semaphore set to use SETALL. When specifying SETALL, the sem_ctime member of the system semaphore data structure is updated.

The last set of semcti cmd values acts upon individual semaphores or upon specific members in the semid_ds structure. All of these commands require read permission except for SETVAL, which requires alter permission:

• GETVAL— Return the current value of the individual semaphore referenced by the value of the semnum argument (remember, arrays in C/C++ are zero-based; thus, the first semaphore of a set is at index 0).

• SETVAL— Set the value of the individual semaphore referenced by the semnum argument to the value specified by the fourth argument to semcti (e.g., the value stored in arg.val).

• GETPID— Return the PID from the sem_perm structure within the semid_ds structure.

• GETNCNT— Return the number of processes waiting for the semaphore referenced by the semnum argument to increase in value.

• GETZCNT— Return the number of processes waiting for the semaphore referenced by the semnum argument to become 0.

If semcti is successfully issues any of these commands, the requested integer value is returned: the value of semncnt for GETNCNT, the value of sempid for GETPID, the value of semval for GETVAL, or the value of semzcnt for GETZCNT. If semcti fails, it returns a value of -1 and sets errno to indicate the specific error. The errors returned by semcti with an explanation of their meaning are shown in Table 7.4.

Table 7.4. semctl Error Messages.

# Constant perror Message Explanation

1 EPERM Operation not Value for cmd is IPC_RMID or IPC_SET and the permitted calling process in not the owner or superuser.

13 EACCES Permission The requested operation is not allowed by the denied current access permissions for this process.

14 EFAULT Bad address The fourth argument to semctl contains a reference to an illegal address (the union semun may not have been declared).

22 EINVAL Invalid argument

• The semaphore identifier is invalid.

• The number of semaphores specified is less than 0 or greater than the number in the semaphore set.

• The value for cmd is invalid.

• The value for cmd is IPC_SET, but the value for sem_perm. uid orsem_perm.gid is invalid.

34 ERANGE Numerical result The value for cmd is SETVAL or SETALL, and the out of range value to be assigned is greater than the system maximum or less than 0.

43 EIDRM Identifier Specified semaphore set is marked for removal, removed

Program 7.3 uses the semctl system call to perform a number of semaphore control operations.

Program 7.3 Using semctl.

| Using the semctl system call

| #include <iostream>

+ #include <cstdio>

10 #if defined(_GNU_LIBRARY_) && !defined(_SEM_SEMUN_UNDEFINED)

| intval; //value forSETVAL

+ struct semid_ds *buf; // buffer for IPC_STAT, IPC_SET

| unsigned short int *array; // array for GETALL, SETALL

| struct seminfo *_buf; // buffer for IPCJNFO

20 using namespace std;

| int

I key_t ipc_key;

+ struct semid_ds sem_buf;

| unsigned short int sem_array[NS] = {3, 1, 4};

| union semun arg;

30 if ((semjd = semget(ipc_key, NS, IPC_CREAT | 0660)) == -1) {

| perror("semget: IPC_CREAT | 0660");

| cout« "Semaphore identifier" « sem_id « endl;

| if (semctl(sem_id, 0, IPC_STAT, arg) == -1) {

| perror("semctl: IPC_STAT");

40 cout « "Created " « ctime(&sem_buf.sem_ctime) « endl;

| perror("semctl: SETALL");

| if ((sem_value = semctl(sem_id, i, GETVAL, 0)) == -1) {

| perror("semctl: GETVAL");

| cout « "Semaphore " « i « " has value of" « sem_value « endl;

| perror("semctl: IPC_RMID");

(1) Do we need to define semun union?

(2) Set arg to be the address of the storage for the returned values.

(3) Set arg to be the address of the initializing vector.

Program 7.3 creates a set of three semaphores. The semaphore identifier for the set is printed. In line 35, the address of sem_buf is assigned to the appropriate member of arg. The union arg now contains the location where the returned data will be stored. Then, by specifying IPC_STAT and passing the proper address, semcti obtains the current values of the system semaphore structure. The date and time the semaphore was created are displayed using the library function ctime. Using similar syntax, other members of the semid_ds structure could be displayed. However, there is another way to obtain the entire contents of the semid_ds structure (albeit on a temporary basis). To do this, compile Program 7.3 with the -g option and then use the debugger, gdb, to examine the semid_ds structure. This can be accomplished by invoking gdb with the executable program name, such as iinux$ gdb p7.3. When in gdb, direct gdb to stop at the correct line (say, break40). The program is then run, and when gdb stops at line 40, it is asked to print the contents of the structure using the gdb command: print sem_buf. The output of such a sequence will display the contents of the entire sem_buf structure. On our system, Program 7.3 run in gdb produces the output shown in Figure 7.4:

Figure 7.4 dbx output of Program 7.3.

linux$ gdb p7.3

GNU gdb 5.0rh-5 Red Hat Linux 7.1 Copyright 2001 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions.

There is absolutely no warranty for GDB. Type "show warranty" for details.

This GDB was configured as "¡386-redhat-linux"...

Breakpoint 1 at 0x8048890: file p7.3.cxx, line 40.

Starting program: /home/faculty/gray/revision/07/p7.3 Semaphore identifier 10027013 Breakpoint 1, main () at p7.3.cxx:40

40 cout « "Created " « ctime(&sem_buf.sem_ctime) « endl; Current language: auto; currently C++ (gdb) print sem_buf

$1 = {sem_perm = {_key = 1393917704, uid = 500, gid = 1000, cuid = 500, cgid = 1000, mode = 432,_pad1 = 0,_seq = 306,_pad2 = 0,

_unusedl = 0,_unused2 = 0}, sem_otime = 0,_unusedl = 0, sem_ctime = 1016545082,_unused2 = 0, sem_nsems = 3,_unused3 = 0,

(1) Compile the program with the-g option.

(2) Stop at line 40 of the program.

Notice, as would be expected, that the number of semaphores in the set, three, has been stored in the sem_nsems member.

Program 7.3 uses the semcti system call to initialize the three-semaphore set to the values stored in the array sem_array. Again, notice that prior to calling semcti the address of the initializing vector (see line 41) is assigned to the proper member of arg. Once the values are assigned to the semaphore set, the program uses a loop to display to the screen the value stored in each semaphore. The last action of Program

7.3 is to use the semctl system call with the IPC_RMID flag to remove the semaphore

When run outside of gdb, the output of Program 7.3 should be similar to that shown in Figure 7.5.

Figure 7.5 Output of Program 7.3.

Iinux$ p7.3

Semaphore identifier 10027013 Created Tue Mar 19 08:38:02 2002

Semaphore 0 has value of 3 Semaphore 1 has value of 1 Semaphore 2 has value of 4

Continue reading here: Exercise

Was this article helpful?

0 0