SlideShare a Scribd company logo
1 of 44
Download to read offline
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

More Related Content

What's hot

C/C++プログラマのための開発ツール
C/C++プログラマのための開発ツールC/C++プログラマのための開発ツール
C/C++プログラマのための開発ツールMITSUNARI Shigeo
 
2011.09.18 v7から始めるunix まとめ
2011.09.18 v7から始めるunix まとめ2011.09.18 v7から始めるunix まとめ
2011.09.18 v7から始めるunix まとめMakiko Konoshima
 
Node-v0.12の新機能について
Node-v0.12の新機能についてNode-v0.12の新機能について
Node-v0.12の新機能についてshigeki_ohtsu
 
Unixカーネルの設計 7 プロセスの制御
Unixカーネルの設計 7 プロセスの制御Unixカーネルの設計 7 プロセスの制御
Unixカーネルの設計 7 プロセスの制御Norito Agetsuma
 
あるコンテキストスイッチの話
あるコンテキストスイッチの話あるコンテキストスイッチの話
あるコンテキストスイッチの話nullnilaki
 
GoogleのSHA-1のはなし
GoogleのSHA-1のはなしGoogleのSHA-1のはなし
GoogleのSHA-1のはなしMITSUNARI Shigeo
 
ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。Kazuki Onishi
 
Deep Dive async/await in Unity with UniTask(UniRx.Async)
Deep Dive async/await in Unity with UniTask(UniRx.Async)Deep Dive async/await in Unity with UniTask(UniRx.Async)
Deep Dive async/await in Unity with UniTask(UniRx.Async)Yoshifumi Kawai
 
HandlerSocket plugin for MySQL
HandlerSocket plugin for MySQLHandlerSocket plugin for MySQL
HandlerSocket plugin for MySQLakirahiguchi
 
Nodejuku01 ohtsu
Nodejuku01 ohtsuNodejuku01 ohtsu
Nodejuku01 ohtsuNanha Park
 
JVM-Reading-ConcurrentMarkSweep
JVM-Reading-ConcurrentMarkSweepJVM-Reading-ConcurrentMarkSweep
JVM-Reading-ConcurrentMarkSweepMinoru Nakamura
 
社内勉強会資料(Varnish Module)
社内勉強会資料(Varnish Module)社内勉強会資料(Varnish Module)
社内勉強会資料(Varnish Module)Iwana Chan
 
Varnish 4.0 Release Party in Tokyo発表資料
Varnish 4.0 Release Party in Tokyo発表資料Varnish 4.0 Release Party in Tokyo発表資料
Varnish 4.0 Release Party in Tokyo発表資料Iwana Chan
 
位置情報を使ったサービス「スマポ」をPostgreSQLで作ってみた db tech showcase 2013 Tokyo
位置情報を使ったサービス「スマポ」をPostgreSQLで作ってみた db tech showcase 2013 Tokyo位置情報を使ったサービス「スマポ」をPostgreSQLで作ってみた db tech showcase 2013 Tokyo
位置情報を使ったサービス「スマポ」をPostgreSQLで作ってみた db tech showcase 2013 TokyoYoshiyuki Asaba
 
BLS署名の実装とその応用
BLS署名の実装とその応用BLS署名の実装とその応用
BLS署名の実装とその応用MITSUNARI Shigeo
 
async/await のしくみ
async/await のしくみasync/await のしくみ
async/await のしくみ信之 岩永
 

What's hot (20)

C/C++プログラマのための開発ツール
C/C++プログラマのための開発ツールC/C++プログラマのための開発ツール
C/C++プログラマのための開発ツール
 
2011.09.18 v7から始めるunix まとめ
2011.09.18 v7から始めるunix まとめ2011.09.18 v7から始めるunix まとめ
2011.09.18 v7から始めるunix まとめ
 
Node-v0.12の新機能について
Node-v0.12の新機能についてNode-v0.12の新機能について
Node-v0.12の新機能について
 
Unixカーネルの設計 7 プロセスの制御
Unixカーネルの設計 7 プロセスの制御Unixカーネルの設計 7 プロセスの制御
Unixカーネルの設計 7 プロセスの制御
 
あるコンテキストスイッチの話
あるコンテキストスイッチの話あるコンテキストスイッチの話
あるコンテキストスイッチの話
 
GoogleのSHA-1のはなし
GoogleのSHA-1のはなしGoogleのSHA-1のはなし
GoogleのSHA-1のはなし
 
