Go syscall is een briljante vervanging van low-level I/O
Samenvatting
We zullen leren over directe system call in Go. Aangezien Go strikte compiler errors en rigide GC biedt, is het veel beter om low-level aanroepen te vervangen in Pure Go. Gelukkig zijn de meeste C functieaanroepen volledig opnieuw geïmplementeerd in Go, op een goede en eigentijdse manier. Laten we ernaar kijken.
System Call
System call is een direct verzoek aan het besturingssysteem. Aangezien het systeem meestal in een rigide, ouderwetse stijl is geschreven omdat het rechtstreeks 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 toch de grootte 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 // Aanroep van de sysinfo system call
29 _, _, errno := syscall.Syscall(syscall.SYS_SYSINFO, uintptr(unsafe.Pointer(&info)), 0, 0)
30 if errno != 0 {
31 fmt.Println("sysinfo syscall failed:", errno)
32 return
33 }
34
35 scale := float64(1 << 16)
36 fmt.Printf("Uptime: %d seconds\n", info.Uptime)
37 fmt.Printf("Load Average: %.2f %.2f %.2f\n",
38 float64(info.Loads[0])/scale,
39 float64(info.Loads[1])/scale,
40 float64(info.Loads[2])/scale)
41 fmt.Printf("Memory: total=%d MB free=%d MB buffer=%d MB\n",
42 info.Totalram*uint64(info.MemUnit)/1024/1024,
43 info.Freeram*uint64(info.MemUnit)/1024/1024,
44 info.Bufferram*uint64(info.MemUnit)/1024/1024)
45 fmt.Printf("Swap: total=%d MB free=%d MB\n",
46 info.Totalswap*uint64(info.MemUnit)/1024/1024,
47 info.Freeswap*uint64(info.MemUnit)/1024/1024)
48 fmt.Printf("Processes: %d\n", info.Procs)
49}
Dit voorbeeld bevat 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 die zich in een kernel bevindt, ontgrendelt.
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 Process 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 toestand.
Nu moeten we weten welke items erin zitten en hoe de items zijn gerangschikt. In een 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 gedeeltelijke 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. Het kan alleen nauwkeurig worden gelezen als we het vorige 64-bit grote geheel getal 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 onderscheid te maken tussen gebruikte variabelen en weggegooide variabelen. 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 ze nooit worden gebruikt. Laten we dit controleren met een voorbeeld, "Free Memory 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
11 _ [3]uint64
12 Totalram uint64
13 Freeram uint64
14 Sharedram uint64
15 Bufferram uint64
16 Totalswap uint64
17 Freeswap uint64
18 _ uint16 // anonieme en ongebruikte zijn gemarkeerd als _
19 _ uint16
20 _ [4]byte
21 _ uint64
22 _ uint64
23 MemUnit uint32
24 _ [4]byte
25}
26
27func main() {
28 var info sysinfo_t
29 // Aanroep van de sysinfo system call
30 _, _, errno := syscall.Syscall(syscall.SYS_SYSINFO, uintptr(unsafe.Pointer(&info)), 0, 0)
31 if errno != 0 {
32 fmt.Println("sysinfo syscall failed:", errno)
33 return
34 }
35
36 fmt.Printf("Memory: total=%d MB free=%d MB buffer=%d MB\n",
37 info.Totalram*uint64(info.MemUnit)/1024/1024,
38 info.Freeram*uint64(info.MemUnit)/1024/1024,
39 info.Bufferram*uint64(info.MemUnit)/1024/1024)
40 fmt.Printf("Swap: total=%d MB free=%d MB\n",
41 info.Totalswap*uint64(info.MemUnit)/1024/1024,
42 info.Freeswap*uint64(info.MemUnit)/1024/1024)
43}
Dientengevolge worden variabelen gelezen zonder labels. Hoewel anonieme waarden feitelijk in een structuur worden opgeslagen, zijn er geen labels/leesbare markeringen in de code.
Conclusie
- Het gebruik van Go's
syscallenunsafeis nog steeds veiliger dan C/CGo - Als u een enorm project schrijft dat gemakkelijk kan worden uitgebreid:
- Maak geen anonieme variabelen; maak namen voor elk van de leden.
- Als u een project schrijft dat beperkt is in gebruik:
- U kunt anonieme variabelen gebruiken om ruimtes vast te houden die feitelijk ongebruikt zijn.
- Go's
syscallis krachtig en modern om low-level aanroepen te verwerken