Shared Memory Control

The shmctl system call permits the user to perform a number of generalized control operations on an existing shared memory segment and on the system shared memory data structure (see Table 8.4).

Table 8.4. Summary of the shmctl System Call.

Include File(s)

 

Manual Section

2

Summary

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

Return

Success

Failure

Sets errno

-1

Yes

There are three arguments for the shmctl system call. The first, shmid , is a valid shared memory segment identifier generated by a prior shmget system call. The second argument, cmd , specifies the operation shmctl is to perform. The third argument, buf , is a reference to a structure of the type shmid_ds .

The operations that shmctl will perform, which are specified by the following defined constants, consist of

If shmctl is successful, it returns a value of 0; otherwise , it returns a value of -1 and sets the value in errno to indicate the specific error condition. The values that errno may be assigned and their interpretation are shown in Table 8.5.

Table 8.5. shmctl Error Messages

#

Constant

perror Message

Explanation

1

EPERM

Operation not permitted

  • The value for cmd is IPC_RMID or IPC_SET, and the calling process is not the owner, creator, or superuser.
  • The value for cmd is SHM_LOCK or SHM_UNLOCK, and the calling process is not the superuser.

13

EACCES

Permission denied

The requested operation is not allowed by current access permissions.

12

ENOMEM

Cannot allocate memory

The cmd is SHM_LOCK, but there is insufficient memory available.

14

EFAULT

Bad address

The third argument to shmctl , buf , contains a reference to an illegal address.

22

EINVAL

Invalid argument

  • The shared memory identifier is invalid.
  • The value for cmd is invalid.
  • The value for cmd is IPC_SET, but the value for shm_perm.uid or shm_perm.gid is invalid.

43

EIDRM

 

Memory segment is marked as removed.

EXERCISE

Justin could not understand all the brouhaha over shared memory. Why not, he reasoned, just use variables that were global to say parent/child processes and control their access with semaphores? Using the SSemaphore object from the previous chapter, he wrote the program below to test his theory:

File : justin.cxx #include #include #include #include "SSemaphore.h" + using namespace std; char c = 0; // 'global' variable int main( ){ SSemaphore S; // SSemaphore object 10 S.Put(1); // Start it at 1 switch(fork( )){ case -1: perror("fork failure"); return 1; + case 0: // Child - lowercase srand(getpid( )); for (int i=0; i < 10; ++i){ S.P( ); // Obtain semaphore cout << char(c+'a'); cout.flush( ); 20 ++c; S.V( ); // Release semaphore sleep(rand( ) % 3 + 1); } break; + default: // Parent - uppercase srand(getpid( )); for (int i=0; i < 10; ++i){ S.P( ); // Obtain semaphore cout << char(c+'A'); cout.flush( ); 30 ++c; S.V( ); // Release semaphore sleep(rand( ) % 3 + 1); } break; + } wait(0); return 0; }

Before he ran his program, Justin expected his output to be similar to AbcDefGhiJ (ten characters with alternating case). He was quite taken back when his output looked more like the following: AabBcCdDeEFfGgHhIiJj . Why did Justin get the output he didwhat was the flaw in his reasoning?

Категории