Memory sanitizer
Memory sanitizerMemory sanitizer
Memory sanitizer
 
Stream2の基本
Stream2の基本Stream2の基本
Stream2の基本
 
ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。
 
Kernel fcache-bug
Kernel fcache-bugKernel fcache-bug
Kernel fcache-bug
 
ゆるバグ
ゆるバグゆるバグ
ゆるバグ
 
Deep Dive async/await in Unity with UniTask(UniRx.Async)
Deep Dive async/await in Unity with UniTask(UniRx.Async)Deep Dive async/await in Unity with UniTask(UniRx.Async)
Deep Dive async/await in Unity with UniTask(UniRx.Async)
 
HandlerSocket plugin for MySQL
HandlerSocket plugin for MySQLHandlerSocket plugin for MySQL
HandlerSocket plugin for MySQL
 
Nodejuku01 ohtsu
Nodejuku01 ohtsuNodejuku01 ohtsu
Nodejuku01 ohtsu
 
JVM-Reading-ConcurrentMarkSweep
JVM-Reading-ConcurrentMarkSweepJVM-Reading-ConcurrentMarkSweep
JVM-Reading-ConcurrentMarkSweep
 
社内勉強会資料(Varnish Module)
社内勉強会資料(Varnish Module)社内勉強会資料(Varnish Module)
社内勉強会資料(Varnish Module)
 
Varnish 4.0 Release Party in Tokyo発表資料
Varnish 4.0 Release Party in Tokyo発表資料Varnish 4.0 Release Party in Tokyo発表資料
Varnish 4.0 Release Party in Tokyo発表資料
 
位置情報を使ったサービス「スマポ」をPostgreSQLで作ってみた db tech showcase 2013 Tokyo
位置情報を使ったサービス「スマポ」をPostgreSQLで作ってみた db tech showcase 2013 Tokyo位置情報を使ったサービス「スマポ」をPostgreSQLで作ってみた db tech showcase 2013 Tokyo
位置情報を使ったサービス「スマポ」をPostgreSQLで作ってみた db tech showcase 2013 Tokyo
 
BLS署名の実装とその応用
BLS署名の実装とその応用BLS署名の実装とその応用
BLS署名の実装とその応用
 
async/await のしくみ
async/await のしくみasync/await のしくみ
async/await のしくみ
 

Similar to SystemV IPC

ホームディレクトリに埋もれた便利なコードをさがせ!
ホームディレクトリに埋もれた便利なコードをさがせ!ホームディレクトリに埋もれた便利なコードをさがせ!
ホームディレクトリに埋もれた便利なコードをさがせ!Yohei Fushii
 
PyOpenCLによるGPGPU入門
PyOpenCLによるGPGPU入門PyOpenCLによるGPGPU入門
PyOpenCLによるGPGPU入門Yosuke Onoue
 
Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Linuxのプロセススケジューラ(Reading the Linux process scheduler)Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Linuxのプロセススケジューラ(Reading the Linux process scheduler)Hiraku Toyooka
 
ROP Illmatic: Exploring Universal ROP on glibc x86-64 (ja)
ROP Illmatic: Exploring Universal ROP on glibc x86-64 (ja)ROP Illmatic: Exploring Universal ROP on glibc x86-64 (ja)
ROP Illmatic: Exploring Universal ROP on glibc x86-64 (ja)inaz2
 
JIT のコードを読んでみた
JIT のコードを読んでみたJIT のコードを読んでみた
JIT のコードを読んでみたy-uti
 
MINCS – containers in the shell script
MINCS – containers in the shell scriptMINCS – containers in the shell script
MINCS – containers in the shell scriptMasami Hiramatsu
 
2011.06.11 v7から始めるunix まとめ
2011.06.11 v7から始めるunix まとめ2011.06.11 v7から始めるunix まとめ
2011.06.11 v7から始めるunix まとめMakiko Konoshima
 
#logstudy 01 rsyslog入門
#logstudy 01 rsyslog入門#logstudy 01 rsyslog入門
#logstudy 01 rsyslog入門Takashi Takizawa
 
【学習メモ#8th】12ステップで作る組込みOS自作入門
【学習メモ#8th】12ステップで作る組込みOS自作入門 【学習メモ#8th】12ステップで作る組込みOS自作入門
【学習メモ#8th】12ステップで作る組込みOS自作入門 sandai
 
PEZY-SC programming overview
PEZY-SC programming overviewPEZY-SC programming overview
PEZY-SC programming overviewRyo Sakamoto
 
