---
id: 43974d116e135fd9d3478f658dcf71c6
author: Lemon Mint
title: 'HQQ: Mengisolasi Pustaka C dari Go melalui Memori Bersama Cache-Line'
description: Runtime IPC tanpa cgo, kompilator IDL (hqq-bindgen), dan supervisor proses terverifikasi yang menjalankan pustaka C11 native dalam proses pekerja terisolasi melalui ring memori bersama.
language: id
date: 2026-10-18T13:56:46.094643498Z
path: /hqq
go_package: gosuda.org/hqq
go_repourl: https://github.com/gosuda/HQQ.git
category: lowlevel
---

`gosuda.org/hqq` adalah runtime komunikasi antarproses tanpa zero-cgo dan toolchain pembangkitan kode untuk Go dan C11. Runtime ini mengisolasi pustaka C native di dalam proses pekerja OS yang terpisah dan menghubungkannya ke pemanggil Go melalui ring memori bersama yang dipetakan dengan memory-mapped dan diselaraskan pada batas cache line. Proyek ini menggabungkan dua tingkat transport (`StandardLink` untuk sesi single-producer single-consumer khusus dan `Advanced` untuk dispatch MPMC multi-pekerja), compiler IDL `hqq-bindgen`, serta supervisor proses yang terverifikasi integritasnya (`secureexec` dan `launch`).

```bash
go get gosuda.org/hqq
```

## Biaya Berbagi Ruang Alamat dengan C

Setiap insinyur sistem Go pada akhirnya menghadapi persimpangan jalan yang sama. Anda sedang membangun layanan Go yang dikompilasi dalam hitungan detik dengan `CGO_ENABLED=0`, didistribusikan sebagai satu binary statis tunggal, dikompilasi silang dari laptop ke target Linux atau Windows tanpa sysroot, dan berjalan di dalam heap yang aman terhadap memori dan dikelola oleh garbage collector. Kemudian Anda memerlukan pustaka C yang matang: SQLite untuk penyimpanan relasional tersemat, Zstandard (`libzstd`) untuk kompresi berbasis kamus, atau pustaka media maupun kriptografi yang diakselerasi perangkat keras.

Mengaktifkan `cgo` untuk menautkan pustaka C tersebut ke dalam proses Go memang menyelesaikan masalah binding secara langsung, tetapi memperkenalkan tiga kelemahan struktural:

1. **Keterkaitan Toolchain dan Kompilasi Silang**: `CGO_ENABLED=1` memerlukan compiler C, header libc target, dan linker platform untuk setiap OS dan arsitektur target. Membangun artefak `linux/arm64` atau `windows/arm64` dari workstation `darwin/arm64` mengubah satu perintah `go build` menjadi matriks cross-compiler dan sysroot.
2. **Overhead Penjadwalan Runtime**: Setiap panggilan `cgo` melintasi batas runtime Go, berpindah dari stack goroutine yang dapat tumbuh ke system stack, dan mengunci thread OS (`M`). Untuk panggilan berbutir halus, biaya transisi (sekitar 50 hingga 150 ns per panggilan) dan kontensi penjadwal terakumulasi dengan cepat.
3. **Runtuhnya Domain Kegagalan**: Kode C berjalan dalam ruang alamat virtual yang sama dengan runtime Go. Satu penulisan di luar batas, use-after-free, stack overflow, atau `abort()` di dalam fungsi C dapat merusak metadata heap Go atau langsung menghentikan seluruh proses server, melewati `recover()` dan menjatuhkan setiap permintaan HTTP atau RPC yang sedang berjalan.

Ketika tim berupaya menghindari `cgo`, alternatif yang umum memaksa kompromi yang berbeda. Terjemahan mekanis murni dari basis kode C ke Go mempertahankan `CGO_ENABLED=0`, tetapi sering tertinggal dari rilis C hulu, membawa lapisan memori virtual yang diemulasi, dan mengalokasikan memori secara intensif di bawah beban. Memindahkan pustaka C ke proses pembantu melalui loopback TCP atau Unix domain socket memulihkan isolasi kesalahan, tetapi setiap panggilan menanggung dua context switch kernel, penyalinan buffer socket, dan serialisasi wire.

