---
id: 43974d116e135fd9d3478f658dcf71c6
author: Lemon Mint
title: 'HQQ: Önbellek Hattı Paylaşımlı Bellek Üzerinden C Kütüphanelerinin Go''dan İzole Edilmesi'
description: Sıfır-cgo IPC çalışma zamanı, IDL derleyicisi (hqq-bindgen) ve paylaşımlı bellek halkaları üzerinden yerel C11 kütüphanelerini izole çalışan süreçlerde yürüten doğrulanmış bir süreç denetleyicisi.
language: tr
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`, C11 ve Go için sıfır-cgo bir süreçlerarası iletişim çalışma zamanı ve kod üretme araç zinciridir. Yerel C kitaplıklarını ayrı işletim sistemi çalışan süreçlerinde izole eder ve bunları bellek eşlemeli, önbellek satırına hizalanmış paylaşımlı bellek halkaları üzerinden Go çağıranlarına bağlar. Proje, iki aktarım katmanını (tek üretici-tek tüketicili özel oturumlar için `StandardLink` ve çok işçili MPMC dağıtımı için `Advanced`), `hqq-bindgen` IDL derleyicisini ve doğrulanmış bir süreç denetleyicisini (`secureexec` ve `launch`) birleştirir.

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

## C ile Adres Uzayını Paylaşmanın Maliyeti

Her Go sistem mühendisi er ya da geç aynı yol ayrımıyla karşılaşır. `CGO_ENABLED=0` ile saniyeler içinde derlenen, tek bir statik ikili dosya olarak dağıtılan, bir sysroot gerektirmeden bir dizüstü bilgisayardan Linux veya Windows hedeflerine çapraz derlenebilen ve bellek açısından güvenli, çöp toplayıcılı bir yığında çalışan bir Go servisi geliştiriyorsunuz. Ardından olgun bir C kitaplığına ihtiyaç duyarsınız: gömülü ilişkisel depolama için SQLite, sözlük sıkıştırması için Zstandard (`libzstd`) ya da donanım hızlandırmalı bir medya veya kriptografi kitaplığı.

Bu C kitaplığını Go süreci içine bağlamak için `cgo`'yu etkinleştirmek, anlık bağlama sorununu çözer ancak üç yapısal sorumluluk doğurur:

1. **Araç Zinciri ve Çapraz Derleme Bağımlılığı**: `CGO_ENABLED=1`, her hedef işletim sistemi ve mimarisi için bir C derleyicisi, hedef libc başlıkları ve bir platform bağlayıcısı gerektirir. Bir `darwin/arm64` iş istasyonundan `linux/arm64` veya `windows/arm64` yapıtları oluşturmak, tek bir `go build` komutunu bir çapraz derleyiciler ve sysroot matrisine dönüştürür.
2. **Çalışma Zamanı Zamanlama Yükü**: Her `cgo` çağrısı Go çalışma zamanı sınırını geçer, büyüyebilen bir goroutine yığınından bir sistem yığınına geçer ve bir işletim sistemi iş parçacığını (`M`) sabitler. İnce taneli çağrılarda geçiş maliyeti (çağrı başına yaklaşık 50 ila 150 ns) ve zamanlayıcı çekişmesi hızla birikir.
3. **Hata Alanının Çökmesi**: C kodu, Go çalışma zamanıyla aynı sanal adres uzayında çalışır. Bir C işlevi içindeki tek bir sınır dışı yazma, serbest bırakılmış belleğe erişim, yığın taşması veya `abort()` çağrısı, Go yığın meta verilerini bozar ya da `recover()` mekanizmasını atlayarak tüm sunucu sürecini anında sonlandırır ve uçuşta olan her HTTP veya RPC isteğini de beraberinde götürür.

Ekipler `cgo`'dan kaçınmaya çalıştığında, yaygın alternatifler farklı bir uzlaşma yapmayı zorunlu kılar. C kod tabanlarının saf Go'ya mekanik çevirileri `CGO_ENABLED=0` desteğini korur, ancak genellikle üst akış C sürümlerinin gerisinde kalır, öykünülmüş bir sanal bellek katmanı taşır ve yük altında yoğun bellek ayırır. C kitaplığını yerel döngü TCP veya Unix alan soketleri üzerinden bir yardımcı sürece taşımak hata izolasyonunu geri kazandırır, ancak her çağrı iki çekirdek bağlam anahtarlaması, soket tampon kopyaları ve kablo serileştirmesi bedelini öder.

HQQ'yu doğrudan bir soruyu sorarak geliştirdik: C kitaplığı kendi sanal adres uzayına sahip ayrı bir işletim sistemi sürecinde yaşarsa ve Go ile C, hızlı yolda çekirdeğe girmeden çerçeveleri doğrudan paylaşılan CPU önbellek satırları üzerinden değiş tokuş ederse ne olur?

| Entegrasyon Modeli                 | `CGO_ENABLED=0` | Hata İzolasyonu       | Hızlı Yol Sistem Çağrıları | Çağrı Başına Yığın Ayırmaları | Üst Akış C11 Sadakati |
| :--------------------------------- | :-------------- | :-------------------- | -------------------------: | ----------------------------: | :-------------------- |
| **`cgo` Süreç İçi Bağlama**        | Hayır           | Yok (paylaşımlı yığın) |                          0 |                      0 ila 1+ | Birebir üst akış C    |
| **Soket / Boru Alt Süreç RPC**     | Evet            | Süreç sınırı          |                    2 ila 4 |  Birden çok (çerçeveleme + G/Ç) | Birebir üst akış C    |
| **Mekanik C'den Go'ya Çeviri**     | Evet            | Süreç içi Go          |                          0 |        Karmaşık çağrılarda yüksek | Öykünülmüş C çalışma zamanı |
| **HQQ Paylaşımlı Bellek IPC**      | Evet            | Süreç sınırı          |        0 (uyarlanabilir döngü) |   0 (`StandardLink`) | Birebir üst akış C    |

## Mimari Genel Bakış: Süreç Sınırları Boyunca Dört Katman

HQQ, süreç izolasyonunu birbirinden bağımsız kalacak şekilde birleştirilebilir dört katmana ayırır; böylece paylaşımlı bellek halkası mekaniği, türlendirilmiş RPC kod üretimi, ikili bütünlük doğrulaması ve alt süreç denetimi birbirinden bağımsız kalır.

```text
+-------------------------------------------------------------------+
| Go Uygulama Süreci (CGO_ENABLED=0)                                |
|                                                                   |
|  +-----------------------+     +-------------------------------+  |
|  | Üretilmiş Go İstemcisi|     | Süreç Denetleyicisi           |  |
|  | (gosuda.org/hqq/      |     | (gosuda.org/hqq/launch +      |  |
|  |  bindgen/rt)          |     |  gosuda.org/hqq/secureexec)   |  |
|  +-----------+-----------+     +---------------+---------------+  |
|              |                                 |                  |
|  +-----------v-----------+                     | Anonim Boru      |
|  | Aktarım Katmanı       |                     | Yaşam Hattı      |
|  | (StandardLink /       |                     | (--parent-stdin) |
|  |  Advanced MPMC)       |                     |                  |
+--------------+---------------------------------+------------------+
               |                                 |
