SEMCTL - Linux手册页

时间:2019-08-20 17:59:19  来源:igfitidea点击:

Linux程序员手册 第2部分
更新日期: 2020-04-11

名称

semctl-System V信号灯控制操作

语法

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semctl(int semid, int semnum, int cmd, ...);

说明

semctl()在由semid标识的System V信号量集或该集合的第semnum信号量上执行cmd指定的控制操作。 (一组中的信号灯从0开始编号。)

此函数具有三个或四个参数,具体取决于cmd。当有四个时,第四个具有union semun类型。调用程序必须按以下方式定义此并集:

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
                                (Linux-specific) */
};

semid_ds数据结构定义如下:

struct semid_ds {
    struct ipc_perm sem_perm;  /* Ownership and permissions */
    time_t          sem_otime; /* Last semop time */
    time_t          sem_ctime; /* Creation time/time of last
                                  modification via semctl() */
    unsigned long   sem_nsems; /* No. of semaphores in set */
};

The fields of the
semid_ds

structure are as follows:

sem_perm
这是一个ipc_perm结构(请参见下文),用于指定对信号集的访问权限。
sem_otime
上次semop(2)系统调用的时间。
sem_ctime
创建信号集的时间或上次semctl()IPCSET,SETVAL或SETALL操作的时间。
sem_nsems
集合中的信号灯数量。集合中的每个信号量都由一个从0到sem_nsems-1的非负整数引用。

ipc_perm结构定义如下(突出显示的字段可使用IPC_SET设置):

struct ipc_perm {
    key_t          __key; /* Key supplied to semget(2) */
    uid_t          uid;   /* Effective UID of owner */
    gid_t          gid;   /* Effective GID of owner */
    uid_t          cuid;  /* Effective UID of creator */
    gid_t          cgid;  /* Effective GID of creator */
    unsigned short mode;  /* Permissions */
    unsigned short __seq; /* Sequence number */
};

ipc_perm结构的mode字段的最低9位定义了共享内存段的访问权限。权限位如下:

0400Read by user
0200Write by user
0040Read by group
0020Write by group
0004Read by others
0002Write by others

实际上,"写"是指信号集的"更改"。系统未使用位0100、0010和0001(执行位)。

cmd的有效值为:

IPC_STAT
将信息从与Semid相关联的内核数据结构复制到arg.buf指向的semid_ds结构中。参数semnum被忽略。调用过程必须对信号集具有读取权限。
IPC_SET
将arg.buf指向的semid_ds结构的某些成员的值写入与此信号量集关联的内核数据结构,同时还更新其sem_ctime成员。该结构的以下成员已更新:sem_perm.uid,sem_perm.gid和sem_perm.mode(其最低9位)。调用过程的有效UID必须与信号量集的所有者(sem_perm.uid)或创建者(sem_perm.cuid)相匹配,否则调用者必须具有特权。参数semnum被忽略。
IPC_RMID
立即删除信号量集,唤醒在该集上的semop(2)调用中阻塞的所有进程(错误返回并将errno设置为EIDRM)。调用过程的有效用户ID必须与信号集的创建者或所有者匹配,或者必须为调用者特权。参数semnum被忽略。
IPC_INFO(Linux-specific)
在arg .__ buf指向的结构中返回有关系统范围信号量限制和参数的信息。如果定义了_GNU_SOURCE功能测试宏,则该结构的类型为seminfo
struct  seminfo {
    int semmap;  /* Number of entries in semaphore
                    map; unused within kernel */
    int semmni;  /* Maximum number of semaphore sets */
    int semmns;  /* Maximum number of semaphores in all
                    semaphore sets */
    int semmnu;  /* System-wide maximum number of undo
                    structures; unused within kernel */
    int semmsl;  /* Maximum number of semaphores in a
                    set */
    int semopm;  /* Maximum number of operations for
                    semop(2) */
    int semume;  /* Maximum number of undo entries per
                    process; unused within kernel */
    int semusz;  /* Size of struct sem_undo */
    int semvmx;  /* Maximum semaphore value */
    int semaem;  /* Max. value that can be recorded for
                    semaphore adjustment (SEM_UNDO) */
};
可以通过/ proc / sys / kernel / sem更改semmslsemmns,semopm和semmni设置;有关详细信息,请参见proc(5)。
SEM_INFO(Linux-specific)
返回一个seminfo结构,该结构包含与IPC_INFO相同的信息,不同之处在于,以下字段返回有关信号量消耗的系统资源的信息:semusz字段返回系统上当前存在的信号量集的数量;信号量字段返回系统上所有信号量集中的信号量总数。
SEM_STAT(Linux-specific)
返回与IPC_STAT相同的semid_ds结构。但是,semid参数不是信号量标识符,而是内核内部数组的索引,该索引维护有关系统上所有信号量集的信息。
SEM_STAT_ANY(Linux-specific, since Linux 4.17)
返回一个seminfo结构,其中包含与SEM_STAT相同的信息。但是,不会检查sem_perm.mode的读取访问权限是否为semid,这意味着任何用户都可以使用此操作(就像任何用户可以读取/ proc / sysvipc / sem以获得相同信息一样)。
GETALL
将集合的所有信号量的semval(即当前值)返回到arg.array中。参数semnum被忽略。调用过程必须对信号集具有读取权限。
GETNCNT
返回集合中第semnum个信号量的semncnt值(即,等待该信号量值增加的进程数)。调用过程必须对信号集具有读取权限。
GETPID
返回集合的第semnum个信号量的sempid值。这是上次对该信号量执行操作的过程的PID(但请参阅"注意")。调用过程必须对信号集具有读取权限。
GETVAL
返回集合中第semnum个信号量的semval(即信号量值)。调用过程必须对信号集具有读取权限。
GETZCNT
返回集合中第semnum个信号量的semzcnt值(即,等待该信号量值变为0的进程数)。调用过程必须对信号集具有读取权限。
SETALL
使用arg.array为集合的所有信号量设置semval值,同时还更新与集合关联的semid_ds结构的sem_ctime成员。撤消条目(请参阅semop(2))会在所有进程中针对已更改的信号量进行清除。如果对信号量值的更改将允许其他进程中阻塞的semop(2)调用继续进行,则这些进程将被唤醒。参数semnum被忽略。调用过程必须对信号集具有更改(写入)权限。
SETVAL
将集合的第semnum信号量的信号量值(semval)设置为arg.val,同时还更新与该集合关联的semid_ds结构的sem_ctime成员。在所有过程中,都会针对更改的信号量清除撤消条目。如果对信号量值的更改将允许其他进程中阻塞的semop(2)调用继续进行,则这些进程将被唤醒。调用过程必须对信号集具有更改权限。

