---
id: c90263519492728e7cc2d0ce840057b6
author: Yunjin Lee
title: Bezpośrednie wywołania systemowe Linuksa w czystym Go z użyciem syscall.Syscall i unsafe.Pointer
description: Wywoływanie wywołań systemowych jądra Linux, takich jak SYS_SYSINFO, bezpośrednio z czystego kodu Go, z wykorzystaniem struktur zgodnych z ABI, unsafe.Pointer oraz standardowego pakietu syscall, bez cgo.
language: pl
date: 2025-10-26T12:31:21.655228078Z
path: /blog/posts/go-syscall-is-a-brilliant-replacement-of-low-level-i-o-za50951e1
category: lowlevel
---

## Podsumowanie

Dowiemy się o bezpośrednich wywołaniach systemowych w Go.
Ponieważ Go oferuje rygorystyczne błędy kompilatora oraz sztywny GC, znacznie lepiej jest zastępować niskopoziomowe wywołania czystym Go.
Na szczęście większość wywołań funkcji C została w pełni zreimplementowana w Go, w dobry i nowoczesny sposób.
Przyjrzyjmy się temu.

## Wywołanie systemowe

Wywołanie systemowe to bezpośrednie żądanie kierowane do systemu operacyjnego.
Ponieważ system jest zazwyczaj napisany w sztywnym, staromodnym stylu, gdyż działa bezpośrednio na sprzęcie, musimy uwzględnić, że jego wywołanie musi dostarczyć ścisłą i poprawną formę żądania.
Zatem nawet jeśli nie potrzebujemy pewnych zmiennych, nadal musimy wypełnić ich rozmiar, niezależnie od tego, czy są używane.
Sprawdźmy to na w pełni działającym przykładzie.

## Pełny przykład

```go
package main
import (
	"fmt"
	"syscall"
	"unsafe"
)

type sysinfo_t struct {
	Uptime    int64
	Loads     [3]uint64
	Totalram  uint64
	Freeram   uint64
	Sharedram uint64
	Bufferram uint64
	Totalswap uint64
	Freeswap  uint64
	Procs     uint16
	Pad       uint16
	_         [4]byte
	Totalhigh uint64
	Freehigh  uint64
	MemUnit   uint32
	_         [4]byte
}

func main() {
	var info sysinfo_t
	_, _, errno := syscall.Syscall(syscall.SYS_SYSINFO, uintptr(unsafe.Pointer(&info)), 0, 0)
	if errno != 0 {
		fmt.Println("sysinfo syscall failed:", errno)
		return
	}

	scale := float64(1 << 16)
	fmt.Printf("Uptime: %d seconds\n", info.Uptime)
	fmt.Printf("Load Average: %.2f %.2f %.2f\n",
		float64(info.Loads[0])/scale,
		float64(info.Loads[1])/scale,
		float64(info.Loads[2])/scale)
	fmt.Printf("Memory: total=%d MB free=%d MB buffer=%d MB\n",
		info.Totalram*uint64(info.MemUnit)/1024/1024,
		info.Freeram*uint64(info.MemUnit)/1024/1024,
		info.Bufferram*uint64(info.MemUnit)/1024/1024)
	fmt.Printf("Swap: total=%d MB free=%d MB\n",
		info.Totalswap*uint64(info.MemUnit)/1024/1024,
		info.Freeswap*uint64(info.MemUnit)/1024/1024)
	fmt.Printf("Processes: %d\n", info.Procs)
}
```

Ten przykład zawiera wszystkie zmienne i wyświetla szczegółowe informacje o bieżącym stanie systemu.
Możemy porównać ten kod do zamka i klucza.
`syscall.SYS_SYSINFO` jest kluczem, który otwiera zamek znajdujący się wewnątrz jądra.
Dlatego użycie właściwego klucza do zamka jest istotne.
Co się stanie, gdy użyjemy `syscall.SYS_GETPID` dla tego wywołania?
Jest to klucz do zamka zawierającego identyfikator procesu (PID).
Spowoduje to próbę odczytu PID z obszaru informacji systemowych.
W rezultacie żadnych informacji nie da się poprawnie odczytać, a wywołanie zakończy się stanem błędu.

