1.共享內存段被映射進進程空間以後,存在於進程空間的什麼位置?共享內存段最大限制是多少?node
存在於進程數據段,最大限制是0x2000000Byte
數據結構
將一塊內存映射到兩個或者多個進程地址空間。經過指針訪問該共享內存區。通常經過mmap將文件映射到進程地址共享區。app
Linux對共享內存的實現,在2.6採用了內存映射技術。對於內存共享,主要集中在三個內核函數,他們是do_shmat,sys_shmat和sys_shmdt。其中,sys_shmat調用了do_shmat最終實現了共享內存的attach。sys_shmdt實現了共享內存的detach和destroy。下面我主要對這三個函數的源碼進行分析。在分析以前,首先介紹共享內存實現原理。ide
原理:函數
咱們知道,LINUX的進程擁有本身獨立的地址空間,這點和vxworks是不一樣的。系統中多個進程共享同一內存段,能夠經過系統提供的共享內存機制進行。當進程向系統提出建立或附着共享內存的申請的時候,內核會爲每個新的共享內存段提供一個shmid_kernel的數據結構來維護共享段和文件系統之間的關係(也能夠理解成共享內存段和文件系統之間創建關係的橋樑)。下面就是這個數據結構:spa
這個數據結構定義在shm.h頭文件中指針
struct shmid_kernel /* private to the kernel */orm
{ 進程
struct kern_ipc_perm shm_perm; // 訪問權限的信息ip
struct file * shm_file; // 指向虛擬文件系統的指針
unsigned long shm_nattch; // 有多少個進程attach上了這個共享內存段
unsigned long shm_segsz; // 共享內存段大小
// 如下是一些訪問時間的相關信息
time_t shm_atim;
time_t shm_dtim;
time_t shm_ctim;
pid_t shm_cprid;
pid_t shm_lprid;
struct user_struct *mlock_user;
};
該數據結構中最重要的部分就是shm_file這個字段。它指向了共享內存對應的文件。在該結構中有一個字段,f_mapping,它指向了該內存段使用的頁面(物理內存)。同時,結構中,也包含一個字段,f_path,用於指向文件系統中的文件(dentry->inode),這樣就創建了物理內存和文件系統的橋樑。當進程須要建立或者attach共享內存的時候,在用戶態,會先向虛擬內存系統申請各自的vma_struct,並將其插入到各自任務的紅黑樹中,該結構中有一個成員vm_file,它指向的就是struct file(shm_file)。這樣虛擬內存、共享內存(文件系統)和物理內存就創建了鏈接。
接着咱們來看看主要的函數:
do_shmat:
1. 這個函數首先根據shared memory的id,在內核中查找相應的shmid_struct。
shp = shm_lock_check(ns, shmid);
if (IS_ERR(shp)) {
err = PTR_ERR(shp);
goto out;
}
2. 對訪問者進行訪問權限檢查
if (ipcperms(&shp->shm_perm, acc_mode))
goto out_unlock;
3. 獲取共享內存對應的文件的信息。
獲取文件表項
path.dentry = dget(shp->shm_file->f_path.dentry);
獲取掛接點
path.mnt = shp->shm_file->f_path.mnt;
共享內存引用計數自增
shp->shm_nattch++;
經過i節點獲取文件大小
size = i_size_read(path.dentry->d_inode);
4. 分配相應的數據結構,並進行初始化。
err = -ENOMEM;
從slab分配其中分配shm_file_data數據結構
sfd = kzalloc(sizeof(*sfd), GFP_KERNEL);
if (!sfd)
goto out_put_dentry;
分配一個struct file的數據結構
file = alloc_file(path.mnt, path.dentry, f_mode, &shm_file_operations);
if (!file)
goto out_free;
初始化file。
file->private_data = sfd;
file->f_mapping = shp->shm_file->f_mapping;
sfd->id = shp->shm_perm.id;
sfd->ns = get_ipc_ns(ns);
sfd->file = shp->shm_file;
sfd->vm_ops = NULL;
5. 最後進行內存映射,完成attach操做。
user_addr = do_mmap (file, addr, size, prot, flags, 0);
sys_shmat:
他是系統調用函數,他調用了do_shmat。
sys_shmdt:
首先查找相應的vma,若是找到執行ummap操做。