Kami membangun HQQ setelah mengajukan pertanyaan langsung: bagaimana jika pustaka C berada dalam proses OS terpisah dengan ruang alamat virtualnya sendiri, sementara Go dan C saling bertukar frame secara langsung melalui cache line CPU bersama tanpa memasuki kernel pada jalur cepat?

| Model Integrasi                    | `CGO_ENABLED=0` | Isolasi Kesalahan       | Syscall Jalur Cepat | Alokasi Heap per Panggilan | Fidelitas C11 Hulu |
| :--------------------------------- | :-------------- | :---------------------- | ------------------: | -------------------------: | :----------------- |
| **Penautan In-Process `cgo`**      | Tidak           | Tidak ada (heap bersama) |                   0 |                    0 hingga 1+ | C hulu persis      |
| **Socket / Pipe Subprocess RPC**   | Ya              | Batas proses            |             2 hingga 4 |  Beberapa (framing + I/O) | C hulu persis      |
| **Translasi Mekanis C-ke-Go**      | Ya              | Go dalam proses         |                   0 | Tinggi pada panggilan kompleks | Runtime C yang diemulasi |
| **HQQ Shared-Memory IPC**          | Ya              | Batas proses            |  0 (adaptive spin)  |   0 (`StandardLink`)       | C hulu persis      |

## Ikhtisar Arsitektur: Empat Lapisan Melintasi Batas Proses

HQQ memisahkan isolasi proses menjadi empat lapisan yang dapat disusun secara komposabel sehingga mekanika ring memori bersama, pembangkitan kode RPC bertipe, verifikasi integritas biner, dan supervisi proses anak tetap independen.

```text
+-------------------------------------------------------------------+
| Proses Aplikasi Go (CGO_ENABLED=0)                                |
|                                                                   |
|  +-----------------------+     +-------------------------------+  |
|  | Klien Go yang Dibangkitkan|   | Supervisor Proses             |  |
|  | (gosuda.org/hqq/      |     | (gosuda.org/hqq/launch +      |  |
|  |  bindgen/rt)          |     |  gosuda.org/hqq/secureexec)   |  |
|  +-----------+-----------+     +---------------+---------------+  |
|              |                                 |                  |
|  +-----------v-----------+                     | Anonymous Pipe   |
|  | Tingkat Transport     |                     | Lifeline         |
|  | (StandardLink /       |                     | (--parent-stdin) |
|  |  Advanced MPMC)       |                     |                  |
+--------------+---------------------------------+------------------+
               |                                 |
===============|========= Shared Memory =========|===================
               |     (mmap / CreateFileMapping)  |
+--------------v---------------------------------v------------------+
| Proses Pekerja C11 (Ruang Alamat Terisolasi)                      |
|                                                                   |
|  +-----------------------+     +-------------------------------+  |
|  | Server C11 yang      |---->| Tabel Handle                  |  |
|  | Dibangkitkan & Shim  |     | Terverifikasi Generasi        |  |
|  | Batch                |     | (hqq_rpc.c)                   |  |
|  +-----------+-----------+     +---------------+---------------+  |
|              |                                 |                  |
|              +----------------+----------------+                  |
|                               |                                   |
|                     +---------v---------+                         |
|                     | Pustaka C Native  |                         |
|                     | (SQLite, Zstd...) |                         |
|                     +-------------------+                         |
+-------------------------------------------------------------------+
```

### 1. Transport Memori Bersama (`gosuda.org/hqq` dan `c/`)

Paket dasar `gosuda.org/hqq` dan padanan C11-nya di `c/` mengimplementasikan dua mode transport memori bersama di atas `mmap` POSIX (Linux dan macOS) serta `CreateFileMappingW` Win32 (Windows). Setiap segmen bersama dimulai dengan superblock `HQQ_STL3` yang terverifikasi, yang mengunci versi protokol, geometri buffer, dan PID endpoint sebelum indeks ring apa pun dibaca.

Seluruh kata kontrol panas dan header slot diselaraskan pada batas cache line 64-byte sehingga core produser dan konsumer tidak pernah berebut cache line yang sama akibat false sharing.