Teraz musimy wiedzieć, jakie elementy są zawarte i w jakiej kolejności są uporządkowane.
W pierwszym slocie zamka znajduje się Uptime, o rozmiarze 2^64.
Jeśli spróbujemy odczytać go za pomocą 2^32, sekwencja bitów nie zostanie odczytana w całości.
Nie możemy używać takich częściowych danych binarnych, chyba że zamierzamy pisać niskopoziomowe sztuczki.

Po odczytaniu 64 bitów danych binarnych w końcu znajdujemy się w drugim slocie.
Można go odczytać poprawnie dopiero wtedy, gdy wcześniej odczytaliśmy poprzednią 64-bitową liczbę całkowitą.

Powtarzając te rygorystyczne i logiczne przepływy, możemy uzyskać właściwe informacje z systemu i poprawnie obsłużyć odczytane dane.

## Jak pominąć 'nazwy zmiennych'

Chociaż nie możemy faktycznie „pominąć” samych zmiennych, ważne jest, aby rozróżniać zmienne używane od odrzuconych.
Jeśli przeznaczenie programu jest wystarczająco jasne, lepiej jest używać zmiennych bezimiennych jako symboli zastępczych, niż oznaczać każdą wartość etykietą, nawet jeśli nie są one używane na stałe.
Sprawdźmy to na przykładzie „Free Memory Checker”.

## Przykład - Free Memory Checker

Podczas sprawdzania wolnej pamięci i wymiany nie potrzebujemy innych informacji wskazujących na inne zasoby.
Aby uzyskać lepszą czytelność, można utworzyć anonimowe zmienne, które zajmą określone miejsca.

```go
package main

import (
	"fmt"
	"syscall"
	"unsafe"
)

type sysinfo_t struct {
	_          int64
	_         [3]uint64
	Totalram  uint64
	Freeram   uint64
	Sharedram uint64
	Bufferram uint64
	Totalswap uint64
	Freeswap  uint64
	_         uint16  // anonimowe, a nieużywane oznaczone jako _
	_         uint16
	_         [4]byte
	_         uint64
	_         uint64
	MemUnit   uint32
	_         [4]byte
}

func main() {
	var info sysinfo_t
	_, _, errno := syscall.Syscall(syscall.SYS_SYSINFO, uintptr(unsafe.Pointer(&info)), 0, 0)
	if errno != 0 {
		fmt.Println("sysinfo syscall failed:", errno)
		return
	}

	fmt.Printf("Memory: total=%d MB free=%d MB buffer=%d MB\n",
		info.Totalram*uint64(info.MemUnit)/1024/1024,
		info.Freeram*uint64(info.MemUnit)/1024/1024,
		info.Bufferram*uint64(info.MemUnit)/1024/1024)
	fmt.Printf("Swap: total=%d MB free=%d MB\n",
		info.Totalswap*uint64(info.MemUnit)/1024/1024,
		info.Freeswap*uint64(info.MemUnit)/1024/1024)
}
```

W konsekwencji zmienne są odczytywane bez etykiet.
Chociaż wartości anonimowe faktycznie są przechowywane w strukturze, w kodzie nie ma etykiet ani czytelnych oznaczeń.

## Podsumowanie końcowe

- Używanie `syscall` i `unsafe` w Go jest nadal bezpieczniejsze niż C/CGo
- Jeśli piszesz duży projekt, który może być łatwo rozbudowywany:
  - Nie twórz zmiennych anonimowych; nadaj każdemu członkowi nazwę.
- Jeśli piszesz projekt o ograniczonym zastosowaniu:
  - Możesz używać zmiennych anonimowych do zajmowania miejsc, które faktycznie nie są używane.
- `syscall` w Go jest potężny i nowoczesny w obsłudze niskopoziomowych wywołań

## Dalsza lektura

[syscall](https://pkg.go.dev/syscall)
[unsafe](https://pkg.go.dev/unsafe)
[x/sys/unix](https://pkg.go.dev/golang.org/x/sys/unix)
