Section 4.5. System V Semaphores


4.5. System V Semaphores

A semaphore, as defined in the dictionary, is a mechanical signaling device or a means of doing visual signaling. The analogy typically used is the railroad mechanism of signaling trains: mechanical arms would swing down to block a train from a section of track that another train was currently using; when the track was free, the arm would swing up and the waiting train could then proceed.

The notion of using semaphores as a means of synchronization in computer software was originated by a Dutch mathematician, E. W. Dijkstra, in 1965. Dijkstra's original work defined two semaphore operations, wait and signal (which correlate nicely with the railroad example). The operations were referred to as P and V operations. The P operation was the wait, which decremented the value of the semaphore if it was greater than zero, and the V operation was the signal, which incremented the semaphore value. The terms P and V originate from the Dutch terms for try and increase. P is from Probeer, which means try or attempt, and V is from Verhoog, which means increase. P(robeer) decreases the semaphore count and V(erhoog) increases the count. (Thanks to henk-jan_van_scherpenseel@stratus.com for sharing that bit of trivia with us.)

Semaphores provide a method of synchronizing access to a sharable resource by multiple processes. They can be used as a binary lock for exclusive access or as a counter; they manage access to a finite number of shared resources, where the semaphore value is initialized to the number of shared resources. Each time a process needs a resource, the semaphore value is decremented. When the process is done with the resource, the semaphore value is incremented. A zero semaphore value conveys to the calling process that no resources are currently available, and the calling process blocks until another process finishes using the resource and frees it.

The semaphore implementation in Solaris (System V semaphores) allows for semaphore sets, meaning that a unique semaphore identifier can contain multiple semaphores. Whether a semaphore identifier contains one semaphore or a set of semaphores is determined when the semget(2) system call creates the semaphore. The second argument to semget(2) determines the number of semaphores that will be associated with the semaphore identifier returned by semget(2). The semaphore system calls allow for some operations on the semaphore set, such that the programmer can make one semctl(2) or semop(2) system call and touch all the semaphores in the semaphore set. This approach makes dealing with semaphore sets programmatically a little easier.

4.5.1. Semaphore Kernel Resources

The tuneable kernel parameters that apply to semaphores are summarized in Table 4.6.

Table 4.6. Semaphore Kernel Tuneables

Name

Default Value

Maximum Value

Description

project.max-sem-ids

128

1<<24

Number of semaphore identifiers

process.max-sem-nsems

512

65536

Maximum number semaphores per identifier

process.max-sem-ops

512

2 billion

Maximum operations per semop(2) call


We next take a closer look at each one and discuss how kernel resources are allocated.

  • project.max-sem-ids. Maximum number of semaphore IDs allowed a project. When semget() allocates a semaphore set, one ID is allocated. If the ID allocation doesn't succeed, semget() fails and errno is set to ENOSPC (previously returned when "The system-imposed limit on the maximum number of allowed semaphores or semaphore identifiers systemwide would be exceeded"). Upon successful semctl(, IPC_RMID), the ID is deallocated.

  • process.max-sem-nsems. Maximum number of semaphores allowed per semaphore set. When semget() allocates a semaphore set, the size of the set is compared with this limit. If the number of semaphores exceeds the limit, semget() fails and errno is set to EINVAL (previously returned when "The nsems argument is ... greater than the system-imposed limit").

  • process.max-sem-ops. Maximum number of semaphore operations allowed per semop call. When semget() successfully allocates a semaphore set, the minimum enforced value of this limit is used to initialize the "system-imposed maximum" number of operations a semop() call for this set can perform.

4.5.2. Kernel Implementation of System V Semaphores

During initialization of the semaphore code, when /kernel/sys/semsys is first loaded, the value of semmni is checked to ensure that it is not greater than the maximum allowable value of 65536 (64 Kbytes). If it is, it gets set to 65536 and prints a console message stating that the value of semmni was too large. Following that, the tuneable parameters, with the exception of semusz, from the /etc/system file are plugged into the internal seminfo data structure.

4.5.3. Semaphore Operations

The creation of a semaphore set by an application requires a call to semget(2). Every semaphore set in the system is described by a semds_id data structure, which contains the following elements.

/*  * Structure Definitions.  */ struct semid_ds {         struct ipc_perm sem_perm;       /* operation permission struct */         struct sem      *sem_base;      /* ptr to first semaphore in set */         ushort_t        sem_nsems;      /* # of semaphores in set */ #if defined(_LP64)         time_t          sem_otime;      /* last semop time */         time_t          sem_ctime;      /* last change time */ #else   /* _LP64 */         time_t          sem_otime;      /* last semop time */         int32_t         sem_pad1;       /* reserved for time_t expansion */         time_t          sem_ctime;      /* last change time */         int32_t         sem_pad2;       /* time_t expansion */ #endif  /* _LP64 */         int             sem_binary;     /* flag indicating semaphore type */         long            sem_pad3[3];    /* reserve area */ };                                                                           See sys/sem.h 


The system checks to see if a semaphore already exists by looking at the key value passed to semget(2) and checks permissions by using the IPC support routine, ipcperm_access(). Semaphore permissions differ slightly from permission modes we're used to seeing in things like Solaris files. They're defined as READ and ALTER, such that processes can either read the current semaphore value or alter it (increment/decrement). Permissions are established with arguments passed to the semget(2) call, following the owner, group, and other conventions used for Solaris file permissions.

Assuming a new semaphore, space is allocated from the resource map pool as needed for the number of semaphores in the set requested, and the elements in the semid_ds data structure are initialized, with the sem_base pointer being set to point to the first semaphore in the set.

Once the semaphore is created, typically the next step is initializing the semaphore values. Initialization is done with the semctl(2) call, using either SETVAL to set the value of each semaphore in the set one at a time (or if there is but one semaphore in the set) or SETALL to set the value of all the semaphores in the set in one operation. The actual kernel flow is relatively straightforward, with the expected permission and value checks against the maximum allowable values and the setting of the user-defined values if everything checks out.

Actual semaphore use by application code involves the semop(2) system call. semop(2) takes the semaphore ID (returned by semget(2)), a pointer to a sembuf structure, and the number of semaphore operations as call arguments. The sembuf structure contains the following elements.

/*  * User semaphore template for semop system calls.  */ struct sembuf {         ushort_t        sem_num;        /* semaphore # */         short           sem_op;         /* semaphore operation */         short           sem_flg;        /* operation flags */ };                                                                           See sys/sem.h 


The programmer must create and initialize the sembuf structure, setting the semaphore number (specifying which semaphore in the set), the operation (more on that in a minute), and the flag. The value of sem_op determines whether the semaphore operation will alter or read the value of a semaphore. A non-zero sem_op value either negatively or positively alters the semaphore value. A zero sem_op value simply reads the current semaphore value.

The semop(2) manual page contains a fairly detailed flow in the DESCRIPTION section on what the operation is for a given sem_op value and a given flag value.




SolarisT Internals. Solaris 10 and OpenSolaris Kernel Architecture
Solaris Internals: Solaris 10 and OpenSolaris Kernel Architecture (2nd Edition)
ISBN: 0131482092
EAN: 2147483647
Year: 2004
Pages: 244

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net