```text
Tata Letak Slot StandardLink (Diselaraskan pada Cache Line 64-Byte)
Offset Byte:  0x00                0x08                0x10                          0x40
              +-------------------+-------------------+-----------------------------+
Header Line:  | seq (u64 atomic)  | len (u32) | flags | reserved (diisi nol)        |
              +-------------------+-------------------+-----------------------------+
Area Payload: | byte payload [0 .. BufferSize - 1] (dikodekan / didekodekan langsung) |
              +---------------------------------------------------------------------+
```

| Field     | Offset |         Ukuran | Semantik                                                                                                                   |
| :-------- | -----: | -------------: | :------------------------------------------------------------------------------------------------------------------------- |
| `seq`     | `0x00` |           8 B | Penghitung urutan monotonik. Nilai ganjil menandai penulisan yang sedang berlangsung; nilai genap mempublikasikan frame yang telah di-commit melalui store-release. |
| `len`     | `0x08` |           4 B | Panjang byte payload yang ditulis ke dalam slot (`0 <= len <= BufferSize`).                                                 |
| `flags`   | `0x0C` |           4 B | Bit kontrol frame (kelanjutan, status kesalahan, atau pemberitahuan penutupan).                                              |
| `payload` | `0x40` | `BufferSize` | Area payload berurutan yang dibaca dan ditulis di tempat tanpa salinan perantara.                                            |

Pemanggil memilih di antara dua tingkat transport bergantung pada struktur konkurensinya:

- **`StandardLink` (Sesi SPSC 1:1)**: Memasangkan sesi klien dan server melalui slot permintaan dan respons khusus yang dilindungi oleh sequence lock (`SeqLock`). Pada jalur cepat, penulis melakukan serialisasi langsung ke dalam slot yang dipetakan dan melakukan commit dengan atomic store-release; pembaca melakukan spin singkat di ruang pengguna sebelum beralih ke primitif wake OS (`futex` di Linux, `__ulock_wait` di macOS, `WaitOnAddress` di Windows). Satu round trip frame tunggal selesai dalam sekitar 200 ns dengan `0 allocs/op`.
- **`Advanced` (Ring Dispatch MPMC)**: Memultipleks `M` pemanggil Go secara konkuren ke `N` thread pekerja C menggunakan ring submisi multi-producer multi-consumer tanpa kunci, kumpulan slot bersama, dan tabel penyelesaian berindeks. Pemanggil mencadangkan sebuah slot, mempublikasikan indeks slot ke ring, dan menunggu entri penyelesaiannya sementara thread pekerja mengambil dan menyelesaikan permintaan secara tidak berurutan.

Kedua tingkat secara terus-menerus melacak kelangsungan hidup peer. Setiap endpoint memperbarui timestamp monotonik atomik melalui `Heartbeat()` dan memeriksa `PeerAlive(timeout)` selama menunggu. Jika proses pekerja mengalami crash di tengah panggilan, peer segera mendeteksi heartbeat yang usang atau PID yang mati, membatalkan waktu tunggu yang terblokir dengan `ErrPeerGone`, dan mendukung `Takeover` sesi secara atomik tanpa meninggalkan berkas memori bersama yang macet.

### 2. RPC Tanpa Alokasi dan Handle Terverifikasi Generasi (`gosuda.org/hqq/bindgen`)

Menulis framing memori bersama secara manual untuk pustaka C dengan puluhan fungsi merepotkan dan rentan kesalahan. `hqq-bindgen` adalah compiler skema yang membaca berkas Interface Definition Language (`.idl`) (atau membuat berkas tersebut langsung dari header C `.h` melalui `hqq-bindgen init`) dan menghasilkan paket klien Go tanpa zero-cgo beserta kerangka server C11.

Kesalahan paling berbahaya dalam binding C mana pun adalah mengekspos pointer C mentah (`sqlite3*`, `sqlite3_stmt*`, `ZSTD_CCtx*`) melintasi batas bahasa. Jika pemanggil meneruskan pointer setelah membebaskannya, meneruskan pointer milik sesi lain, atau merusak alamat integer, pustaka C akan melakukan dereferensi memori yang tidak valid.

`hqq-bindgen` melarang pointer mentah pada wire. Sebagai gantinya, IDL memodelkan resource C yang stateful sebagai deklarasi `handle` bertipe:

