GoSuda

Go syscall is een briljante vervanging van low-level I/O

By Yunjin Lee
views ...

Samenvatting

We zullen leren over directe systeemaanroepen in Go. Aangezien Go strikte compilerfouten en rigide GC biedt, is het veel beter om low-level aanroepen te vervangen door Pure Go. Gelukkig zijn de meeste C-functieaanroepen volledig opnieuw geïmplementeerd in Go, op een goede en eigentijdse manier. Laten we ernaar kijken.

Systeemaanroep

Een systeemaanroep is een direct verzoek aan het besturingssysteem. Aangezien een systeem meestal in een rigide, ouderwetse stijl is geschreven, omdat het direct op hardware draait, moeten we overwegen dat de aanroep ervan een strikte en correcte vorm van een verzoek moet leveren. Dus, zelfs als we sommige variabelen niet nodig hebben, moeten we de grootte toch invullen, ongeacht het gebruik. Laten we dit controleren met een volledig werkend voorbeeld.

Volledig voorbeeld

 1package main
 2import (
 3	"fmt"
 4	"syscall"
 5	"unsafe"
 6)
 7
 8type sysinfo_t struct {
 9	Uptime    int64
10	Loads     [3]uint64
11	Totalram  uint64
12	Freeram   uint64
13	Sharedram uint64
14	Bufferram uint64
15	Totalswap uint64
16	Freeswap  uint64
17	Procs     uint16
18	Pad       uint16
19	_         [4]byte
20	Totalhigh uint64
21	Freehigh  uint64
22	MemUnit   uint32
23	_         [4]byte
24}
25
26func main() {
27	var info sysinfo_t
28	// Roep de SYS_SYSINFO systeemaanroep aan om systeeminformatie te verkrijgen
29	_, _, errno := syscall.Syscall(syscall.SYS_SYSINFO, uintptr(unsafe.Pointer(&info)), 0, 0)
30	// Controleer op fouten
31	if errno != 0 {
32		fmt.Println("sysinfo systeemaanroep mislukt:", errno)
33		return
34	}
35
36	scale := float64(1 << 16)
37	fmt.Printf("Uptime: %d seconden\n", info.Uptime)
38	fmt.Printf("Gemiddelde belasting: %.2f %.2f %.2f\n",
39		float64(info.Loads[0])/scale,
40		float64(info.Loads[1])/scale,
41		float64(info.Loads[2])/scale)
42	fmt.Printf("Geheugen: totaal=%d MB vrij=%d MB buffer=%d MB\n",
43		info.Totalram*uint64(info.MemUnit)/1024/1024,
44		info.Freeram*uint64(info.MemUnit)/1024/1024,
45		info.Bufferram*uint64(info.MemUnit)/1024/1024)
46	fmt.Printf("Swap: totaal=%d MB vrij=%d MB\n",
47		info.Totalswap*uint64(info.MemUnit)/1024/1024,
48		info.Freeswap*uint64(info.MemUnit)/1024/1024)
49	fmt.Printf("Processen: %d\n", info.Procs)
50}

Dit voorbeeld omvat alle variabelen en drukt uitgebreide informatie over de huidige systeeminformatie af. We kunnen deze code vergelijken met een kluis en een sleutel.syscall.SYS_SYSINFO is een sleutel die een kluis ontgrendelt die zich in de kernel bevindt. Daarom is het belangrijk om de juiste sleutel voor een kluis te gebruiken. Wat zal er gebeuren als we syscall.SYS_GETPID gebruiken voor deze aanroep? Dit is een sleutel voor een kluis die de Proces ID bevat. Dit zal proberen een PID te verkrijgen uit een ruimte voor systeeminformatie. Als gevolg hiervan kan geen van de informatie correct worden gelezen; de aanroep moet worden geretourneerd als een mislukte status.

