SystemV IPC 
Masami Ichikawa (@masami256)
overview 
• libc側 
• kernel側 
• 主な構造体 
• IPC全般の共通処理 
• 共通処理(shmget、semget、msgget共通部) 
• 共有メモリ
overview 
• libc側 
• kernel側 
• 主な構造体 
• IPC全般の共通処理 
• 共通処理(shmget、semget、msgget共通部) 
• 共有メモリ
system calls 
• msgctl, msgget, msgrcv, msgsnd 
• semctl, semget, semop, 
• shmctl, shmget, shmat, shmdt
ipc(2) - libc 
• SystemV IPCのsystem callの窓口 
• socket関連にあるsocketcall(2)みたいなもの
ipc(2)の呼び出し 
• sysdeps/unix/sysv/linux/shmat.c 
41 resultvar = INTERNAL_SYSCALL (ipc, err, 5, IPCOP_shmat, 
42 shmid, shmflg, 
43 (long int) &raddr, 
44 (void *) shmaddr); 
• sysdeps/unix/sysv/linux/x86_64/sysdep.h 
220 # define INTERNAL_SYSCALL_NCS(name, err, nr, args...)  
221 ({  
222 unsigned long int resultvar;  
223 LOAD_ARGS_##nr (args)  
224 LOAD_REGS_##nr  
225 asm volatile (  
226 "syscallnt"  
227 : "=a" (resultvar)  
228 : "0" (name) ASM_ARGS_##nr : "memory", "cc", "r11", "cx");  
229 (long int) resultvar; }) 
230 # undef INTERNAL_SYSCALL 
231 # define INTERNAL_SYSCALL(name, err, nr, args...)  
232 INTERNAL_SYSCALL_NCS (__NR_##name, err, nr, ##args)
ipc(2) - kernel 
• ipc/syscall.c 
• 対象のsystem callに応じた関数を呼んで結果を 
返す
overview 
• libc側 
• kernel側 
• 主な構造体 
• IPC全般の共通処理 
• 共通処理(shmget、semget、msgget共通部) 
• 共有メモリ
kernel側実装 
• コードはipc/以下に 
• 主に以下のファイルを参照 
• ipc/syscall.c 
• ipc/shm.c 
• ipc/util.c
主な構造体 
• IPC objectの管理 
• セマフォ、共有メモリ、メッセージキュー固有の構造体 
• パーミッションの管理 
• IPC Identifier 
• 1つのIPC Objecdtに対して一つ設定 
• IPC namespace単位で管理
共有メモリ管理オブジェクト 
• include/linux/shm.h 
9 struct shmid_kernel /* private to the kernel */ 
10 { 
11 struct kern_ipc_perm shm_perm; 
12 struct file *shm_file; 
13 unsigned long shm_nattch; 
14 unsigned long shm_segsz; 
15 time_t shm_atim; 
16 time_t shm_dtim; 
17 time_t shm_ctim; 
18 pid_t shm_cprid; 
19 pid_t shm_lprid; 
20 struct user_struct *mlock_user; 
21 
22 /* The task created the shm object. NULL if the task is dead. */ 
23 struct task_struct *shm_creator; 
24 struct list_head shm_clist; /* list by creator */ 
25 };
セマフォ管理オブジェクト 
• include/linux/sem.h 
12 struct sem_array { 
13 struct kern_ipc_perm ____cacheline_aligned_in_smp 
14 sem_perm; /* permissions .. see ipc.h */ 
15 time_t sem_ctime; /* last change time */ 
16 struct sem *sem_base; /* ptr to first semaphore in 
array */ 
17 struct list_head pending_alter; /* pending operations */ 
18 /* that alter the array */ 
19 struct list_head pending_const; /* pending complex operations */ 
20 /* that do not alter semvals */ 
21 struct list_head list_id; /* undo requests on this array 
*/ 
22 int sem_nsems; /* no. of semaphores in array */ 
23 int complex_count; /* pending complex operations */ 
24 };
message queue管理オブジェクト 
• include/linux/msg.h 
18 struct msg_queue { 
19 struct kern_ipc_perm q_perm; 
20 time_t q_stime; /* last msgsnd time */ 
21 time_t q_rtime; /* last msgrcv time */ 
22 time_t q_ctime; /* last change time */ 
23 unsigned long q_cbytes; /* current number of bytes on queue 
*/ 
24 unsigned long q_qnum; /* number of messages in queue */ 
25 unsigned long q_qbytes; /* max number of bytes on queue */ 
26 pid_t q_lspid; /* pid of last msgsnd */ 
27 pid_t q_lrpid; /* last receive pid */ 
28 
29 struct list_head q_messages; 
30 struct list_head q_receivers; 
31 struct list_head q_senders; 
32 };
IPCパーミッション管理 
• include/linux/ipc.h 
11 struct kern_ipc_perm 
12 { 
13 spinlock_t lock; 
kuid_t・kgid_tはコンテナ型仮想 
14 bool deleted; 
化において、host側のuid/gitと 
15 int id; 
guest側のuid/pidをマッピングす 
16 key_t key; 
るための型。 
17 kuid_t uid; 
参照:http://www.slideshare.net/ 
18 kgid_t gid; 
masamiichikawa/linux-namespace 
19 kuid_t cuid; 
20 kgid_t cgid; 
21 umode_t mode; 
22 unsigned long seq; 
23 void *security; 
24 };
プロセスからIPCオブジェクトの参照 
• セマフォ/共有メモリを作成すると、struct 
task_structのメンバ変数よりリストで繋がる 
1385 #ifdef CONFIG_SYSVIPC 
1386 /* ipc stuff */ 
1387 struct sysv_sem sysvsem; 
1388 struct sysv_shm sysvshm; 
1389 #endif 
• メッセージキューは無し
IPC Identifier 
• IPC Namespace単位で管理 
• 管理する構造体はstruct ipc_ids 
• struct ipc_namespaceのメンバ変数ids[3]にて管理 
29 struct ipc_namespace { 
30 atomic_t count; 
31 struct ipc_ids ids[3]; 
• 初期化のタイミングはIPC namespace作成時の 
create_ipc_ns() 
• ipc_addid()にてidを設定
struct ipc_ids 
• include/linux/ipc_namespace.h 
21 struct ipc_ids { 
22 int in_use; 
23 unsigned short seq; 
24 struct rw_semaphore rwsem; 
25 struct idr ipcs_idr; 
26 int next_id; 
27 }; 
IPC Object作成時に+1 
IPC_RMIDの操作時に-1 
idを振るときに使用 
通常は-1を設定し、この番号を使いたい!という場合にsysctlで設定可能。 
カーネルのconfigでCONFIG_CHECKPOINT_RESTOREが設定されている必要あり。 
https://github.com/torvalds/linux/commit/03f595668017f1a1fb971c02fc37140bc6e7bb1c
struct ipc_idsの初期化 
• 共有メモリの場合(セマフォ、メッセージも同 
様の流れ) 
create_ipc_ns() 
--> shm_init_ns() 
--> ipc_init_ids()  
初期化対象のstruct 
ipc_idsを渡す
ipc_init_ids() 
• 引数で渡されたstruct ipc_idsの初期化 
• 処理内容は各変数に初期値を設定する程度
ipc_addid() 
• 関数プロトタイプ 
int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int size) 
• IPC Identifierはnew->idに設定される 
• 戻り値のintはidr_alloc()の戻り値 
• idr_alloc()の戻り値もidだけど、ipc_addid() 
の呼び出し元はこの変数はエラーチェックに 
しか使用しない
ipc_addid()処理概要 
• IPC Identifierの使用数(in_use)のチェック 
• 最大で32768 
• IDR APIによるidの取得 
• in_useをインクリメント 
• kern_ipc_perm構造体にeuid、egidを設定 
• next_idの値に応じてseq変数を設定 
• ipc_buildid()でidになる値を計算して返す
管理用オブジェクトのalloc 
• メモリ確保はすべてipc_rcu_alloc()にて実施 
477 void *ipc_rcu_alloc(int size) 
478 { 
479 /* 
480 * We prepend the allocation with the rcu struct 
481 */ 
482 struct ipc_rcu *out = ipc_alloc(sizeof(struct 
ipc_rcu) + size); 
483 if (unlikely(!out)) 
484 return NULL; 
485 atomic_set(&out->refcount, 1); 
486 return out + 1; 
487 }
ipc_rcu_allocが返すデータ構造 
• メモリ上の構造は先頭にipc_rcu構造体が置か 
れ、その後ろに本来のデータを置く形 
struct 
ipc_rcu 
struct 
shmid_kenel 
とか 
[kv]malloc()の返したアドレス 
ipc_rcu_alloc()が返すアドレス
xxxget()共通処理 
• shmget, semget, msggetはipcget()を共通の 
処理として使用 
• 機能固有の処理は関数ポインタを渡し、それを 
実行してもらう 
• ipc_addid()でIPC 識別子を設定
機能固有処理の登録 
• ipc/util.hにあるstruct ipc_opsに関数をセット 
80 struct ipc_ops { 
81 int (*getnew)(struct ipc_namespace *, struct ipc_params *); 
82 int (*associate)(struct kern_ipc_perm *, int); 
83 int (*more_checks)(struct kern_ipc_perm *, struct ipc_params *); 
84 }; 
• getnew() 
• 新規にIPCのオブジェクトを作成 
• associate() 
• パーミッションのチェック 
• more_checks() 
• その他のチェック 
• optional
ipcget() 
• keyにIPC_PRIVATEが設定されているかで分岐 
• ipcget_new() 
• IPC_PRIVATE指定時 
• ipcget_public() 
• IP_PRIVATE以外のキーが指定された場合
ipcget()の流れ 
ipcget() 
--> ipcget_new() // if key is IPC_PRIVATE 
--> ipcget_public() // if key is not IPC_PRIVATE 
--> ipc_findkey() // find key 
--> ipcget_new() // if key is not found 
--> ipc_check_perms() // if found key 
--> (struct ips_ops *)->more_checks() 
--> (struct ips_ops *)->associate() 
ipcget_new() 
--> (struct ipc_ops *)->getnew()
ipcget_new() 
• struct ipc_opsに設定されているgetnew()を呼 
ぶ程度
ipcget_public() 
• keyがnamespace中にあるかチェック 
• keyが見つからなかったらipcget_new()を呼ぶ 
• keyが見つかった 
• flagのチェック 
• ipc_opsのmore_checksがセットされていればそれを呼ぶ 
• ipc_check_perms()でパーミッションのチェックとipc_opsの 
associate()呼び出し 
• ipc_check_permsがシステムコール(xxxget())の戻り値となるidを返 
す
overview 
• libc側 
• kernel側 
• 主な構造体 
• IPC全般の共通処理 
• 共通処理(shmget、semget、msgget共通部) 
• 共有メモリ
shmget 
• 共有メモリのセグメントを作成 
• ipcget()からnewseg()が呼ばれる 
• struct ips_opsのgetnewにnewseg()を設定 
• IPCの管理オブジェクトはstruct shmid_kernel 
• 作成したオブジェクトはcurrent->sysvshm.shm_clistにつながる 
• セグメントは擬似ファイルとして作る 
• SYSVxxxxxxxx(xはkey)というファイル名 
• lsofすると以下のように表示される 
41997 a.out 29678 root DEL REG 0,4 27394068 /SYSV00000000 
• flagにSHM_HUGETLBによりファイルの作成方法が変わる 
• hugetlb_file_setup() or shmem_file_setup()
セグメント作成の流れ 
• shmem_file_setup() 
• mm/shmem.cの__shmem_file_setup()が本 
体 
__shmem_file_setup() 
--> mntget() // path to mount directory 
--> d_alloc_pseudo() // allocate a dentry 
--> shmem_get_inode() // get an inode 
--> alloc_file() // allocate a file object
shmat() 
• 実際の処理はdo_shmat() 
• 共有メモリ固有データ作成 
• struct fileのprivate_dataへ設定する 
• ファイルオブジェクト(struct file)の作成 
• ファイルはshmget()で作成した擬似ファイルを使用 
• ファイルをmmap()でメモリにマップ 
• 使用するのはdo_mmap_pgoff() 
• do_mmap_pgoff()の返り値がshmat(2)の返り値になる
セグメントattachの流れ 
do_shmat() 
--> path_get() // get a file path for shmem 
--> alloc_file() // allocate a file object 
--> do_mmap_pgoff() // map the file object 
--> shm_may_destroy() // check if other process 
destroying this shmem 
--> shm_destroy() // other process destorying 
this shmem 
--> shm_unlock() // no one destorys this shmem
共有メモリ固有データ 
50 struct shm_file_data { 
51 int id; 
52 struct ipc_namespace *ns; 
53 struct file *file; 
54 const struct vm_operations_struct *vm_ops; 
55 }; 
• 以下のデータを設定 
• idにはkey 
• nsにはカレントプロセスのipc namespace 
• ipc namespaceのリファレンスカウンタをインクリメントする 
• fileにはnewseg()で作成したファイルオブジェクト 
• vm_opsにはNULL
shmdt() 
• do_shmat()でmmap(do_mmap_pgoff)した領 
域を解放 
• アドレスに対して単純にdo_munmap()を呼べな 
い 
• アドレスがmlock()やmunmap()で変更されて 
いる可能性がある
セグメントdetatchの流れ 
shmdt() 
--> find_vma() // find a vm_area_struct from 
address 
--> file_inode() // if vma is found, find 
an inode to get file(segment) size 
--> do_munmap() // unmap the address 
--> do_munmap()
shmdt() 
• 処理はCONFIG_MMUがdefineされているかで違うが、ここではdefineされてい 
る場合を見る 
• do_unmap()は 複数回呼ばれる可能性がある 
• find_vma()でvmaが見つかった場合 
• unmap対象のアドレスを探し、unmap()する 
• これは1回だけ 
• vmaがNULLでなく、vma->vm_end - addrの結果がセグメントサイズより小さ 
い間 
• ここでは複数回do_unmap()を呼ぶ可能性がある
shmctl() 
• セグメントに関して各種操作ができるが、破棄の 
場合を見ていきます 
• 破棄 
• swap禁止・禁止解除 
• 情報取得 
• etc…
セグメント破棄の流れ 
shmctl() 
--> shmctl_down() 
--> do_shm_rmid() 
--> shm_unlock() // someone using this segment 
--> shm_destroy() // anyone using it 
--> shm_rmid() // remove id from namespace and segment's 
list 
--> shm_unlock() 
--> shm_lock() // if shmflg is not SHM_HUGETLB 
--> user_shm_unlock() // else if (struct shmid *)- 
>mlock_user isn't 0 
--> fput() // remove file object
shmctl_down() 
• shmctl(2)でcmdにIPC_RMIDもしくはIPC_SET 
を指定した時に呼ばれる 
• ロックを取るなどの部分はIPC_RMID、IPC_SET 
で共通 
• cmdがIPC_RMIDの場合はdo_shm_rmid()を呼ぶ
do_shm_rmid() 
• まだ誰かがセグメントにattachしている場合 
• struct shmid_kenrnelのshm_perm.modeにSHM_DESTを 
セット 
• 削除予定フラグ 
• keyをIPC_PRIVATEに設定し、他から参照できないようにす 
る 
• 他にattachしているプロセスはいない 
• shm_destroy()を呼ぶ
shm_destroy() 
• shm_rmid()を呼ぶ 
• namespaceからidの削除 
• shm_clistのリストから管理オブジェクトを削除 
• セグメントがhugetlbを使っていない場合 
• shmem_lock()でセグメントがswap禁止になっていたら許可するように設定 
• もしくはmlockされている場合 
• 共有メモリで使用するmlock対象のページ数をstruct userのlocked_shmか 
ら減らす 
• fput()でnewseg()で作成したセグメント用のファイルオブジェクトを削除
Reference 
• LXR 
• http://lxr.free-electrons.com/ 
• glibc git 
• https://sourceware.org/git/?p=glibc.git

SystemV IPC

  • 1.
    SystemV IPC MasamiIchikawa (@masami256)
  • 2.
    overview • libc側 • kernel側 • 主な構造体 • IPC全般の共通処理 • 共通処理(shmget、semget、msgget共通部) • 共有メモリ
  • 3.
    overview • libc側 • kernel側 • 主な構造体 • IPC全般の共通処理 • 共通処理(shmget、semget、msgget共通部) • 共有メモリ
  • 4.
    system calls •msgctl, msgget, msgrcv, msgsnd • semctl, semget, semop, • shmctl, shmget, shmat, shmdt
  • 5.
    ipc(2) - libc • SystemV IPCのsystem callの窓口 • socket関連にあるsocketcall(2)みたいなもの
  • 6.
    ipc(2)の呼び出し • sysdeps/unix/sysv/linux/shmat.c 41 resultvar = INTERNAL_SYSCALL (ipc, err, 5, IPCOP_shmat, 42 shmid, shmflg, 43 (long int) &raddr, 44 (void *) shmaddr); • sysdeps/unix/sysv/linux/x86_64/sysdep.h 220 # define INTERNAL_SYSCALL_NCS(name, err, nr, args...) 221 ({ 222 unsigned long int resultvar; 223 LOAD_ARGS_##nr (args) 224 LOAD_REGS_##nr 225 asm volatile ( 226 "syscallnt" 227 : "=a" (resultvar) 228 : "0" (name) ASM_ARGS_##nr : "memory", "cc", "r11", "cx"); 229 (long int) resultvar; }) 230 # undef INTERNAL_SYSCALL 231 # define INTERNAL_SYSCALL(name, err, nr, args...) 232 INTERNAL_SYSCALL_NCS (__NR_##name, err, nr, ##args)
  • 7.
    ipc(2) - kernel • ipc/syscall.c • 対象のsystem callに応じた関数を呼んで結果を 返す
  • 8.
    overview • libc側 • kernel側 • 主な構造体 • IPC全般の共通処理 • 共通処理(shmget、semget、msgget共通部) • 共有メモリ
  • 9.
    kernel側実装 • コードはipc/以下に • 主に以下のファイルを参照 • ipc/syscall.c • ipc/shm.c • ipc/util.c
  • 10.
    主な構造体 • IPCobjectの管理 • セマフォ、共有メモリ、メッセージキュー固有の構造体 • パーミッションの管理 • IPC Identifier • 1つのIPC Objecdtに対して一つ設定 • IPC namespace単位で管理
  • 11.
    共有メモリ管理オブジェクト • include/linux/shm.h 9 struct shmid_kernel /* private to the kernel */ 10 { 11 struct kern_ipc_perm shm_perm; 12 struct file *shm_file; 13 unsigned long shm_nattch; 14 unsigned long shm_segsz; 15 time_t shm_atim; 16 time_t shm_dtim; 17 time_t shm_ctim; 18 pid_t shm_cprid; 19 pid_t shm_lprid; 20 struct user_struct *mlock_user; 21 22 /* The task created the shm object. NULL if the task is dead. */ 23 struct task_struct *shm_creator; 24 struct list_head shm_clist; /* list by creator */ 25 };
  • 12.
    セマフォ管理オブジェクト • include/linux/sem.h 12 struct sem_array { 13 struct kern_ipc_perm ____cacheline_aligned_in_smp 14 sem_perm; /* permissions .. see ipc.h */ 15 time_t sem_ctime; /* last change time */ 16 struct sem *sem_base; /* ptr to first semaphore in array */ 17 struct list_head pending_alter; /* pending operations */ 18 /* that alter the array */ 19 struct list_head pending_const; /* pending complex operations */ 20 /* that do not alter semvals */ 21 struct list_head list_id; /* undo requests on this array */ 22 int sem_nsems; /* no. of semaphores in array */ 23 int complex_count; /* pending complex operations */ 24 };
  • 13.
    message queue管理オブジェクト •include/linux/msg.h 18 struct msg_queue { 19 struct kern_ipc_perm q_perm; 20 time_t q_stime; /* last msgsnd time */ 21 time_t q_rtime; /* last msgrcv time */ 22 time_t q_ctime; /* last change time */ 23 unsigned long q_cbytes; /* current number of bytes on queue */ 24 unsigned long q_qnum; /* number of messages in queue */ 25 unsigned long q_qbytes; /* max number of bytes on queue */ 26 pid_t q_lspid; /* pid of last msgsnd */ 27 pid_t q_lrpid; /* last receive pid */ 28 29 struct list_head q_messages; 30 struct list_head q_receivers; 31 struct list_head q_senders; 32 };
  • 14.
    IPCパーミッション管理 • include/linux/ipc.h 11 struct kern_ipc_perm 12 { 13 spinlock_t lock; kuid_t・kgid_tはコンテナ型仮想 14 bool deleted; 化において、host側のuid/gitと 15 int id; guest側のuid/pidをマッピングす 16 key_t key; るための型。 17 kuid_t uid; 参照:http://www.slideshare.net/ 18 kgid_t gid; masamiichikawa/linux-namespace 19 kuid_t cuid; 20 kgid_t cgid; 21 umode_t mode; 22 unsigned long seq; 23 void *security; 24 };
  • 15.
    プロセスからIPCオブジェクトの参照 • セマフォ/共有メモリを作成すると、struct task_structのメンバ変数よりリストで繋がる 1385 #ifdef CONFIG_SYSVIPC 1386 /* ipc stuff */ 1387 struct sysv_sem sysvsem; 1388 struct sysv_shm sysvshm; 1389 #endif • メッセージキューは無し
  • 16.
    IPC Identifier •IPC Namespace単位で管理 • 管理する構造体はstruct ipc_ids • struct ipc_namespaceのメンバ変数ids[3]にて管理 29 struct ipc_namespace { 30 atomic_t count; 31 struct ipc_ids ids[3]; • 初期化のタイミングはIPC namespace作成時の create_ipc_ns() • ipc_addid()にてidを設定
  • 17.
    struct ipc_ids •include/linux/ipc_namespace.h 21 struct ipc_ids { 22 int in_use; 23 unsigned short seq; 24 struct rw_semaphore rwsem; 25 struct idr ipcs_idr; 26 int next_id; 27 }; IPC Object作成時に+1 IPC_RMIDの操作時に-1 idを振るときに使用 通常は-1を設定し、この番号を使いたい!という場合にsysctlで設定可能。 カーネルのconfigでCONFIG_CHECKPOINT_RESTOREが設定されている必要あり。 https://github.com/torvalds/linux/commit/03f595668017f1a1fb971c02fc37140bc6e7bb1c
  • 18.
    struct ipc_idsの初期化 •共有メモリの場合(セマフォ、メッセージも同 様の流れ) create_ipc_ns() --> shm_init_ns() --> ipc_init_ids()  初期化対象のstruct ipc_idsを渡す
  • 19.
    ipc_init_ids() • 引数で渡されたstructipc_idsの初期化 • 処理内容は各変数に初期値を設定する程度
  • 20.
    ipc_addid() • 関数プロトタイプ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int size) • IPC Identifierはnew->idに設定される • 戻り値のintはidr_alloc()の戻り値 • idr_alloc()の戻り値もidだけど、ipc_addid() の呼び出し元はこの変数はエラーチェックに しか使用しない
  • 21.
    ipc_addid()処理概要 • IPCIdentifierの使用数(in_use)のチェック • 最大で32768 • IDR APIによるidの取得 • in_useをインクリメント • kern_ipc_perm構造体にeuid、egidを設定 • next_idの値に応じてseq変数を設定 • ipc_buildid()でidになる値を計算して返す
  • 22.
    管理用オブジェクトのalloc • メモリ確保はすべてipc_rcu_alloc()にて実施 477 void *ipc_rcu_alloc(int size) 478 { 479 /* 480 * We prepend the allocation with the rcu struct 481 */ 482 struct ipc_rcu *out = ipc_alloc(sizeof(struct ipc_rcu) + size); 483 if (unlikely(!out)) 484 return NULL; 485 atomic_set(&out->refcount, 1); 486 return out + 1; 487 }
  • 23.
    ipc_rcu_allocが返すデータ構造 • メモリ上の構造は先頭にipc_rcu構造体が置か れ、その後ろに本来のデータを置く形 struct ipc_rcu struct shmid_kenel とか [kv]malloc()の返したアドレス ipc_rcu_alloc()が返すアドレス
  • 24.
    xxxget()共通処理 • shmget,semget, msggetはipcget()を共通の 処理として使用 • 機能固有の処理は関数ポインタを渡し、それを 実行してもらう • ipc_addid()でIPC 識別子を設定
  • 25.
    機能固有処理の登録 • ipc/util.hにあるstructipc_opsに関数をセット 80 struct ipc_ops { 81 int (*getnew)(struct ipc_namespace *, struct ipc_params *); 82 int (*associate)(struct kern_ipc_perm *, int); 83 int (*more_checks)(struct kern_ipc_perm *, struct ipc_params *); 84 }; • getnew() • 新規にIPCのオブジェクトを作成 • associate() • パーミッションのチェック • more_checks() • その他のチェック • optional
  • 26.
    ipcget() • keyにIPC_PRIVATEが設定されているかで分岐 • ipcget_new() • IPC_PRIVATE指定時 • ipcget_public() • IP_PRIVATE以外のキーが指定された場合
  • 27.
    ipcget()の流れ ipcget() -->ipcget_new() // if key is IPC_PRIVATE --> ipcget_public() // if key is not IPC_PRIVATE --> ipc_findkey() // find key --> ipcget_new() // if key is not found --> ipc_check_perms() // if found key --> (struct ips_ops *)->more_checks() --> (struct ips_ops *)->associate() ipcget_new() --> (struct ipc_ops *)->getnew()
  • 28.
    ipcget_new() • structipc_opsに設定されているgetnew()を呼 ぶ程度
  • 29.
    ipcget_public() • keyがnamespace中にあるかチェック • keyが見つからなかったらipcget_new()を呼ぶ • keyが見つかった • flagのチェック • ipc_opsのmore_checksがセットされていればそれを呼ぶ • ipc_check_perms()でパーミッションのチェックとipc_opsの associate()呼び出し • ipc_check_permsがシステムコール(xxxget())の戻り値となるidを返 す
  • 30.
    overview • libc側 • kernel側 • 主な構造体 • IPC全般の共通処理 • 共通処理(shmget、semget、msgget共通部) • 共有メモリ
  • 31.
    shmget • 共有メモリのセグメントを作成 • ipcget()からnewseg()が呼ばれる • struct ips_opsのgetnewにnewseg()を設定 • IPCの管理オブジェクトはstruct shmid_kernel • 作成したオブジェクトはcurrent->sysvshm.shm_clistにつながる • セグメントは擬似ファイルとして作る • SYSVxxxxxxxx(xはkey)というファイル名 • lsofすると以下のように表示される 41997 a.out 29678 root DEL REG 0,4 27394068 /SYSV00000000 • flagにSHM_HUGETLBによりファイルの作成方法が変わる • hugetlb_file_setup() or shmem_file_setup()
  • 32.
    セグメント作成の流れ • shmem_file_setup() • mm/shmem.cの__shmem_file_setup()が本 体 __shmem_file_setup() --> mntget() // path to mount directory --> d_alloc_pseudo() // allocate a dentry --> shmem_get_inode() // get an inode --> alloc_file() // allocate a file object
  • 33.
    shmat() • 実際の処理はdo_shmat() • 共有メモリ固有データ作成 • struct fileのprivate_dataへ設定する • ファイルオブジェクト(struct file)の作成 • ファイルはshmget()で作成した擬似ファイルを使用 • ファイルをmmap()でメモリにマップ • 使用するのはdo_mmap_pgoff() • do_mmap_pgoff()の返り値がshmat(2)の返り値になる
  • 34.
    セグメントattachの流れ do_shmat() -->path_get() // get a file path for shmem --> alloc_file() // allocate a file object --> do_mmap_pgoff() // map the file object --> shm_may_destroy() // check if other process destroying this shmem --> shm_destroy() // other process destorying this shmem --> shm_unlock() // no one destorys this shmem
  • 35.
    共有メモリ固有データ 50 structshm_file_data { 51 int id; 52 struct ipc_namespace *ns; 53 struct file *file; 54 const struct vm_operations_struct *vm_ops; 55 }; • 以下のデータを設定 • idにはkey • nsにはカレントプロセスのipc namespace • ipc namespaceのリファレンスカウンタをインクリメントする • fileにはnewseg()で作成したファイルオブジェクト • vm_opsにはNULL
  • 36.
    shmdt() • do_shmat()でmmap(do_mmap_pgoff)した領 域を解放 • アドレスに対して単純にdo_munmap()を呼べな い • アドレスがmlock()やmunmap()で変更されて いる可能性がある
  • 37.
    セグメントdetatchの流れ shmdt() -->find_vma() // find a vm_area_struct from address --> file_inode() // if vma is found, find an inode to get file(segment) size --> do_munmap() // unmap the address --> do_munmap()
  • 38.
    shmdt() • 処理はCONFIG_MMUがdefineされているかで違うが、ここではdefineされてい る場合を見る • do_unmap()は 複数回呼ばれる可能性がある • find_vma()でvmaが見つかった場合 • unmap対象のアドレスを探し、unmap()する • これは1回だけ • vmaがNULLでなく、vma->vm_end - addrの結果がセグメントサイズより小さ い間 • ここでは複数回do_unmap()を呼ぶ可能性がある
  • 39.
    shmctl() • セグメントに関して各種操作ができるが、破棄の 場合を見ていきます • 破棄 • swap禁止・禁止解除 • 情報取得 • etc…
  • 40.
    セグメント破棄の流れ shmctl() -->shmctl_down() --> do_shm_rmid() --> shm_unlock() // someone using this segment --> shm_destroy() // anyone using it --> shm_rmid() // remove id from namespace and segment's list --> shm_unlock() --> shm_lock() // if shmflg is not SHM_HUGETLB --> user_shm_unlock() // else if (struct shmid *)- >mlock_user isn't 0 --> fput() // remove file object
  • 41.
    shmctl_down() • shmctl(2)でcmdにIPC_RMIDもしくはIPC_SET を指定した時に呼ばれる • ロックを取るなどの部分はIPC_RMID、IPC_SET で共通 • cmdがIPC_RMIDの場合はdo_shm_rmid()を呼ぶ
  • 42.
    do_shm_rmid() • まだ誰かがセグメントにattachしている場合 • struct shmid_kenrnelのshm_perm.modeにSHM_DESTを セット • 削除予定フラグ • keyをIPC_PRIVATEに設定し、他から参照できないようにす る • 他にattachしているプロセスはいない • shm_destroy()を呼ぶ
  • 43.
    shm_destroy() • shm_rmid()を呼ぶ • namespaceからidの削除 • shm_clistのリストから管理オブジェクトを削除 • セグメントがhugetlbを使っていない場合 • shmem_lock()でセグメントがswap禁止になっていたら許可するように設定 • もしくはmlockされている場合 • 共有メモリで使用するmlock対象のページ数をstruct userのlocked_shmか ら減らす • fput()でnewseg()で作成したセグメント用のファイルオブジェクトを削除
  • 44.
    Reference • LXR • http://lxr.free-electrons.com/ • glibc git • https://sourceware.org/git/?p=glibc.git