Go syscall je brilantná náhrada nízkoúrovňového I/O
Zhrnutie
Oboznámime sa s priamym systémovým volaním v jazyku Go. Pretože Go ponúka prísne chyby kompilátora a rigidný GC, je omnoho lepšie nahradiť volania nízkej úrovne v Pure Go. Našťastie, väčšina volaní funkcií C je plne re-implementovaná v Go, a to dobrým a súčasným spôsobom. Pozrime sa na to.
Systémové volanie
Systémové volanie je priama požiadavka na operačný systém. Keďže je systém zvyčajne napísaný v rigidnom, staromódnom štýle, pretože beží priamo na hardvéri, musíme zvážiť, že jeho volanie musí poskytnúť prísnu a správnu formu požiadavky. Takže, aj keď nepotrebujeme nejaké premenné, stále musíme vyplniť veľkosť bez ohľadu na použitie. Pozrime sa na plne funkčný príklad.
Úplný príklad
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 _, _, errno := syscall.Syscall(syscall.SYS_SYSINFO, uintptr(unsafe.Pointer(&info)), 0, 0)
29 if errno != 0 {
30 fmt.Println("sysinfo syscall failed:", errno)
31 return
32 }
33
34 scale := float64(1 << 16)
35 fmt.Printf("Uptime: %d seconds\n", info.Uptime)
36 fmt.Printf("Load Average: %.2f %.2f %.2f\n",
37 float64(info.Loads[0])/scale,
38 float64(info.Loads[1])/scale,
39 float64(info.Loads[2])/scale)
40 fmt.Printf("Memory: total=%d MB free=%d MB buffer=%d MB\n",
41 info.Totalram*uint64(info.MemUnit)/1024/1024,
42 info.Freeram*uint64(info.MemUnit)/1024/1024,
43 info.Bufferram*uint64(info.MemUnit)/1024/1024)
44 fmt.Printf("Swap: total=%d MB free=%d MB\n",
45 info.Totalswap*uint64(info.MemUnit)/1024/1024,
46 info.Freeswap*uint64(info.MemUnit)/1024/1024)
47 fmt.Printf("Processes: %d\n", info.Procs)
48}
Tento príklad zahŕňa všetky premenné a tlačí rozsiahle informácie o aktuálnom systéme.
Tento kód môžeme prirovnať k skrinke a kľúču.syscall.SYS_SYSINFO je kľúč, ktorý odomyká skrinku, ktorá je vo vnútri jadra.
Preto je dôležité použiť správny kľúč pre skrinku.
Čo sa stane, ak použijeme syscall.SYS_GETPID pre toto volanie?
Toto je kľúč pre skrinku, ktorá obsahuje ID procesu (Process ID).
Tým sa pokúsi získať PID z priestoru pre systémové informácie.
V dôsledku toho nie je možné správne prečítať žiadne informácie; volanie musí byť vrátené ako neúspešný stav.
Teraz potrebujeme vedieť, ktoré položky sú obsiahnuté a ako sú usporiadané. V prvom slote skrinky máme Uptime s veľkosťou 2^64. Ak sa to pokúsime prečítať s 2^32, bitová sekvencia nie je úplne prečítaná. Nemôžeme použiť tieto druhy čiastočných binárnych súborov, pokiaľ nebudeme písať triky nízkej úrovne.
Po prečítaní 64 bitov binárnych údajov sme konečne na druhom slote. Môže byť prečítaný presne iba vtedy, ak sme prečítali predchádzajúce celé číslo s veľkosťou 64 bitov.
Opakovaním týchto prísnych a logických postupov na získanie správnych informácií zo systému môžeme správne spracovať prečítané údaje.
Ako preskočiť 'názvy premenných'
Aj keď nemôžeme 'preskočiť' samotné premenné, je dôležité rozlišovať použité premenné a tie, ktoré boli zahodené. Ak je použitie programu dostatočne jasné, je lepšie použiť bezmenné premenné ako zástupné symboly, než označovať každú hodnotu, aj keď nie sú nikdy použité. Pozrime sa na to na príklade, "Kontrola voľnej pamäte" (Free Memory Checker).
Príklad - Kontrola voľnej pamäte
Pri kontrole voľnej pamäte/odkladacích priestorov nepotrebujeme iné informácie, ktoré naznačujú iné zdroje. Na dosiahnutie lepšej prehľadnosti môžete vytvoriť anonymné premenné na uchovanie špecifických priestorov.
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 // anonymné a nepoužité sú označené ako _
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 _, _, 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 fmt.Printf("Memory: total=%d MB free=%d MB buffer=%d MB\n",
36 info.Totalram*uint64(info.MemUnit)/1024/1024,
37 info.Freeram*uint64(info.MemUnit)/1024/1024,
38 info.Bufferram*uint64(info.MemUnit)/1024/1024)
39 fmt.Printf("Swap: total=%d MB free=%d MB\n",
40 info.Totalswap*uint64(info.MemUnit)/1024/1024,
41 info.Freeswap*uint64(info.MemUnit)/1024/1024)
42}
V dôsledku toho sa premenné čítajú bez označení. Hoci sú anonymné hodnoty skutočne uložené v štruktúre, v kóde nie sú žiadne označenia/čitateľné značky.
Záver
- Používanie
syscallaunsafev Go je stále bezpečnejšie ako C/CGo - Ak píšete rozsiahly projekt, ktorý sa dá ľahko rozšíriť:
- Nevytvárajte anonymné premenné; vytvorte pre členov jednotlivé názvy.
- Ak píšete projekt, ktorý má obmedzené použitie:
- Môžete použiť anonymné premenné na uchovanie priestorov, ktoré sú v skutočnosti nevyužité.
syscallv Go je výkonný a moderný na spracovanie volaní nízkej úrovne