> ## Documentation Index
> Fetch the complete documentation index at: https://zinc.ossl.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Core Concepts

> Regions, handles, naming, and the architecture of shared memory

## SharedRegion

`SharedRegion` is the central type in Zinc. It represents a handle to a mapped shared memory segment. Every language adapter wraps this concept in its native type system: a class in Python, Go, Java, and C#, a struct in Rust, a header-only class in C++.

A region is created by one process and opened by others. The creator's handle carries ownership privileges. Openers get read/write access to the data area. This isn't about security — it's about lifecycle: only the creator may unlink the segment from the system.

```rust theme={null}
// Creator: owns the segment, may unlink on drop
let region = SharedRegion::create("my-segment", 65536);

// Opener: reads and writes, but cannot unlink
let region = SharedRegion::open("my-segment");
```

## Memory layout

Every mapped region starts with a 64-byte header — exactly one cache line on modern x86 and ARM. The header stores library metadata: a magic number for corruption detection, a version field for forward compatibility, a reference count, the creator's PID, and the notification sequence counter.

```
Offset  Size  Field         Description
------  ----  -----         -----------
0       8     magic         Must equal 0x5A494E435F524547 ("ZINC_REG")
8       2     version       Breaking-change guard (currently 1)
10      2     flags         Reserved for future use
12      4     notify_seq    Futex/semaphore signal counter
16      8     capacity      Usable bytes after the header
24      4     ref_count     Atomic reference count
28      4     owner_pid     PID of the creating process
32      8     created_at    Unix timestamp in nanoseconds
40      8     name_hash     FNV-1a hash of the region name
48      8     ring_head     Notification ring write head
56      8     ring_tail     Notification ring read tail
```

The usable data area begins at byte 64 and extends for `capacity` bytes.

## Naming

Each shared region has a name, chosen by the creator, that serves as its identifier on the system. Other processes use this name to open the region.

Names must be non-empty and contain only ASCII alphanumeric characters, underscores, and hyphens. The pattern is `[a-zA-Z0-9_-]+`. Spaces, dots, slashes, and other special characters are rejected at the API level before any system call is made. This validation is identical across all adapters since it happens in the Rust core.

On Linux and macOS, the name is prefixed with `/zinc_` internally when passed to `shm_open`. So a region named `my-data` becomes a POSIX shared memory object named `/zinc_my-data`. The prefix avoids collisions with other shared memory users on the system.

## Ownership and lifecycle

The lifecycle of a shared region follows these rules:

1. A process calls `create` to establish a new region. The region is backed by `shm_open` with `O_CREAT | O_EXCL`, which fails atomically if a region with the same name already exists.

2. Other processes call `open` to attach to the existing region. `open` increments the atomic reference count stored in the header.

3. Any process can read and write the data area. There is no access control beyond file permissions on the shared memory object.

4. When a process is done, it calls `close` (or drops the handle in languages with destructors). This decrements the reference count.

5. When the creator's handle is closed and the reference count reaches zero, the region is automatically unlinked. The memory is freed once all mapped copies are unmapped.

6. If an opener closes before the creator, the region stays alive. The creator retains ownership.

7. If the creator crashes or forgets to unlink, the region persists in the system. Clean up stale segments by unlinking the name and creating a new one.

## The 8 C functions

All language adapters call the same C ABI surface. Every function takes or returns opaque handles and primitive types only.

| Function        | Purpose                                                     |
| --------------- | ----------------------------------------------------------- |
| `zinc_create`   | Create a region. Returns handle, caller owns it.            |
| `zinc_open`     | Open an existing region by name. Returns handle.            |
| `zinc_ptr`      | Get raw pointer to the data area (first byte after header). |
| `zinc_capacity` | Get usable size in bytes.                                   |
| `zinc_close`    | Close handle. Decrements ref count. May trigger unlink.     |
| `zinc_notify`   | Signal all waiters that data has changed.                   |
| `zinc_wait`     | Block until notified or timeout.                            |
| `zinc_version`  | Get library version for compatibility checks.               |

Error codes follow POSIX conventions: zero means success, negative values indicate specific errors. Every adapter translates these into language-native exceptions or error types.

## Zero-copy guarantee

Zinc provides one zero-copy guarantee and one caveat.

The guarantee: when you call `zinc_ptr` (or the adapter method that wraps it, such as `as_buffer()`, `Bytes()`, or `buffer()`), the returned pointer or buffer view points directly into the mapped memory. No copying occurs. A write through one adapter is immediately visible to all other adapters mapping the same region.

The caveat: Zinc does not provide built-in data structure serialization. If you write a Rust struct to shared memory and read it from Python, you must ensure the memory layout matches. For primitive arrays and flat structs, this is straightforward. For complex nested types, you need a wire format such as FlatBuffers or Cap'n Proto that can operate on shared memory directly.

## Synchronization

Zinc provides a lightweight notify/wait mechanism built on an atomic sequence counter. Not a general-purpose synchronization primitive. It solves one pattern: a producer writes data, then signals consumers.

For complex synchronization — multiple producers, reader-writer locks, condition variables that guard multi-field updates — reach for atomic operations on the shared data itself. The notify/wait mechanism only signals that *something* changed. It does not say what changed or protect against races.

See the [notify/wait guide](/guides/notify-wait) for detailed usage.
