--- name: System V IPC tutorial --- # System V IPC System V IPC gives two unrelated processes a shared resource the kernel owns: a **semaphore set** for coordination, or a **shared memory segment** for passing bytes with no copying through a pipe. Each resource is identified by an integer key and survives until a process explicitly removes it. The convenience modules `IPC::SysV`, `IPC::Semaphore`, and `IPC::SharedMem` are not available in PetaPerl, so the recipes here use the raw [`semget`](../../p5/core/perlfunc/semget) / [`shmget`](../../p5/core/perlfunc/shmget) built-in family with the flag values written as plain numbers. Those built-ins are the layer the modules wrap; using them directly costs only a few named constants you supply yourself. ## The flag constants you need A handful of small integers control how these calls behave. They are the standard Linux values: ```perl use constant { IPC_PRIVATE => 0, # "give me a fresh, private key" IPC_CREAT => 0o1000, # create the resource if absent IPC_EXCL => 0o2000, # fail if it already exists IPC_RMID => 0, # control command: remove the resource }; ``` The low nine bits of the flag word are ordinary permission bits, the same `0600` / `0644` you would pass to [`chmod`](../../p5/core/perlfunc/chmod). `IPC_CREAT | 0600` means "create it, owner read/write". ## A shared-memory hand-off Shared memory is the fastest channel: one process writes bytes into a segment, another reads them straight out, with no kernel copy in between. This program creates a segment, writes a payload, forks, and the child reads the same bytes back: ```perl use constant { IPC_PRIVATE => 0, IPC_CREAT => 0o1000, IPC_RMID => 0, }; my $size = 1024; my $id = shmget(IPC_PRIVATE, $size, IPC_CREAT | 0600); defined $id or die "shmget: $!"; my $payload = "shared-payload"; shmwrite($id, $payload, 0, length $payload) or die "shmwrite: $!"; my $kid = fork() // die "fork: $!"; if ($kid == 0) { # Child reads the same segment the parent wrote. shmread($id, my $buf, 0, length $payload) or die "shmread: $!"; print "child read: $buf\n"; # child read: shared-payload exit 0; } waitpid($kid, 0); # The segment outlives the processes - remove it explicitly. shmctl($id, IPC_RMID, 0) or warn "shmctl: $!"; ``` Two points decide whether this code leaks: - **`shmread` / `shmwrite` take an explicit length.** They do not stop at a NUL or a newline; you tell them exactly how many bytes to move, starting at an offset. Pass `length $payload` so reader and writer agree on the size. - **`IPC_RMID` is not automatic.** A shared segment persists in the kernel after every process attached to it has exited. You can see orphaned segments with `ipcs -m` at the shell. Always pair a [`shmget`](../../p5/core/perlfunc/shmget) with a matching [`shmctl`](../../p5/core/perlfunc/shmctl) `IPC_RMID`. ## A semaphore for coordination A semaphore set is a small array of counters the kernel guards. The classic use is a lock: a process decrements the counter to enter a critical section and increments it to leave. This recipe creates a one-element set, initialises it, and removes it: ```perl use constant { IPC_PRIVATE => 0, IPC_CREAT => 0o1000, IPC_RMID => 0, SETVAL => 16, # semctl command: set one value GETVAL => 12, # semctl command: read one value }; # A set with one semaphore. my $sem = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600); defined $sem or die "semget: $!"; # Initialise semaphore 0 to the value 1 (one token available). semctl($sem, 0, SETVAL, 1) or die "semctl SETVAL: $!"; my $value = semctl($sem, 0, GETVAL, 0); print "semaphore value: $value\n"; # semaphore value: 1 # Remove the set when finished. semctl($sem, 0, IPC_RMID, 0) or warn "semctl IPC_RMID: $!"; ``` The wait/signal operations themselves go through [`semop`](../../p5/core/perlfunc/semop), which takes a packed string of `(sem_num, sem_op, sem_flg)` triples built with [`pack`](../../p5/core/perlfunc/pack). Decrementing by one waits until a token is free; incrementing by one releases it. As with shared memory, a semaphore set the kernel owns must be removed with `IPC_RMID` or it lingers - visible under `ipcs -s`. ## Reference cross-links - [`shmget`](../../p5/core/perlfunc/shmget) - create or open a shared segment - [`shmread`](../../p5/core/perlfunc/shmread) / [`shmwrite`](../../p5/core/perlfunc/shmwrite) - move bytes in and out - [`shmctl`](../../p5/core/perlfunc/shmctl) - control, including `IPC_RMID` - [`semget`](../../p5/core/perlfunc/semget) - create or open a semaphore set - [`semop`](../../p5/core/perlfunc/semop) - the wait/signal operations - [`semctl`](../../p5/core/perlfunc/semctl) - set, read, and remove - [`pack`](../../p5/core/perlfunc/pack) - build the `semop` operation string ## Next Shared memory and semaphores are the heavyweight channels. For the lighter, stream-oriented ones, see [Subprocesses and co-processes](subprocesses) and [TCP sockets](sockets-tcp).