semget()は以前のエントリ(Linuxカーネル:SystemV IPC get系操作の共通実装部分を読む - φ(・・*)ゞ ウーン カーネルとか弄ったりのメモ)で書いたようにSystemV IPC共通部分と機能固有部分に分かれていて、semget()の場合はnewary()が使われます。
というわけでnewary()を見ていきます。
最初は特筆することはないですね。
477 static int newary(struct ipc_namespace *ns, struct ipc_params *params) 478 { 479 int id; 480 int retval; 481 struct sem_array *sma; 482 int size; 483 key_t key = params->key; 484 int nsems = params->u.nsems; 485 int semflg = params->flg; 486 int i;
最初にsemget(2)の2番目の引数をチェック。次のチェックは現在のセマフォ数にnsemsを足した結果が、maxのセマフォ数を超えるかどうかのチェックです。ちなみにsc_semmnsは構造体のメンバではなくてsem_ctls[1]のdefineです。
488 if (!nsems) 489 return -EINVAL; 490 if (ns->used_sems + nsems > ns->sc_semmns) 491 return -ENOSPC;
セマフォを管理するstruct sem_array用にメモリを確保。これはshmget()の時と同様です。気になる方はLinux SystemV IPC: shmgetの実装を読む - φ(・・*)ゞ ウーン カーネルとか弄ったりのメモをどぞ。
493 size = sizeof(*sma) + nsems * sizeof(struct sem); 494 sma = ipc_rcu_alloc(size); 495 if (!sma) 496 return -ENOMEM; 497 498 memset(sma, 0, size);
パーミッション関連の設定。
500 sma->sem_perm.mode = (semflg & S_IRWXUGO); 501 sma->sem_perm.key = key;
毎度おなじみのselinux関連部分なので気にしません。
503 sma->sem_perm.security = NULL; 504 retval = security_sem_alloc(sma); 505 if (retval) { 506 ipc_rcu_putref(sma, ipc_rcu_free); 507 return retval; 508 }
ここはstruct idrを使ったidの取得です。
510 id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni); 511 if (id < 0) { 512 ipc_rcu_putref(sma, sem_rcu_free); 513 return id; 514 }
確保したセマフォ数を使用済みの数に追加。
515 ns->used_sems += nsems;
セマフォのベースアドレスを設定していますが、0番目の要素を渡していません。ここだけだとなんで1番目と思いますよね。
517 sma->sem_base = (struct sem *) &sma[1]; 518
これはsmaをallocする時のサイズが以下のように計算されていて、本当のデータはsizeof(*sma)以降の要素でインデックスとして1なんじゃないかと思います。
493 size = sizeof(*sma) + nsems * sizeof(struct sem);
smaの型はstruct sem_arrayです。struct sem_arrayは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 };
ここは見た通りの処理ですね。
519 for (i = 0; i < nsems; i++) { 520 INIT_LIST_HEAD(&sma->sem_base[i].pending_alter); 521 INIT_LIST_HEAD(&sma->sem_base[i].pending_const); 522 spin_lock_init(&sma->sem_base[i].lock); 523 }
ここから最後のreturn文までも特にこれといったことはしていないですね。戻り値はsma->sem_perm.idですが、この値は最初にsmaをmemsetして以降は誰も触っていないはずなので0が返るはずです。
525 sma->complex_count = 0; 526 INIT_LIST_HEAD(&sma->pending_alter); 527 INIT_LIST_HEAD(&sma->pending_const); 528 INIT_LIST_HEAD(&sma->list_id); 529 sma->sem_nsems = nsems; 530 sma->sem_ctime = get_seconds(); 531 sem_unlock(sma, -1); 532 rcu_read_unlock(); 533 534 return sma->sem_perm.id;
リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)
- 作者: Dustin Boswell,Trevor Foucher,須藤功平,角征典
- 出版社/メーカー: オライリージャパン
- 発売日: 2012/06/23
- メディア: 単行本(ソフトカバー)
- 購入: 68人 クリック: 1,802回
- この商品を含むブログ (117件) を見る