返回值

失败时,semctl()返回-1,并带有errno指示错误。

否则,系统调用将根据cmd返回非负值,如下所示:

GETNCNT
semncnt的值。
GETPID
sempid的价值。
GETVAL
semval的值。
GETZCNT
semzcnt的值。
IPC_INFO
内核内部数组中使用最高的条目的索引,该条目记录有关所有信号量集的信息。 (此信息可以与重复的SEM_STAT或SEM_STAT_ANY操作一起使用,以获得有关系统上所有信号量集的信息。)
SEM_INFO
至于IPC_INFO。
SEM_STAT
信号量集的标识符,其索引以Semid给出。
SEM_STAT_ANY
至于SEM_STAT。

所有其他cmd值成功均返回0。

错误说明

失败时,errno将设置为以下之一:

EACCES
参数cmd具有值GETALLGETPIDGETVALGETNCNTGETZCNTIPC_STATSEM_STATSEM_STAT_ANY,SETALL或SETVAL之一,并且调用过程对信号集没有必需的权限,并且不具有CAP_IPC_OWNER功能控制其IPC名称空间的用户名称空间。
EFAULT
无法访问arg.buf或arg.array指向的地址。
EIDRM
信号量集已删除。
EINVAL
cmd或semid的值无效。或:对于SEM_STAT操作,以Semid指定的索引值引用当前未使用的数组插槽。
EPERM
参数cmd的值为IPC_SET或IPC_RMID,但是调用过程的有效用户ID不是信号量集的创建者(如sem_perm.cuid中所找到)或所有者(如sem_perm.uid中所见),并且该过程确实不具备CAP_SYS_ADMIN功能。
ERANGE
参数cmd具有值SETALL或SETVAL,并且要设置semval的值(对于该集合的某些信号量)小于0或大于实现限制SEMVMX。

遵循规范

POSIX.1-2001,POSIX.1-2008,SVr4。

POSIX.1将semid_ds结构的sem_nsems字段指定为unsigned short类型,并且该字段在大多数其他系统上已定义。在Linux 2.2和更早版本上也是如此定义,但是自Linux 2.4起,该字段的类型为unsigned long。

备注

在Linux或任何版本的POSIX上,都不需要包含和。但是,一些旧的实现需要包含这些头文件,并且SVID也记录了这些头文件。打算移植到这样的旧系统的应用程序可能需要包含这些头文件。

ipcs(1)程序使用IPC_INFO,SEM_STAT和SEM_INFO操作来提供有关已分配资源的信息。将来,这些内容可能会修改或移至/ proc文件系统接口。

struct semid_ds结构中的各个字段在Linux 2.2下的类型为short,而在Linux 2.4下的类型为long。要利用此优势,在glibc-2.1.91或更高版本下进行重新编译就足够了。 (内核通过cmd中的IPC_64标志区分新旧呼叫。)

在glibc的某些早期版本中,semun联合是在中定义的,但是POSIX.1要求调用者定义该联合。在未定义此并集的glibc版本中,_SEM_SEMUN_UNDEFINED宏在中定义。

信号量集的以下系统限制会影响semctl()调用:

SEMVMX
semval的最大值:与实现有关(32767)。

为了提高可移植性,最好始终使用四个参数调用semctl()。

The sempid value

POSIX.1将sempid定义为信号量上的" [最后一个操作的进程ID]",并明确指出此值是由成功的semop(2)调用设置的,这意味着没有其他接口会影响sempid值。

虽然某些实现符合POSIX.1中指定的行为,但其他实现则不符合。 (这里的错误可能是POSIX.1所致,因为它可能无法捕获现有实现行为的全部范围。)各种其他实现也为其他更新信号量值的操作更新了sempid:SETVAL和SETALL操作,以及由于使用SEM_UNDO标志而在进程终止时执行的信号量调整(请参见semop(2))。

Linux还更新了用于SETVAL操作和信号量调整的sempid。但是,在Linux 4.5之前(包括Linux 4.5)中,内核并没有为SETALL操作更新sempid。这已在Linux 4.6中得到纠正。

示例

请参见shmop(2)。

另外参见

ipc(2),semget(2),semop(2),功能(7),sem_overview(7),sysvipc(7)

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/