```text
service sqlite3 {
    handle Db;
    handle Stmt @owned_by(Db);

    fn open_v2(path: string, flags: i32) -> result<Db, i32>;
    fn prepare_one(db: Db, sql: string) -> result<Stmt, i32>;
    fn finalize(stmt: @consume Stmt) -> result<void, i32>;
    fn close(db: @consume Db) -> result<void, i32>;
}
```

Pada wire, setiap handle adalah integer 64-bit yang menggabungkan indeks tabel 32-bit dan penghitung generasi 32-bit yang bukan nol: `(uint64_t)generation << 32 | index`. Runtime C (`c/src/hqq_rpc.c`) memelihara tabel handle per sesi dengan tiga invarian:

1. **Validasi Generasi**: Setiap pencarian memverifikasi bahwa slot terisi, generasi yang tersimpan cocok dengan 32 bit atas handle, dan tag tipe handle-nya cocok dengan tipe parameter (`Db` vs. `Stmt`). Menggunakan kembali handle yang sudah ditutup akan gagal seketika dengan `HQQRPC_E_BAD_HANDLE` sebelum memanggil pustaka C.
2. **Kepemilikan Hierarkis (`@owned_by`)**: Karena `Stmt` dianotasi dengan `@owned_by(Db)`, menutup handle `Db` secara otomatis menelusuri seluruh handle `Stmt` anak yang masih hidup dan milik `Db` tersebut, lalu menjalankan destruktornya dalam urutan alokasi terbalik (`sqlite3_finalize` sebelum `sqlite3_close_v2`).
3. **Penyapuan Penghentian Sesi**: Jika klien Go terputus atau crash tanpa menutup handle-nya, destruktor sesi server C menyapu seluruh tabel handle sesi dalam urutan terbalik, sehingga menjamin tidak ada alokasi C yang bocor di antara restart klien.

Sebelum sesi memproses panggilan RPC pertamanya, klien dan server saling bertukar digest interface SHA-256 sepanjang 32 byte yang dihitung atas IDL yang telah dikanonikalisasi (dengan awalan `HQQ-BINDGEN-IDL-V1\n`). Jika klien Go dan worker C dikompilasi dari skema IDL yang tidak kompatibel, handshake menolak koneksi saat bootstrap.

### 3. Eksekusi Biner Bebas Pemalsuan (`gosuda.org/hqq/secureexec`)

Memindahkan kode C ke dalam biner worker menimbulkan pertanyaan rantai pasok: bagaimana proses Go mengetahui bahwa biner worker di disk tidak dimodifikasi atau diganti antara verifikasi dan eksekusi?

Memanggil `crypto/sha256` pada path berkas lalu `os/exec.Command(path).Start()` menyisakan jendela Time-of-Check to Time-of-Use (TOCTOU) di mana proses lain dapat menimpa atau menukar berkas sebelum kernel mengeksekusinya. `gosuda.org/hqq/secureexec` menutup jendela ini:

- Di Linux, `secureexec` membuka biner, mengalirkan isinya ke dalam deskriptor berkas memori anonim yang dibuat melalui `memfd_create(MFD_CLOEXEC | MFD_ALLOW_SEALING)` sambil menghitung hash SHA-256-nya, memverifikasi hash tersebut terhadap digest 32 byte yang dipasang (pinned) atau manifest rilis yang ditandatangani Ed25519 (`cmd/hqq-manifest`), menerapkan `fcntl(F_ADD_SEALS, F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE)` sehingga tidak ada proses di sistem yang dapat memodifikasi halaman tersebut, dan menjalankan proses anak dari deskriptor yang tersegel.
- Di macOS dan Windows, `secureexec` memindahkan biner yang telah diverifikasi ke direktori cache dengan izin terkunci yang diindeks berdasarkan digest SHA-256, dan memverifikasi integritas ukuran berkas serta digest sebelum peluncuran.

### 4. Supervisi Proses Parent-Lifeline (`gosuda.org/hqq/launch`)

Ketika aplikasi Go menjalankan proses worker C di latar belakang, worker tidak boleh bertahan hidup sebagai proses yatim setelah parent-nya, bahkan jika proses parent Go dihentikan dengan `SIGKILL` (`kill -9`) dan tidak dapat menjalankan handler pembersihan `defer`.

