[ Pobierz całość w formacie PDF ]
IPC RMID
Removes the set from the kernel.
GETALL
Used to obtain the values of all semaphores in a set. The integer values are stored in
an array of unsigned short integers pointed to by the array member of the union.
GETNCNT
Returns the number of processes currently waiting for resources.
GETPID
Returns the PID of the process which performed the last semop call.
GETVAL
Returns the value of a single semaphore within the set.
GETZCNT
Returns the number of processes currently waiting for 100% resource utilization.
SETALL
Sets all semaphore values with a set to the matching values contained in the array
member of the union.
SETVAL
Sets the value of an individual semaphore within the set to the val member of the
union.
The arg argument represents an instance of type semun. This particular union is
declared inlinux/sem.has follows:
/* arg for semctl system calls. */
union semun {
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */
ushort *array; /* array for GETALL & SETALL */
struct seminfo *__buf; /* buffer for IPC_INFO */
void *__pad;
};
val
Used when the SETVAL command is performed. Specifies the value to set the
semaphore to.
buf
Used in the IPC STAT/IPC SET commands. Represents a copy of the internal
semaphore data structure used in the kernel.
array
A pointer used in the GETALL/SETALL commands. Should point to an array of
integer values to be used in setting or retrieving all semaphore values in a set.
6.4. SYSTEM V IPC 53
The remaining arguments buf and pad are used internally in the semaphore code
within the kernel, and are of little or no use to the application developer. As a matter of
fact, these two arguments are specific to the Linux operating system, and are not found in
other UNIX implementations.
Since this particular system call is arguably the most difficult to grasp of all the System
V IPC calls, we ll examine multiple examples of it in action.
The following snippet returns the value of the passed semaphore. The final argument
(the union) is ignored when the GETVAL command is used:
int get_sem_val( int sid, int semnum )
{
return( semctl(sid, semnum, GETVAL, 0));
}
To revisit the printer example, let s say the status of all five printers was required:
#define MAX_PRINTERS 5
printer_usage()
{
int x;
for(x=0; x
printf("Printer %d: %d\n\r", x, get_sem_val( sid, x ));
}
Consider the following function, which could be used to initialize a new semaphore
value:
void init_semaphore( int sid, int semnum, int initval)
{
union semun semopts;
semopts.val = initval;
semctl( sid, semnum, SETVAL, semopts);
}
Note that the final argument of semctl is a copy of the union, rather than a pointer to it.
While we re on the subject of the union as an argument, allow me to demonstrate a rather
common mistake when using this system call.
Recall from the msgtool project that the IPC STAT and IPC SET commands were used
to alter permissions on the queue. While these commands are supported in the semaphore
implementation, their usage is a bit different, as the internal data structure is retrieved and
copied from a member of the union, rather than as a single entity. Can you locate the bug
in this code?
/* Required permissions should be passed in as text (ex: "660") */
void changemode(int sid, char *mode)
{
int rc;
struct semid_ds mysemds;
54 CHAPTER 6. LINUX INTERPROCESS COMMUNICATIONS
/* Get current values for internal data structure */
if((rc = semctl(sid, 0, IPC_STAT, semopts)) == -1)
{
perror("semctl");
exit(1);
}
printf("Old permissions were %o\n", semopts.buf->sem_perm.mode);
/* Change the permissions on the semaphore */
sscanf(mode, "%o", &semopts.buf->sem_perm.mode);
/* Update the internal data structure */
semctl(sid, 0, IPC_SET, semopts);
printf("Updated...\n");
}
The code is attempting to make a local copy of the internal data structure for the set,
modify the permissions, and IPC SET them back to the kernel. However, the first call to
semctl promptly returns EFAULT, or bad address for the last argument (the union!). In
addition, if we hadn t checked for errors from that call, we would have gotten a memory
fault. Why?
Recall that the IPC SET/IPC STAT commands use the buf member of the union, which
is a pointer to a type semid ds. Pointers are pointers are pointers are pointers! The buf
member must point to some valid storage location in order for our function to work prop-
erly. Consider this revamped version:
void changemode(int sid, char *mode)
{
int rc;
struct semid_ds mysemds;
/* Get current values for internal data structure */
/* Point to our local copy first! */
semopts.buf = &mysemds;
/* Let s try this again! */
if((rc = semctl(sid, 0, IPC_STAT, semopts)) == -1)
{
perror("semctl");
exit(1);
}
printf("Old permissions were %o\n", semopts.buf->sem_perm.mode);
/* Change the permissions on the semaphore */
sscanf(mode, "%o", &semopts.buf->sem_perm.mode);
/* Update the internal data structure */
semctl(sid, 0, IPC_SET, semopts);
6.4. SYSTEM V IPC 55
[ Pobierz całość w formacie PDF ]