Signal lamp
Zheng yanxing
Mlinux@163.com
National Defense Emy of Computer Science
Introduction:
The traffic signal is not the same as that of other processes. It mainly provides resource access control for inter-process sharing. It is equivalent to a memory flag. A process can determine whether it can access some shared resources. At the same time, the process can modify the flag. In addition to access control, it can also be used for process synchronization.
Label of this article:
Signal lamp
, Kernel
, Encoding
Mark this article!
Release date:
April 07, 2003
Level:
Elementary
Access status
4266 views
Suggestion:
0 (add comments
)
Average score (7 in total)
I. Traffic Signal Overview
The traffic signal is not the same as that of other processes. It mainly provides resource access control for inter-process sharing. It is equivalent to a memory flag. A process can determine whether it can access some shared resources. At the same time, the process can modify the flag. In addition to access control, it can also be used for process synchronization. There are two types of traffic signals:
- Binary signal light: the simplest form of signal light. The signal light value can only be 0 or 1, similar to mutex lock.
Note: the binary signal lamp can implement the mutex lock function, but the two have different concerns. The signal lamp emphasizes shared resources. As long as the shared resources are available, other processes can also modify the signal lamp value. The mutex also emphasizes the process. After resources are used by the process, it must be unlocked by the process itself.
- Computing traffic signal: the traffic signal value can be any non-negative value (of course, subject to the kernel constraints ).
Back to Top
Ii. Linux traffic signals
Linux supports traffic signals in the same way as message queue. In Red had 8.0 release, the traffic signals of System V are supported. Therefore, this article mainly introduces the system V signal lamp and its corresponding APIs. If there is no declaration, the System V signal lights are described below.
Note that the System V signal lamp usually refers to the Count signal lamp set.
Back to Top
3. Signal lights and Kernel
1. The System V traffic signal is continuously maintained with the kernel. This traffic signal set will be deleted only when the kernel restarts or is displayed and deleted. Therefore, the data structure (struct ipc_ids sem_ids) of the recorded signal lights in the system is located in the kernel. All the signal lights in the system can find the access entry in the structure sem_ids.
2. Explain how the kernel is connected with the signal light:
Here, struct ipc_ids sem_ids is the global data structure of the signal lamp recorded in the kernel. It describes a specific signal lamp and its related information.
The structure of struct SEM is as follows:
struct sem{int semval;// current valueint sempid// pid of last operation} |
We can see that the global data structure struct ipc_ids sem_ids can access struct.
The first member of kern_ipc_perm: struct kern_ipc_perm; each struct
Kern_ipc_perm can correspond to a specific traffic signal because there is a key_t member key in the structure, and the key uniquely identifies a traffic signal set. At the same time, the structure
Struct
Sem_nsems, the last member of kern_ipc_perm, determines the sequence of the signal in the signal set so that the kernel can record the information of each signal.
For the kern_ipc_perm structure, see inter-process communication in Linux (3): Message queue. For struct sem_array, see Appendix 1.
Back to Top
Iv. Operation signal lights
There are three types of Message Queue operations:
1. Enable or create a signal light
It is basically the same as creating and opening a message queue.
2. Traffic Signal Value operation
In Linux, you can increase or decrease the traffic signal value, and release and occupy shared resources accordingly. For more information, see semop system call.
3. Obtain or set the traffic signal properties:
Each traffic signal set in the system corresponds to a struct sem_array structure, which records various information of the traffic signal set and exists in the system space. In order to set and obtain various information and attributes of the traffic signal set, there is an important joint structure in the user space, that is, Union semun.
For the meanings of the members of the combined semun data structure, see appendix 2.
Signal lamp API
1. file name to key value
#include <sys/types.h>#include <sys/ipc.h>key_t ftok (char*pathname, char proj); |
It returns a key value corresponding to the path pathname. For specific usage, see inter-process communication in Linux (3): Message queue.
2. Linux-specific IPC () call:
Int IPC (unsigned int call, int first, int second, int third, void * PTR, long second th );
When the call parameter is set to a different value, the three system calls of the corresponding signal are as follows:
When the call is semop, the corresponding int semop (INT Semid, struct sembuf * SOPs, unsigned nsops) call;
When the call is semget, the corresponding int semget (key_t key, int nsems, int semflg) call;
When the call is semctl, the corresponding int semctl (INT Semid, int semnum, int cmd, Union semun Arg) call;
These calls will be described later.
Note: I do not advocate using the system to call IPC (), but prefer to use the System V or POSIX inter-process communication API. Cause: inter-process communication in Linux (3) is provided in message queue.
3. System V signal lamp API
There are only three System V Message Queue APIs, which must contain several header files:
#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h> |
1) int semget (key_t key, int nsems, int semflg)
The parameter key is a key value obtained by ftok and uniquely identifies a traffic signal set. Its usage is the same as the key in msgget (). The nsems parameter specifies whether to enable or create a traffic signal set
The number of signal lights. The semflg parameter is a flag. Parameter key and semflg values, and when to enable an existing traffic signal set or create a new traffic signal set and
The corresponding part in msgget () is the same and will not be described here.
This call returns the signal set description corresponding to the key.
Call and return: The Signal Set description is returned. Otherwise,-1 is returned.
Note: If the signal lamp represented by the key already exists and semget specifies ipc_creat | ipc_excl, even if the nsems parameter is different from the number of the original signal lamp
The returned value is also an eexist error. If semget only specifies the ipc_creat flag, the nsems parameter must be the same as the original value, and further steps must be performed in subsequent program instances.
Description.
2) int semop (INT Semid, struct sembuf * SOPs, unsigned nsops );
Semid is the Signal Set ID, and SOPs points to each sembuf structure of the array to depict an operation on a specific signal. Nsops is the size of the SOPs pointing to the array.
The sembuf structure is as follows:
struct sembuf {unsigned short sem_num;/* semaphore index in array */shortsem_op;/* semaphore operation */shortsem_flg;/* operation flags */}; |
Sem_num corresponds to the signal light in the signal set, and 0 corresponds to the first signal light. Sem_flg can be ipc_nowait and sem_undo. For example
If the sem_undo flag is set, the corresponding operation will be canceled at the end of the process, which is an important flag. If this flag is set, the system will return if the shared resource is not released by the process.
The kernel is released. If this flag is set for a traffic signal, the kernel will allocate a sem_undo structure to record it, in order to ensure that future resources can be safely released. In fact
But the traffic signal value has not changed. The traffic signal value does not reflect the actual resource occupation. In this case, the problem is solved by the kernel. This
It is a bit like a zombie process. Although the process exits and the resources are released, its records still exist in the kernel table. In this case, the parent process needs to call waitpid to solve the problem.
The sem_op value is greater than 0, equal to 0, and less than 0. Three operations are performed on the signal lamp specified by sem_num. For details, refer to the corresponding Linux manual page.
It should be emphasized that semop operates multiple signal lights at the same time. In actual application, it applies for or releases multiple resources. This is especially important when semop ensures the atomicity of operations. Especially for multiple types of resources
For the source application, you can either get all resources at a time, or give up the application, or continue to wait without occupying any resources. In this way, the waste of resources is avoided, avoid
The application for shared resources causes a deadlock.
These operations may be better understood from the actual meaning: the current value of the signal lamp records the current available number of resources; sem_op> 0 corresponds to the process to release the shares of the number of sem_op
Source; sem_op = 0 can be used to test whether shared resources are used up; sem_op <0 is equivalent to the process requesting-sem_op shared resources. Think about the atomicity of operations, let alone
It is hard to understand when the system calls normal response and sleep wait.
Call return: 0 is returned if the call is successful. Otherwise,-1 is returned.
3) int semctl (INT Semid, int semnum, int cmd, Union semun Arg)
The system calls various control operations on traffic signals. The Semid parameter specifies the traffic signal set, and the CMD parameter specifies the specific operation type. The semnum parameter specifies the traffic signal to operate on, only a few special cmd operations are meaningful; Arg is used to set or return signal light information.
For more information about the system call, see the manual page. Only the operation that can be specified by the CMD parameter is provided here.
Ipc_stat |
Obtains the signal light information, which is returned by Arg. Buf; |
Ipc_set |
Set the traffic signal information. The information to be set is saved in Arg. Buf (which information can be set in manpage ); |
Getall |
Returns the values of all traffic signals. The results are saved in Arg. array, and the parameter sennum is ignored; |
Getncnt |
Return the number of processes that increase when the value of the waiting semnum represents the signal lamp, which is equivalent to the number of processes that are currently waiting for the shared resources represented by the signal lamp represented by the semnum; |
Getpid |
Returns the ID of the last process that performs the semop operation on the signal lamp represented by semnum; |
Getval |
Returns the value of the signal lamp represented by semnum; |
Getzcnt |
Returns the number of processes that wait for semnum to change the value of the signal lamp to 0; |
Setall |
Update the values of all traffic signals through Arg. array. At the same time, update the sem_ctime Member of the semid_ds structure related to the current signal set; |
Setval |
Set the value of the signal lamp represented by semnum to Arg. Val; |
Call return:-1 is returned if the call fails. If the call succeeds, it is related to cmd:
CMD |
Return Value |
Getncnt |
Semncnt |
Getpid |
Sempid |
Getval |
Semval |
Getzcnt |
Semzcnt |
Back to Top
5. Restrictions on Traffic Signals
1. semopm is the number of signals that the system can simultaneously operate on when calling semop. If the nsops parameter in semop exceeds this number, the e2big error will be returned. Semopm size is specific to the system, and RedHat 8.0 is 32.
2. Maximum number of traffic signals: semvmx. If the traffic signal value exceeds this limit, an erange error is returned. In RedHat 8.0, this value is 32767.
3. the maximum number of semmni signal sets in the system range and the maximum number of semmns signals in the system range. If these two limits are exceeded, an enospc error is returned. In RedHat 8.0, this value is 32000.
4. the maximum number of semmsl signals in each traffic signal set. The value of RedHat 8.0 is 250.
Semopm and semvmx should be noted when using semop; semmni and semmns should be noted when calling semget. Semvmx is also worth noting when calling semctl.
Back to Top
Vi. competitive issues
The first process to create a signal lamp also initializes the signal lamp. In this way, the system calls semget and involves two steps: creating a signal lamp and initializing a signal lamp. This may cause
Competition status: when the first process to create a signal lamp is initializing the signal lamp, the second process calls semget and finds that the signal lamp already exists. At this time, the second process must have a positive
The ability to initialize traffic signals. In reference [1], we provide a method to bypass this competition: When semget creates a new signal light, the semid_ds
The value of the sem_otime Member after Initialization is 0. Therefore, after the second process successfully calls semget, you can use the ipc_stat command to call semctl again.
When sem_otime is changed to a non-0 value, you can determine that the signal has been initialized. Describes the competition status generation and solution:
In fact, this solution is based on the assumption that the first process that creates a traffic signal must call semop so that sem_otime can be changed to a non-zero value. In addition, because the first process may not call semop, or the semop operation takes a long time, the second process may wait for an indefinite period of time, or wait for a long time.
Back to Top
VII. Traffic Signal Application Example
This instance has two purposes: 1. To obtain information about various traffic signals; 2. To use traffic signals to apply for and release shared resources. Detailed comments are provided in the program.
# Include <Linux/SEM. h> # include <stdio. h> # include <errno. h> # define sem_path "/Unix/my_sem" # define max_tries 3 int Semid; Main () {int flag1, flag2, key, I, init_ OK, tmperrno; struct semid_ds sem_info; struct seminfo sem_info2; Union semun ARG; // Union semun: See Appendix 2 struct sembuf askfor_res, free_res; flag1 = ipc_creat | ipc_excl | 00666; flag2 = ipc_creat | 00666; key = ftok (sem_path, 'A'); // error handling for ftok here; init_o K = 0; Semid = semget (Key, 1, flag1); // create a semaphore set that only includes des one semphore. if (Semid <0) {tmperrno = errno; perror ("semget"); If (tmperrno = eexist) // errno is undefined after a successful Library call (including perror call) // so it is saved in tmperrno. {Semid = semget (Key, 1, flag2); // flag2 only contains the ipc_creat sign. The parameter nsems (1 here) must be consistent with the number of original signal lights Arg. buf = & sem_info; for (I = 0; I <max_tries; I ++) {If (semctl (SE Mid, 0, ipc_stat, ARG) =-1) {perror ("semctl error"); I = max_tries;} else {If (Arg. Buf-> sem_otime! = 0) {I = max_tries; init_ OK = 1;} else sleep (1) ;}} if (! Init_ OK) // do some initializing, here we assume that the first process that creates the SEM // will finish initialize the SEM and run semop in max_tries * 1 seconds. else it will // not run semop any more. {Arg. val = 1; if (semctl (Semid, 0, setval, ARG) =-1) perror ("semctl setval error") ;}} else {perror ("semget error, process exit "); exit () ;}} else // Semid> = 0; do some initializing {Arg. val = 1; if (semctl (Semid, 0, setval, ARG) =-1) perror ("semctl setval error ");} // get some information about the semaphore and the limit of semaphore in redhat8.0 Arg. buf = & sem_info; If (semctl (Semid, 0, ipc_stat, ARG) =-1) perror ("semctl IPC stat "); printf ("Owner's uid is % d/N", Arg. buf-> sem_perm.uid); printf ("Owner's GID is % d/N", Arg. buf-> sem_perm.gid); printf ("creater's uid is % d/N", Arg. buf-> sem_perm.cuid); printf ("creater's GID is % d/N", Arg. buf-> sem_perm.cgid); arg. _ Buf = & sem_info2; If (semctl (Semid, 0, ipc_info, ARG) =-1) perror ("semctl ipc_info "); printf ("the number of entries in semaphore map is % d/N", Arg. _ Buf-> semmap); printf ("Max number of semaphore identifiers is % d/N", Arg. _ Buf-> semmni); printf ("Mas Number of semaphores in system is % d/N", Arg. _ Buf-> semmns); printf ("the number of Undo structures system wide is % d/N", Arg. _ Buf-> semmnu); printf ("Max number of semaphores per Semid is % d/N", Arg. _ Buf-> semmsl); printf ("Max number of OPS per semop call is % d/N", Arg. _ Buf-> semopm); printf ("Max number of Undo entries per process is % d/N", Arg. _ Buf-> semume); printf ("the sizeof of struct sem_undo is % d/N", Arg. _ Buf-> semusz); printf ("the maximum semaphore value is % d/N", Arg. _ Buf-> semvmx); // now ask for available resource: askfor_res.sem_num = 0; region =-1; region = sem_undo; If (semop (Semid, & askfor_res, 1) =-1) // ask for resource perror ("semop error"); sleep (3); // do some handling on the sharing resource here, just sleep on it 3 seconds printf ("now free the resource/N"); // now free resource free_res.sem_num = 0; free_res.sem_op = 1; free_res.sem_flg = sem_undo; if (semop (Semid, & free_res, 1) =-1) // free the resource. if (errno = eidrm) printf ("the semaphore set was removed/N"); // you can comment out the codes below to compile a different version: if (semctl (Semid, 0, ipc_rmid) =-1) perror ("semctl ipc_rmid"); else printf ("Remove sem OK/N ");} |
Note: You can try to comment out the initialization steps, what will happen to the process during running (the process will sleep when applying for resources), and the comments at the end of the program, compile the program into two different versions. The following is the running result of the Program (operating system redhat8.0 ):
owner's uid is 0owner's gid is 0creater's uid is 0creater's gid is 0the number of entries in semaphore map is 32000 max number of semaphore identifiers is 128 mas number of semaphores in system is 32000 the number of undo structures system wide is 32000 max number of semaphores per semid is 250 max number of ops per semop call is 32 max number of undo entries per process is 32 the sizeof of struct sem_undo is 20 the maximum semaphore value is 32767 now free the resourceremove sem ok |
Summary: The traffic signal is different from other processes. It is mainly used for inter-process synchronization. Generally speaking, the system V signal lamp is actually a collection of signal lights, available
It is used for synchronization between multiple processes that share resources. Each traffic signal has a value that indicates the number of available shared resources (available) represented by the current traffic signal.
Source, then the number of requests to be applied is subtracted from the traffic signal value. If there is not enough available resources, the process can wait for sleep or return immediately. When a process needs to apply for multiple types of shared resources
To ensure the atomicity of operations, you can either apply for all shared resources or discard all resources. This ensures that multiple processes do not cause mutual locks. Linux has various restrictions on traffic signals.
Output results. In addition, if you want to further understand the signal lamp, it is recommended to read the SEM. H source code. This file is not long, but provides an important data structure related to the signal lamp.
Appendix 1: struct sem_array:
/* Each traffic signal set in the system corresponds to a sem_array structure */struct sem_array {struct kern_ipc_perm sem_perm;/* permissions .. see IPC. H */time_t sem_otime;/* Last semop time */time_t sem_ctime;/* last change time */struct SEM * sem_base; /* PTR to first semaphore in array */struct sem_queue * sem_pending;/* pending operations to be processed */struct sem_queue ** sem_pending_last; /* last pending operation */struct sem_undo * undo;/* undo requests on this array */unsigned long sem_nsems;/* No. of semaphores in array */}; |
The sem_queue structure is as follows:
/* Every process sleeping due to a signal lamp in the system corresponds to a sem_queue structure */struct sem_queue {struct sem_queue * next; /* next entry in the queue */struct sem_queue ** Prev;/* previous entry in the queue, * (Q-> PREV) = Q */struct task_struct * sleeper; /* This process */struct sem_undo * undo;/* undo structure */int pid;/* process ID of requesting process */INT status; /* completion status of operation */struct sem_array * SMA;/* semaphore array for Operations */int id;/* internal sem id */struct sembuf * SOPs; /* array of pending operations */INT nsops;/* Number of Operations */INT alter;/* operation will alter semaphore */}; |
Appendix 2: Union semun is an important parameter in the System Call semctl:
union semun {int val;/* value for SETVAL */struct semid_ds *buf;/* buffer for IPC_STAT & IPC_SET */unsigned short *array;/* array for GETALL & SETALL */struct seminfo *__buf;/* buffer for IPC_INFO */ //test!!void *__pad;};struct seminfo {int semmap;int semmni;int semmns;int semmnu;int semmsl;int semopm;int semume;int semusz;int semvmx;int semaem;}; |
References
[1] second volume of UNIX Network Programming: inter-process communication, Author: W. Richard Steven S, Translator: Yang jizhang, Tsinghua University Press. Both POSIX and System V signal lights are described, which is of great inspiration for program development in Linux.
[2] Linux kernel source code scenario analysis (I), by Mao decao, Hu Ximing, Zhejiang University Press, provides source code analysis related to system V signal lights, especially in the aspect of ensuring the atomicity of operations and the Undo flag, we have discussed it very deeply.
[3] GNU/Linux programming guide, second edition, and Kurt Wall
[4] semget, semop, semctl Manual
About the author
Zheng yanxing, male, is now pursuing a doctorate degree in network direction from the computer College of the National Defense University. You can email
Mlinux@163.com
Contact him.
Post: http://www.ibm.com/developerworks/cn/linux/l-ipc/part4/