`gosuda.org/hqq/launch` menegakkan keterkaitan masa hidup melalui pipa OS anonim yang diteruskan ke standard input worker dengan flag `--parent-stdin`. Parent Go memegang ujung tulis pipa dan tidak pernah menulis ke dalamnya; worker C memantau ujung baca pada thread lifeline khusus. Jika proses Go keluar secara normal, panik, atau dihentikan oleh kernel OS (`SIGKILL` atau OOM killer), kernel segera menutup deskriptor tulis. Worker C menerima `EOF` pada pipa dalam hitungan mikrodetik, menginterupsi panggilan aktif apa pun, menjalankan destruktor handle sesinya, menghapus tautan berkas memori bersama, dan keluar dengan bersih.

## Panduan Cepat: Memanggil Layanan yang Dibangkitkan

Dengan `hqq-bindgen` dan `launch`, memanggil worker C yang terisolasi dari Go terlihat seperti klien Go bertipe yang biasa sambil tetap mempertahankan `CGO_ENABLED=0`:

```go
package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"gosuda.org/hqq/bindgen/rt"
	"gosuda.org/hqq/launch"
	"gosuda.org/hqq/secureexec"
)

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	hash, err := secureexec.ParseHash("7649b1b45dacd934cde8149f35f4fcc3937f6486fbac23ce976466719b3752bb")
	if err != nil {
		log.Fatal(err)
	}

	listener, err := launch.NewListenerName("demo")
	if err != nil {
		log.Fatal(err)
	}

	srv, err := launch.Start(ctx, launch.Config{
		Binary:   "/path/to/verified-worker",
		SHA256:   hash,
		Listener: listener,
		Args:     []string{listener},
	})
	if err != nil {
		log.Fatal(err)
	}
	defer srv.Close()

	fmt.Printf("worker berjalan pada listener memori bersama %s (opts=%+v)\n", listener, rt.SessionOptions{})
}
```

## Struktur Repositori

Setiap subsistem dalam `gosuda.org/hqq` diorganisasikan ke dalam paket-paket terfokus dengan batas yang eksplisit:

```text
gosuda.org/hqq
├── standard.go / ring.go      # StandardLink (SPSC) dan primitif ring memori bersama tingkat rendah
├── advanced.go / slotpool.go  # Dispatcher Advanced (MPMC), kumpulan slot, dan tabel penyelesaian
├── shm_*.go / wait_*.go       # mmap/CreateFileMapping spesifik OS dan futex/ulock/WaitOnAddress
├── c/                         # Pustaka transport C11 (hqq.c) dan runtime server RPC (hqq_rpc.c)
├── bindgen/                   # Parser IDL hqq-bindgen, verifier (V1-V41), dan generator kode Go/C11
│   └── rt/                    # Runtime klien Go tanpa alokasi untuk layanan yang dibangkitkan
├── secureexec/                # Verifikasi manifest SHA-256 / Ed25519 dan eksekusi tersegel memfd
├── launch/                    # Supervisor proses pekerja dengan manajemen lifeline --parent-stdin
├── cmd/hqq-manifest/          # Alat CLI untuk membangkitkan dan menandatangani manifest biner rilis
└── spec/                      # Spesifikasi wire yang dapat dieksekusi dan vektor uji emas (BINDGEN.md)
```

Untuk melihat bagaimana HQQ menyediakan pengganti produksi langsung pakai (drop-in) bagi dua pustaka `cgo` yang paling banyak digunakan dalam ekosistem Go, lihat paket pendamping yang dibangun di atas tumpukan ini:

- **[`gosuda.org/sqlite3`](https://gosuda.org/sqlite3)**: Driver `database/sql` drop-in yang kompatibel dengan `github.com/mattn/go-sqlite3`, menjalankan SQLite C native `3.54.1` melalui memori bersama dengan prefetch batch yang di-pipeline.
- **[`gosuda.org/zstd`](https://gosuda.org/zstd)**: Pengganti drop-in untuk `github.com/DataDog/zstd`, menjalankan `libzstd 1.5.7` C native dalam worker memori bersama yang terisolasi dengan konteks tanpa alokasi dan batching massal.
- **Repositori GitHub**: [https://github.com/gosuda/HQQ](https://github.com/gosuda/HQQ)