===============|========= Paylaşımlı Bellek ======|===================
               |     (mmap / CreateFileMapping)  |
+--------------v---------------------------------v------------------+
| C11 Çalışan Süreç (İzole Adres Uzayı)                             |
|                                                                   |
|  +-----------------------+     +-------------------------------+  |
|  | Üretilmiş C11 Sunucusu|---->| Üretim Denetimli Tutamaç      |  |
|  | & Toplu Katmanlar     |     | Tablosu (hqq_rpc.c)           |  |
|  +-----------+-----------+     +---------------+---------------+  |
|              |                                 |                  |
|              +----------------+----------------+                  |
|                               |                                   |
|                     +---------v---------+                         |
|                     | Yerel C Kitaplığı |                         |
|                     | (SQLite, Zstd...) |                         |
|                     +-------------------+                         |
+-------------------------------------------------------------------+
```

### 1. Paylaşımlı Bellek Aktarımı (`gosuda.org/hqq` ve `c/`)

Temel `gosuda.org/hqq` paketi ve `c/` dizinindeki C11 karşılığı, POSIX `mmap` (Linux ve macOS) ile Win32 `CreateFileMappingW` (Windows) üzerinden iki paylaşımlı bellek aktarım modu uygular. Her paylaşımlı segment, herhangi bir halka indeksi okunmadan önce protokol sürümünü, tampon geometrisini ve uç nokta PID'lerini sabitleyen doğrulanmış bir `HQQ_STL3` süper bloğuyla başlar.

Tüm sıcak kontrol kelimeleri ve yuva başlıkları, üretici ve tüketici çekirdeklerinin yanlış paylaşım (false sharing) nedeniyle aynı önbellek satırı üzerinde çakışmaması için 64 baytlık önbellek satırı sınırlarına hizalanmıştır.

```text
StandardLink Yuva Düzeni (64 Baytlık Önbellek Satırına Hizalı)
Bayt Ofseti:  0x00                0x08                0x10                          0x40
              +-------------------+-------------------+-----------------------------+
