shmat, shmdt - System V 共有メモリ (shared memory)
の操作
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
shmat() は
shmid
で指定された System V
共有メモリ・セグメント
(shared memory segment) を
コールしたプロセスのアドレス空間に付加
(attach) する。
付加するアドレスは
shmaddr
に以下のどれかの形式で指定する:
shmaddr が NULL
ならば、システムはセグメントを付加するための
適切な
(使用されていない)
アドレスを選択する。
shmaddr が NULL でなく
SHM_RND が
shmflg
に指定されている場合は、
shmaddr を
SHMLBA
の倍数へと切り捨てた
(rounding down)
のと等しいアドレスへ付加する。
その他の場合は
shmaddr
は付加を行なうアドレスで、ページ境界を指している必要がある。
SHM_RDONLY が
shmflg
に指定されていた場合は、
セグメントは読み込み専用に付加され、プロセスはそのセグメントへの
読み込み許可を持たなければならない。
そうでなければそのセグメントは読み込みと書き込みのために付加され、
プロセスはそのセグメントに読み込みと書き込みの許可を持つ必要がある。
書き込み専用の共有メモリ・セグメントという概念は存在しない。
(Linux 特有の)
SHM_REMAP
フラグが
shmflg
に指定された場合は、
セグメントのマッピングを既存のマッピングに置き換える。
マッピングの範囲は、
shmaddr
から始まりセグメントのサイズ分だけある
(通常
EINVAL
エラーは、このアドレス範囲にマッピングが既に存在するために起る)。
このフラグを指定する場合は、
shmaddr が NULL
であってはならない。
呼び出したプロセスの
brk(2)
の値は付加によって変化しない。
そのセグメントはプロセスが終了
(exit)
したら自動的に分離
(detach) される。
同じセグメントをプロセスのアドレス空間に、読み込み専用および読み書き両用
として付加でき、また複数回付加することもできる。
成功した
shmat()
コールは共有メモリ・セグメントに関連する
shmid_ds 構造体 (
shmctl(2)
を参照)
のメンバーを以下のように更新する:
- shm_atime
には現在の時刻を設定する。
- shm_lpid
には呼び出したプロセスのプロセス
ID が設定される。
- shm_nattch を 1
増加させる。
shmdt()
は呼び出したプロセスのアドレス空間から
shmaddr
で指定されたアドレスに配置された共有メモリ・セグメントを分離
(detach) する。
分離する共有メモリ・セグメントは、現在
shmaddr
に付加されているものでなければならない。
shmaddr
は、それを付加した時に
shmat()
が返した値に等しくなければならない。
成功した
shmdt()
コールはその共有メモリ・セグメントに関連する
shmid_ds
構造体のメンバーを以下のように更新する:
- shm_dtime
には現在の時刻が設定される。
- shm_lpid
には呼び出したプロセスのプロセス
ID が設定される。
- shm_nattch を 1
減少させる。 もし 0
になり、削除マークがあった場合は
そのセグメントは削除される。
fork(2)
した後、子プロセスは付加された共有メモリ・セグメントを継承する。
exec(2)
した後、全ての付加された共有メモリ・セグメントはプロセスから分離される。
exit(2)
において、全ての付加された共有メモリ・セグメントはプロセスから分離される。
返り値¶
shmat()
は、成功した場合、
付加された共有メモリ・セグメントのアドレスを返す。
エラーの場合、
(void *) -1 を返し、
errno
にエラーの原因を示す値を設定する。
shmdt() は、成功すると 0
を返す。
エラーの場合、-1
を返し、
errno
にエラーの原因を示す値を設定する。
エラー¶
shmat() が失敗した場合、
errno
に以下の値のどれかを設定して返す:
- EACCES
- 呼び出したプロセスに要求された種類の付加に必要な許可がなく、
CAP_IPC_OWNER
ケーパビリティ (capability)
がない。
- EIDRM
- shmid が削除 (remove)
された識別子 (identifier)
を指している。
- EINVAL
- shmid
の値が不正である。
shmaddr の値が境界違反
(unaligned)
(つまり、ページ境界に合っておらず、
SHM_RND
が指定されていない)
または
が不正である。 shmaddr
へのセグメントの付加に失敗した。
または SHM_REMAP
が指定されているが、
shmaddr が NULL であった。
- ENOMEM
- ディスクリプター
(descriptor)
やページ・テーブルのためのメモリを
割り当てることができない。
shmdt() が失敗した場合、
EINVAL
は以下のようにセットされる:
- EINVAL
- shmaddr
に付加された共有メモリ・セグメントが存在しない。
もしくは、 shmaddr
がページ境界に合っていない。
SVr4, POSIX.1-2001.
SVID 3 で
(たぶんそれより前だと思うが)
shmaddr 引き数の型は
char * から
const void *
に、
shmat()
の返り値の型は
char *
から
void *
に変更された (Linux では libc4
と libc5
のプロトタイプは
char * であり、glibc2
のプロトタイプは
void * である)。
共有メモリセグメントを付加する場合の移植性の高い方法としては、
shmaddr を NULL にして
shmat()
を使用するのがよい。
このような方法で付加される共有メモリセグメントは、
プロセスが異なれば別のアドレスに付加される、という点に注意すること。
よって共有メモリ内で管理されるポインタは、
絶対アドレスではなく、
(一般的にはセグメントの開始アドレスからの)
相対アドレスで作成するべきである。
Linux
では共有メモリセグメントに既に削除マークが付けられていても、
その共有メモリセグメントを付加することができる。
しかし POSIX.1-2001
ではこのような動作を指定しておらず、
他の多くの実装もこれをサポートしていない。
以下のシステム・パラメーターは、
shmat() に影響する:
- SHMLBA
- セグメントの境界アドレスの最小倍数。ページ境界に合ってなければならない。
現在の実装では SHMLBA
の値は PAGE_SIZE
である。
現在の実装では、プロセスごとの
共有メモリ・セグメントの最大数
(
SHMSEG)
に関する実装依存の制限はない。
関連項目¶
brk(2),
mmap(2),
shmctl(2),
shmget(2),
capabilities(7),
shm_overview(7),
svipc(7)
この文書について¶
この man ページは Linux
man-pages
プロジェクトのリリース
3.65 の一部
である。プロジェクトの説明とバグ報告に関する情報は
http://www.kernel.org/doc/man-pages/
に書かれている。