上一篇
参考文章: tmpfs-基于内存的文件系统 浅析Linux的共享内存与tmpfs文件系统
文章目录
一、System V 共享内存1. shmget 源码分析2. shmat 源码分析
二、System V 信号量1. semget 源码分析2. semctl 源码分析2.1 SETALL --> semctl_main2.2 SETVAL --> semctl_setval
3. semop 源码分析
一、System V 共享内存
1. shmget 源码分析
SYSCALL_DEFINE3(shmget
, key_t
, key
, size_t
, size
, int, shmflg
)
{
struct ipc_namespace
*ns
= current
->nsproxy
->ipc_ns
;;
static const struct ipc_ops shm_ops
= {
.getnew
= newseg
,
... ...
};
struct ipc_params shm_params
;
shm_params
.key
= key
;
... ...
return ipcget(ns
, ...);
}
static int newseg(struct ipc_namespace
*ns
, struct ipc_params
*params
)
{
struct shmid_kernel
*shp
;
... ...
shp
= kvmalloc(sizeof(*shp
), GFP_KERNEL
);
file
= shmem_kernel_file_setup(name
, size
, acctflag
);
... ...
error
= ipc_addid(&shm_ids(ns
), &shp
->shm_perm
, ns
->shm_ctlmni
);
list_add(&shp
->shm_clist
, ¤t
->sysvshm
.shm_clist
);
... ...
return error
;
}
2. shmat 源码分析
SYSCALL_DEFINE3(shmat
, int, shmid
, char __user
*, shmaddr
, int, shmflg
)
{
... ...
err
= do_shmat(shmid
, shmaddr
, shmflg
, &ret
, SHMLBA
);
}
long do_shmat(int shmid
, char __user
*shmaddr
, int shmflg
,
ulong
*raddr
, unsigned long shmlba
)
{
shp
= shm_obtain_object_check(ns
, shmid
);
... ...
sfd
= kzalloc(sizeof(*sfd
), GFP_KERNEL
);
file
= alloc_file(&path
, f_mode
,
is_file_hugepages(shp
->shm_file
) ?
&shm_file_operations_huge
:
&shm_file_operations
);
addr
= do_mmap_pgoff(file
, addr
, size
, prot
, flags
, 0, &populate
, NULL);
}
二、System V 信号量
1. semget 源码分析
SYSCALL_DEFINE3(semget
, key_t
, key
, int, nsems
, int, semflg
)
{
struct ipc_namespace
*ns
;
static const struct ipc_ops sem_ops
= {
.getnew
= newary
,
};
... ...
return ipcget(ns
, &sem_ids(ns
), &sem_ops
, &sem_params
);
}
static int newary(struct ipc_namespace
*ns
, struct ipc_params
*params
)
{
... ...
sma
= sem_alloc(nsems
);
... ...
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
);
}
... ...
retval
= ipc_addid(&sem_ids(ns
), &sma
->sem_perm
, ns
->sc_semmni
);
... ...
}
2. semctl 源码分析
SYSCALL_DEFINE4(semctl
, int, semid
, int, semnum
, int, cmd
, unsigned long, arg
)
{
int version
;
struct ipc_namespace
*ns
;
void __user
*p
= (void __user
*)arg
;
... ...
switch (cmd
) {
... ...
case SETALL
:
return semctl_main(ns
, semid
, semnum
, cmd
, p
);
case SETVAL
:
return semctl_setval(ns
, semid
, semnum
, arg
);
... ...
}
2.1 SETALL --> semctl_main
union semun
{
int val
;
struct semid_ds
*buf
;
unsigned short int *array
;
struct seminfo
*__buf
;
};
static int semctl_main(struct ipc_namespace
*ns
, int semid
, int semnum
,
int cmd
, void __user
*p
)
{
struct sem_array
*sma
;
sma
= sem_obtain_object_check(ns
, semid
);
... ...
case SETALL
: {
if (copy_from_user(sem_io
, p
, nsems
*sizeof(ushort
))) {
ipc_rcu_putref(&sma
->sem_perm
, sem_rcu_free
);
err
= -EFAULT
;
goto out_free
;
}
for (i
= 0; i
< nsems
; i
++) {
sma
->sems
[i
].semval
= sem_io
[i
];
sma
->sems
[i
].sempid
= task_tgid_vnr(current
);
}
}
... ...
2.2 SETVAL --> semctl_setval
static int semctl_setval(struct ipc_namespace
*ns
, int semid
, int semnum
,
unsigned long arg
)
{
struct sem_array
*sma
;
struct sem
*curr
;
int err
, val
;
val
= arg
;
sma
= sem_obtain_object_check(ns
, semid
);
curr
= &sma
->sems
[semnum
];
curr
->semval
= val
;
curr
->sempid
= task_tgid_vnr(current
);
... ...
}
3. semop 源码分析
struct sembuf
{
unsigned short sem_num
;
short sem_op
;
short sem_flg
;
};
SYSCALL_DEFINE3(semop
, int, semid
, struct sembuf __user
*, tsops
,
unsigned, nsops
)
{
return sys_semtimedop(semid
, tsops
, nsops
, NULL);
}
SYSCALL_DEFINE4(semtimedop
, int, semid
, struct sembuf __user
*, tsops
,
unsigned, nsops
, const struct timespec __user
*, timeout
)
{
struct sem_array
*sma
;
struct sembuf fast_sops
[SEMOPM_FAST
];
struct sembuf
*sops
= fast_sops
, *sop
;
struct sem_queue queue
;
if (copy_from_user(sops
, tsops
, nsops
* sizeof(*tsops
))) {
... ...
if (timeout
) {
... ...
sma
= sem_obtain_object_check(ns
, semid
);
queue
.sops
= sops
;
queue
.nsops
= nsops
;
... ...
error
= perform_atomic_semop(sma
, &queue
);
if (error
== 0) {
DEFINE_WAKE_Q(wake_q
);
do_smart_update(sma
, sops
, nsops
, 1, &wake_q
);
wake_up_q(&wake_q
);
... ...
goto out_free
;
}
if (nsops
== 1) {
struct sem
*curr
;
curr
= &sma
->sems
[sops
->sem_num
];
if (alter
) {
if (sma
->complex_count
) {
list_add_tail(&queue
.list
,
&sma
->pending_alter
);
... ...
} else {
... ...
}