Başlık Satırı:| seq (u64 atomik)  | len (u32) | flags | reserved (sıfır dolgulu)    |
              +-------------------+-------------------+-----------------------------+
Yük Alanı:    | yük baytları [0 .. BufferSize - 1] (doğrudan kodlanmış / çözülmüş)  |
              +---------------------------------------------------------------------+
```

| Alan      | Ofset  |         Boyut | Anlamı                                                                                                                     |
| :-------- | -----: | ------------: | :------------------------------------------------------------------------------------------------------------------------- |
| `seq`     | `0x00` |           8 B | Monoton dizi sayacı. Tek değerler devam eden bir yazmayı işaretler; çift değerler store-release ile onaylanmış bir çerçeveyi yayımlar. |
| `len`     | `0x08` |           4 B | Yuvaya yazılan yük bayt uzunluğu (`0 <= len <= BufferSize`).                                                              |
| `flags`   | `0x0C` |           4 B | Çerçeve kontrol bitleri (devamlılık, hata durumu veya kapanış bildirimi).                                                 |
| `payload` | `0x40` | `BufferSize`  | Ara kopyalar olmadan yerinde okunan ve yazılan bitişik yük bölgesi.                                                       |

Çağıranlar, eşzamanlılık yapısına bağlı olarak iki aktarım katmanı arasında seçim yapar:

- **`StandardLink` (1:1 SPSC Oturumu)**: Bir istemci ve bir sunucu oturumunu, bir sıra kilidi (`SeqLock`) ile korunan özel istek ve yanıt yuvaları üzerinden eşleştirir. Hızlı yolda yazıcı, doğrudan eşlenmiş yuvaya serileştirir ve atomik store-release ile onaylar; okuyucu, OS uyandırma ilkellerine (Linux'ta `futex`, macOS'ta `__ulock_wait`, Windows'ta `WaitOnAddress`) geri dönmeden önce kullanıcı alanında kısa süre döner. Tek çerçeveli bir gidiş-dönüş yaklaşık 200 ns'de ve `0 allocs/op` ile tamamlanır.
- **`Advanced` (MPMC Dağıtım Halkası)**: Kilitsiz çoklu üretici çoklu tüketici gönderim halkası, paylaşımlı bir yuva havuzu ve indeksli bir tamamlanma tablosu kullanarak `M` eşzamanlı Go çağıranını `N` C işçi iş parçacığı üzerinden çoklar. Çağıranlar bir yuva ayırır, yuva indeksini halkaya yayımlar ve işçi iş parçacıkları istekleri sıra dışı kuyruktan çıkarıp tamamlarken kendi tamamlanma girdilerini bekler.

Her iki katman da eş canlılığını sürekli izler. Her uç nokta, `Heartbeat()` aracılığıyla atomik monoton bir zaman damgasını günceller ve beklerken `PeerAlive(timeout)` ile denetler. Bir işçi süreci bir çağrının ortasında çökerse, eş bayat kalp atışını ya da ölü PID'yi hemen fark eder, bloke olmuş beklemeleri `ErrPeerGone` ile iptal eder ve geride kilitli paylaşımlı bellek dosyaları bırakmadan atomik oturum `Takeover` işlemini destekler.

### 2. Sıfır Ayırmalı RPC ve Üretim Denetimli Tutamaçlar (`gosuda.org/hqq/bindgen`)

Düzinelerce işlevi olan bir C kitaplığı için paylaşımlı bellek çerçevelemesini elle yazmak zahmetli ve hataya açıktır. `hqq-bindgen`, bir Arayüz Tanımlama Dili (`.idl`) dosyasını okuyan (veya `hqq-bindgen init` ile doğrudan bir C `.h` başlığından bir tane türeten) ve bir C11 sunucu iskeletiyle birlikte sıfır-cgo bir Go istemci paketi üreten bir şema derleyicisidir.

Herhangi bir C bağlamasındaki en tehlikeli hata, ham C işaretçilerini (`sqlite3*`, `sqlite3_stmt*`, `ZSTD_CCtx*`) dil sınırının ötesine açmaktır. Bir çağıran, serbest bıraktıktan sonra bir işaretçi geçerse, başka bir oturuma ait bir işaretçi geçerse ya da bir tamsayı adresini bozarsa, C kitaplığı geçersiz belleğe erişir.

`hqq-bindgen`, tel üzerinde ham işaretçilere izin vermez. Bunun yerine IDL, durumlu C kaynaklarını türlendirilmiş `handle` bildirimleri olarak modeller:

```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>;
}
```

Tel üzerinde her tutamaç, 32 bitlik bir tablo indeksini ve 32 bitlik sıfır olmayan bir üretim sayacını paketleyen 64 bitlik bir tamsayıdır: `(uint64_t)generation << 32 | index`. C çalışma zamanı (`c/src/hqq_rpc.c`), üç değişmezi koruyan oturum başına bir tutamaç tablosu tutar:

1. **Üretim Doğrulaması**: Her arama, yuvanın dolu olduğunu, saklanan üretimin tutamacın üst 32 bitiyle eşleştiğini ve tutamaç türü etiketinin parametre türüyle (`Db` ya da `Stmt`) uyuştuğunu doğrular. Kapatılmış bir tutamacın yeniden kullanılması, C kitaplığına çağrı yapılmadan önce `HQQRPC_E_BAD_HANDLE` ile hemen başarısız olur.
2. **Hiyerarşik Sahiplik (`@owned_by`)**: `Stmt`, `@owned_by(Db)` ile işaretlendiği için, bir `Db` tutamacını kapatmak, o `Db` tarafından sahip olunan tüm canlı alt `Stmt` tutamaçlarını otomatik olarak dolaşır ve yıkıcılarını ayırma sırasının tersine çalıştırır (`sqlite3_close_v2`'den önce `sqlite3_finalize`).
3. **Oturum Sonlandırma Taraması**: Bir Go istemcisi tutamaçlarını kapatmadan bağlantısı kesilir ya da çökerse, C sunucusunun oturum yıkıcısı tüm oturum tutamaç tablosunu ters sırada tarar ve istemci yeniden başlatmaları boyunca sıfır sızıntılı C ayırmasını garanti eder.

Bir oturum ilk RPC çağrısını işlemeden önce, istemci ve sunucu, kanonikleştirilmiş IDL üzerinden hesaplanan 32 baytlık bir SHA-256 arayüz özetini (`HQQ-BINDGEN-IDL-V1\n` öneki ile) değiş tokuş eder. Go istemcisi ve C işçisi uyumsuz IDL şemalarından derlenmişse, el sıkışma bağlantıyı başlangıçta reddeder.

### 3. Kurcalamaya Karşı Korumalı İkili Yürütme (`gosuda.org/hqq/secureexec`)

C kodunu bir işçi ikili dosyasına taşımak bir tedarik zinciri sorusunu gündeme getirir: Go süreci, doğrulama ile yürütme arasında diskteki işçi ikili dosyasının değiştirilmediğini ya da yerine başka bir dosya konulmadığını nasıl bilir?

Bir dosya yolu üzerinde `crypto/sha256` çağırmak, ardından `os/exec.Command(path).Start()` çağırmak, çekirdek dosyayı çalıştırmadan önce başka bir sürecin dosyanın üzerine yazabileceği veya dosyayı değiştirebileceği bir Kontrol Zamanı ile Kullanım Zamanı (TOCTOU) penceresi bırakır. `gosuda.org/hqq/secureexec` bu pencereyi kapatır:

- Linux'ta `secureexec`, ikiliyi açar, içeriğini `memfd_create(MFD_CLOEXEC | MFD_ALLOW_SEALING)` ile oluşturulan anonim bellek dosyası tanımlayıcısına akıtırken SHA-256 özetini hesaplar, özeti sabitlenmiş 32 baytlık bir özete ya da Ed25519 ile imzalanmış bir sürüm manifestosuna (`cmd/hqq-manifest`) karşı doğrular, sistemdeki hiçbir sürecin sayfaları değiştirememesi için `fcntl(F_ADD_SEALS, F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE)` uygular ve alt süreci mühürlenmiş tanımlayıcıdan başlatır.
- macOS ve Windows'ta `secureexec`, doğrulanmış ikilileri SHA-256 özetiyle anahtarlanmış, izinleri kilitli önbellek dizinlerine yerleştirir ve başlatmadan önce dosya boyutunu ve özet bütünlüğünü doğrular.

### 4. Ebeveyn Yaşam Hattı ile Süreç Denetimi (`gosuda.org/hqq/launch`)

Bir Go uygulaması arka plan C işçi süreci başlattığında, Go ebeveyni `SIGKILL` (`kill -9`) ile sonlandırılsa ve `defer` temizleme işleyicilerini çalıştıramasa bile, işçi hiçbir zaman ebeveyninden yetim bir süreç olarak yaşamamalıdır.

`gosuda.org/hqq/launch`, `--parent-stdin` bayrağıyla işçinin standart girdisine aktarılan anonim bir OS borusu üzerinden yaşam döngüsü bağını zorunlu kılar. Go ebeveyni borunun yazma ucunu tutar ve oraya hiçbir zaman yazmaz; C işçisi okuma ucunu özel bir yaşam hattı iş parçacığında izler. Go süreci normal şekilde çıkarsa, panik yaparsa veya işletim sistemi çekirdeği tarafından sonlandırılırsa (`SIGKILL` ya da OOM öldürücüsü), çekirdek yazma tanımlayıcısını anında kapatır. C işçisi boru üzerinde mikrosaniyeler içinde `EOF` alır, etkin çağrıları keser, oturum tutamaç yıkıcılarını çalıştırır, paylaşımlı bellek dosyalarının bağlantısını kaldırır ve temiz bir şekilde çıkar.

## Hızlı Başlangıç: Üretilmiş Bir Servisi Çağırmak

`hqq-bindgen` ve `launch` ile izole bir C işçisini Go'dan çağırmak, `CGO_ENABLED=0` ortamını koruyarak sıradan türlendirilmiş bir Go istemcisi gibi görünür:

```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 running on shared-memory listener %s (opts=%+v)\n", listener, rt.SessionOptions{})
}
```

## Depo Yapısı

`gosuda.org/hqq` içindeki her alt sistem, açık sınırlara sahip odaklanmış paketlere düzenlenmiştir:

```text
gosuda.org/hqq
├── standard.go / ring.go      # StandardLink (SPSC) ve düşük seviyeli paylaşımlı bellek halka ilkelleri
├── advanced.go / slotpool.go  # Advanced (MPMC) dağıtıcı, yuva havuzu ve tamamlanma tablosu
├── shm_*.go / wait_*.go       # OS'e özgü mmap/CreateFileMapping ve futex/ulock/WaitOnAddress
├── c/                         # C11 aktarım kitaplığı (hqq.c) ve RPC sunucu çalışma zamanı (hqq_rpc.c)
├── bindgen/                   # hqq-bindgen IDL ayrıştırıcısı, doğrulayıcı (V1-V41) ve Go/C11 kod üreteci
│   └── rt/                    # Üretilmiş servisler için sıfır ayırmalı Go istemci çalışma zamanı
├── secureexec/                # SHA-256 / Ed25519 manifesto doğrulaması ve memfd mühürlü yürütme
├── launch/                    # --parent-stdin yaşam hattı yönetimi ile işçi süreç denetleyicisi
├── cmd/hqq-manifest/          # Sürüm ikili manifestolarını üretmek ve imzalamak için CLI aracı
└── spec/                      # Çalıştırılabilir kablo spesifikasyonları ve altın test vektörleri (BINDGEN.md)
```

HQQ'nun Go ekosistemindeki en yaygın kullanılan iki `cgo` kitaplığı için doğrudan üretim ortamında yerine geçebilen bileşenleri nasıl desteklediğini görmek için, bu yığın üzerine kurulmuş tamamlayıcı paketlere bakın:

- **[`gosuda.org/sqlite3`](https://gosuda.org/sqlite3)**: `github.com/mattn/go-sqlite3` ile uyumlu, doğrudan kullanılabilen bir `database/sql` sürücüsü; paylaşımlı bellek üzerinden boru hattı toplu ön getirme ile yerel C SQLite `3.54.1` çalıştırır.
- **[`gosuda.org/zstd`](https://gosuda.org/zstd)**: `github.com/DataDog/zstd` için doğrudan yerine geçen bir bileşen; sıfır ayırmalı bağlamlar ve toplu işleme ile yalıtılmış bir paylaşımlı bellek işçisinde yerel C `libzstd 1.5.7` çalıştırır.
- **GitHub Deposu**: [https://github.com/gosuda/HQQ](https://github.com/gosuda/HQQ)