Nu moeten we weten welke items zijn opgenomen en hoe items zijn gerangschikt. In het eerste slot van een kluis hebben we Uptime, met een grootte van 2^64. Als we dit proberen te lezen met 2^32, wordt de bitreeks niet volledig gelezen. We kunnen dit soort partiële binaire bestanden niet gebruiken, tenzij we low-level trucs gaan schrijven.

Na het lezen van 64 bits binaire gegevens, zijn we eindelijk bij het tweede slot. Dit kan alleen nauwkeurig worden gelezen als we de vorige 64-bit sized integer hebben gelezen.

Door deze strikte en logische stromen te herhalen om de juiste informatie van een systeem te verkrijgen, kunnen we gelezen gegevens correct verwerken.

Hoe 'variabelenamen' over te slaan

Hoewel we variabelen zelf niet kunnen 'overslaan', is het belangrijk om gebruikte variabelen en weggegooide variabelen te onderscheiden. Als het gebruik van het programma duidelijk genoeg is, is het beter om naamloze variabelen als plaatsaanduidingen te gebruiken dan elke waarde te labelen, zelfs als deze nooit worden gebruikt. Laten we dit controleren met een voorbeeld, "Vrije Geheugen Checker".

Voorbeeld - Vrije Geheugen Checker

Bij het controleren van Vrij Geheugen/Swaps hebben we geen andere informatie nodig die verschillende bronnen aangeeft. Om een betere zichtbaarheid te bereiken, kunt u anonieme variabelen maken om specifieke ruimtes vast te houden.

 1package main
 2
 3import (
 4	"fmt"
 5	"syscall"
 6	"unsafe"
 7)
 8
 9type sysinfo_t struct {
10	_          int64 // Anoniem veld voor Uptime
11	_         [3]uint64 // Anoniem veld voor Loads
12	Totalram  uint64
13	Freeram   uint64
14	Sharedram uint64
15	Bufferram uint64
16	Totalswap uint64
17	Freeswap  uint64
18	_         uint16  // anoniem, en ongebruikte worden gemarkeerd als _
19	_         uint16  // anoniem veld
20	_         [4]byte // anoniem veld
21	_         uint64  // anoniem veld
22	_         uint64  // anoniem veld
23	MemUnit   uint32
24	_         [4]byte // anoniem veld
25}
26
27func main() {
28	var info sysinfo_t
29	// Roep de SYS_SYSINFO systeemaanroep aan om systeeminformatie te verkrijgen
30	_, _, errno := syscall.Syscall(syscall.SYS_SYSINFO, uintptr(unsafe.Pointer(&info)), 0, 0)
31	// Controleer op fouten
32	if errno != 0 {
33		fmt.Println("sysinfo systeemaanroep mislukt:", errno)
34		return
35	}
36
37	fmt.Printf("Geheugen: totaal=%d MB vrij=%d MB buffer=%d MB\n",
38		info.Totalram*uint64(info.MemUnit)/1024/1024,
39		info.Freeram*uint64(info.MemUnit)/1024/1024,
40		info.Bufferram*uint64(info.MemUnit)/1024/1024)
41	fmt.Printf("Swap: totaal=%d MB vrij=%d MB\n",
42		info.Totalswap*uint64(info.MemUnit)/1024/1024,
43		info.Freeswap*uint64(info.MemUnit)/1024/1024)
44}

Dientengevolge worden variabelen gelezen zonder labels. Hoewel anonieme waarden daadwerkelijk in een structuur worden opgeslagen, zijn er geen labels/leesbare markeringen in de code.

Conclusie

  • Het gebruik van Go's syscall en unsafe is nog steeds veiliger dan C/CGo
  • Als u een groot project schrijft dat gemakkelijk kan worden uitgebreid:
    • Maak geen anonieme variabelen; geef elk lid een naam.
  • Als u een project schrijft dat beperkt gebruik heeft:
    • U kunt anonieme variabelen gebruiken om ruimtes vast te houden die eigenlijk ongebruikt zijn.
  • Go's syscall is krachtig en modern om low-level aanroepen af te handelen

Verder lezen

syscall unsafe x/sys/unix