Linux进程间通讯
Linux进程间通讯(五)信号量
一、信号量集的创建
信号量集的创建需要通过系统调用 semget,其定义如下(这里需要注意的是,semget创建的是一个信号量集合,也就是一个集合是可以包含多个信号量的)
SYSCALL_DEFINE3(semget, key_t, key, int, nsems, int, semflg)
{
struct ipc_namespace *ns;
static const struct ipc_ops sem_ops = {
.getnew = newary,
.associate = sem_security,
.more_checks = sem_more_checks,
};
struct ipc_params sem_params;
ns = current->nsproxy->ipc_ns;
sem_params.key = key;
sem_params.flg = semflg;
sem_params.u.nsems = nsems;
return ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params);
}
- key:表示信号量的id
- msems:表示这个信号量集合中的信号量个数
这部分的操作和上一篇文章分析共享内存时创建共享内存十分相似。首先将请求封装成 sem_params,然后调用通用的 ipcget,指定信号量对应的 ipc 为 sem_ids,指定信号量对应的操作为 sem_ops,这一次请求的操作为 sem_params
ipcget 在上一篇文章已经解析过了,如果设置了 IPC_PRIVATE,那么就永远创建新的信号量;否则就会调用 ipcget_public
在 ipcget_public 中,首先会通过 id 去 sem_ids 中查找信号量是否存在,如果存在就返回,如果不存在,那么就创建一个新的
当要创建新的信号量的时候,对应的函数就是 newary 函数,其定义如下
static int newary(struct ipc_namespace *ns, struct ipc_params *params)
{
int retval;
struct sem_array *sma;
key_t key = params->key;
int nsems = params->u.nsems;
int semflg = params->flg;
int i;
......
sma = sem_alloc(nsems);
......
sma->sem_perm.mode = (semflg & S_IRWXUGO);
sma->sem_perm.key = key;
sma->sem_perm.security = NULL;
......
for (i = 0; i < nsems; i++) {
INIT_LIST_HEAD(&sma->sems[i].pending_alter);
INIT_LIST_HEAD(&sma->sems[i].pending_const);
spin_lock_init(&sma->sems[i].lock);
}
sma->complex_count = 0;
sma->use_global_lock = USE_GLOBAL_LOCK_HYSTERESIS;
INIT_LIST_HEAD(&sma->pending_alter);
INIT_LIST_HEAD(&sma->pending_const);
INIT_LIST_HEAD(&sma->list_id);
sma->sem_nsems = nsems;
sma->sem_ctime = get_seconds();
retval = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
......
ns->used_sems += nsems;
......
return sma->sem_perm.id;
}
newary 的第一步就是分配一个 struct sem_array 对象,它表示一个信号量集对象,然后是设置信号量的属性,如 key、权限等
struct sem_array 中其实定义了多个信号量,具体多少个是通过 semget 系统调用指定的,其定义如下
struct sem_array {
struct kern_ipc_perm ____cacheline_aligned_in_smp
sem_perm; /* permissions .. see ipc.h */
time_t sem_otime; /* last semop time */
time_t sem_ctime; /* last change time */
struct sem *sem_base;