○○大学の本当にあった怖い話
○○大学の本当にあった怖い話○○大学の本当にあった怖い話
○○大学の本当にあった怖い話idkqh7 Nishino
 
Pythonによる並列プログラミング -GPGPUも-
Pythonによる並列プログラミング   -GPGPUも- Pythonによる並列プログラミング   -GPGPUも-
Pythonによる並列プログラミング -GPGPUも- Yusaku Watanabe
 
Node予備校 vol.1 名古屋
Node予備校 vol.1 名古屋Node予備校 vol.1 名古屋
Node予備校 vol.1 名古屋Mori Shingo
 
さわってみようTOPPERS/SSP
さわってみようTOPPERS/SSPさわってみようTOPPERS/SSP
さわってみようTOPPERS/SSPNSaitoNmiri
 

Similar to SystemV IPC (20)

ホームディレクトリに埋もれた便利なコードをさがせ!
ホームディレクトリに埋もれた便利なコードをさがせ!ホームディレクトリに埋もれた便利なコードをさがせ!
ホームディレクトリに埋もれた便利なコードをさがせ!
 
PyOpenCLによるGPGPU入門
PyOpenCLによるGPGPU入門PyOpenCLによるGPGPU入門
PyOpenCLによるGPGPU入門
 
Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Linuxのプロセススケジューラ(Reading the Linux process scheduler)Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Linuxのプロセススケジューラ(Reading the Linux process scheduler)
 
ROP Illmatic: Exploring Universal ROP on glibc x86-64 (ja)
ROP Illmatic: Exploring Universal ROP on glibc x86-64 (ja)ROP Illmatic: Exploring Universal ROP on glibc x86-64 (ja)
ROP Illmatic: Exploring Universal ROP on glibc x86-64 (ja)
 
Gingerbread
GingerbreadGingerbread
Gingerbread
 
JIT のコードを読んでみた
JIT のコードを読んでみたJIT のコードを読んでみた
JIT のコードを読んでみた
 
MINCS – containers in the shell script
MINCS – containers in the shell scriptMINCS – containers in the shell script
MINCS – containers in the shell script
 
2011.06.11 v7から始めるunix まとめ
2011.06.11 v7から始めるunix まとめ2011.06.11 v7から始めるunix まとめ
2011.06.11 v7から始めるunix まとめ
 
Linux Namespace
Linux NamespaceLinux Namespace
Linux Namespace
 
#logstudy 01 rsyslog入門
#logstudy 01 rsyslog入門#logstudy 01 rsyslog入門
#logstudy 01 rsyslog入門
 
initramfsについて
initramfsについてinitramfsについて
initramfsについて
 
【学習メモ#8th】12ステップで作る組込みOS自作入門
【学習メモ#8th】12ステップで作る組込みOS自作入門 【学習メモ#8th】12ステップで作る組込みOS自作入門
【学習メモ#8th】12ステップで作る組込みOS自作入門
 
PEZY-SC programming overview
PEZY-SC programming overviewPEZY-SC programming overview
PEZY-SC programming overview
 
○○大学の本当にあった怖い話
○○大学の本当にあった怖い話○○大学の本当にあった怖い話
○○大学の本当にあった怖い話
 
Capistrano
CapistranoCapistrano
Capistrano
 
Pythonによる並列プログラミング -GPGPUも-
Pythonによる並列プログラミング   -GPGPUも- Pythonによる並列プログラミング   -GPGPUも-
Pythonによる並列プログラミング -GPGPUも-
 
Ext4 filesystem(1)
Ext4 filesystem(1)Ext4 filesystem(1)
Ext4 filesystem(1)
 
Node予備校 vol.1 名古屋
Node予備校 vol.1 名古屋Node予備校 vol.1 名古屋
Node予備校 vol.1 名古屋
 
T93 com入門
T93 com入門T93 com入門
T93 com入門
 
さわってみようTOPPERS/SSP
さわってみようTOPPERS/SSPさわってみようTOPPERS/SSP
さわってみようTOPPERS/SSP
 

SystemV IPC

  • 1. SystemV IPC Masami Ichikawa (@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. 主な構造体 • IPC objectの管理 • セマフォ、共有メモリ、メッセージキュー固有の構造体 • パーミッションの管理 • 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() • 引数で渡されたstruct ipc_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()処理概要 • IPC Identifierの使用数(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にある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
  • 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() • struct ipc_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 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
  • 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