Posted on 2008-02-21 14:10
ZelluX 閱讀(644)
評論(0) 編輯 收藏 所屬分類:
Linux 、
System
ipc/shm.c:
sys_shmat 連接共享內存
/**/
/*
*?Fix?shmaddr,?allocate?descriptor,?map?shm,?add?attach?descriptor?to?lists.
*/
asmlinkage?
long
?sys_shmat?(
int
?shmid,?
char
?
*
shmaddr,?
int
?shmflg,?
ulong
?
*
raddr)

{
????
struct
?shmid_kernel?
*
shp;
????unsigned?
long
?addr;
????unsigned?
long
?size;
????
struct
?file?
*
?file;
????
int
????err;
????unsigned?
long
?flags;
????unsigned?
long
?prot;
????unsigned?
long
?o_flags;
????
int
?acc_mode;
????
void
?
*
user_addr;

????
if
?(shmid?
<
?
0
)
????????
return
?
-
EINVAL;


????
if
?((addr?
=
?(
ulong
)shmaddr))?
{?????????
//
?如果shmaddr不為零,則為固定地址
????????
if
?(addr?
&
?(SHMLBA
-
1
))?
{???????????
//
?檢查是否是SHMLBA的整數倍
????????????
if
?(shmflg?
&
?SHM_RND)??????????
//
?如果設置了SHM_RND,則自動調整,否則返回錯誤信息
????????????????addr?
&=
?
~
(SHMLBA
-
1
);???????
/**/
/*
?round?down?
*/
????????????
else
????????????????
return
?
-
EINVAL;
????????}
????????flags?
=
?MAP_SHARED?
|
?MAP_FIXED;

????}
?
else
?
{
????????
if
?((shmflg?
&
?SHM_REMAP))
????????????
return
?
-
EINVAL;

????????flags?
=
?MAP_SHARED;
????}
????
if
?(shmflg?
&
?SHM_RDONLY)?
{?????????????
//
?權限設置
????????prot?
=
?PROT_READ;
????????o_flags?
=
?O_RDONLY;
????????acc_mode?
=
?S_IRUGO;

????}
?
else
?
{
????????prot?
=
?PROT_READ?
|
?PROT_WRITE;
????????o_flags?
=
?O_RDWR;
????????acc_mode?
=
?S_IRUGO?
|
?S_IWUGO;
????}
????
/**/
/*
????*?We?cannot?rely?on?the?fs?check?since?SYSV?IPC?does?have?an
????*?additional?creator?id
????
*/
????shp?
=
?shm_lock(shmid);
????
if
(shp?
==
?NULL)
????????
return
?
-
EINVAL;
????err?
=
?shm_checkid(shp,shmid);??????????
//
?檢查共享內存是否存在?
????
if
?(err)?
{
????????shm_unlock(shmid);
????????
return
?err;
????}
????
if
?(ipcperms(
&
shp
->
shm_perm,?acc_mode))?
{??
//
?檢查訪問權限
????????shm_unlock(shmid);
????????
return
?
-
EACCES;
????}
????file?
=
?shp
->
shm_file;
????size?
=
?file
->
f_dentry
->
d_inode
->
i_size;
????shp
->
shm_nattch
++
;
????shm_unlock(shmid);

????down_write(
&
current
->
mm
->
mmap_sem);

????
if
?(addr?
&&
?
!
(shmflg?
&
?SHM_REMAP))?
{
????????user_addr?
=
?ERR_PTR(
-
EINVAL);
????????
if
?(find_vma_intersection(current
->
mm,?addr,?addr?
+
?size))
????????????
goto
?invalid;

????????
/**/
/*
????????*?If?shm?segment?goes?below?stack,?make?sure?there?is?some
????????*?space?left?for?the?stack?to?grow?(at?least?4?pages).
????????
*/
????????
if
?(addr?
<
?current
->
mm
->
start_stack?
&&
????????????addr?
>
?current
->
mm
->
start_stack?
-
?size?
-
?PAGE_SIZE?
*
?
5
)
????????????
goto
?invalid;
????}
????
//
?映射內存
????user_addr?
=
?(
void
*
)?do_mmap?(file,?addr,?size,?prot,?flags,?
0
);

invalid:
????up_write(
&
current
->
mm
->
mmap_sem);

????down?(
&
shm_ids.sem);
????
if
(
!
(shp?
=
?shm_lock(shmid)))
????????BUG();
????shp
->
shm_nattch
--
;?????????????????????
//
?這里又減一了,真正的映射數增加是在do_mmap中完成的
????
if
(shp
->
shm_nattch?
==
?
0
?
&&
????????shp
->
shm_flags?
&
?SHM_DEST)
????????shm_destroy?(shp);
????shm_unlock(shmid);
????up?(
&
shm_ids.sem);

????
*
raddr?
=
?(unsigned?
long
)?user_addr;
????err?
=
?
0
;
????
if
?(IS_ERR(user_addr))
????????err?
=
?PTR_ERR(user_addr);
????
return
?err;

}
shmctl這函數功能亂得很,一個switch一堆case,代碼分析略
ipc/utils.h:IPC子系統對共享內存的管理是通過shm_ids{}來實現的。



struct?ipc_ids?
{
????int?size;
????int?in_use;
????int?max_id;??????????????//?最大索引號
????unsigned?short?seq;??????//?當前的順序標號
????unsigned?short?seq_max;??//?順序編號上界
????struct?semaphore?sem;?????//?信號量
????spinlock_t?ary;??????????//?自旋鎖
????struct?ipc_id*?entries;??//?標識符數組
};


struct?ipc_id?
{
????struct?kern_ipc_perm*?p;
};shm_ids的初始化:
調用關系鏈:start_kernel() -> ipc_init() -> shm_init() -> ipc_init_ids(&shm_ids, 1)


void?__init?ipc_init_ids(struct?ipc_ids*?ids,?int?size)


{
????int?i;
????sema_init(&ids->sem,1);

????if(size?>?IPCMNI)
????????size?=?IPCMNI;
????ids->size?=?size;
????ids->in_use?=?0;
????ids->max_id?=?-1;
????ids->seq?=?0;

????
{
????????int?seq_limit?=?INT_MAX/SEQ_MULTIPLIER;
????????if(seq_limit?>?USHRT_MAX)
????????????ids->seq_max?=?USHRT_MAX;
?????????else
?????????????ids->seq_max?=?seq_limit;
????}

????ids->entries?=?ipc_alloc(sizeof(struct?ipc_id)*size);


????if(ids->entries?==?NULL)?
{
????????printk(KERN_ERR?"ipc_init_ids()?failed,?ipc?service?disabled.\n");
????????ids->size?=?0;
????}
????ids->ary?=?SPIN_LOCK_UNLOCKED;
????for(i=0;i<ids->size;i++)
????????ids->entries[i].p?=?NULL;
}看ipc/util.c中的代碼似乎一開始創建了一個只能容納一個ipc_id的數組,之后有擴充數組的需求的時候再重新分配內存,轉移數據。這樣效率會不會太低呢?