A Go syscall a low-level I/O ragyogó helyettesítője.
Összefoglalás
Megismerkedünk a közvetlen rendszerhívással Go nyelven. Mivel a Go szigorú fordítóprogram-hibákat és merev GC-t kínál, sokkal jobb a low-level hívásokat tiszta Go-ban helyettesíteni. Szerencsére a legtöbb C függvényhívás teljes mértékben újraimplementálva lett Go nyelven, megfelelő és korszerű módon. Vessünk rá egy pillantást.
Rendszerhívás (System Call)
A rendszerhívás közvetlen kérés az operációs rendszerhez. Mivel a rendszert általában merev, régimódi stílusban írják, mivel közvetlenül a hardveren fut, figyelembe kell vennünk, hogy a hívásának a kérés szigorú és korrekt formáját kell továbbítania. Tehát, még ha nincs is szükségünk néhány változóra, a méretet akkor is ki kell töltenünk, a felhasználástól függetlenül. Nézzünk meg egy teljesen működő példát.
Teljes példa
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}
Ez a példa tartalmazza az összes változót, és kiterjedt információkat nyomtat a jelenlegi rendszerinformációkról.
Összehasonlíthatjuk ezt a kódot egy zárral és egy kulccsal.
A syscall.SYS_SYSINFO egy kulcs, amely kinyit egy zárat, amely a kernelen belül található.
Ezért fontos a megfelelő kulcs használata a zárhoz.
Mi történik, ha syscall.SYS_GETPID-et használunk ehhez a híváshoz?
Ez egy kulcs ahhoz a zárhoz, amely a Process ID-t tartalmazza.
Ez megpróbálja lekérni a PID-et a rendszerinformációk számára kijelölt helyről.
Ennek eredményeként egyetlen információ sem olvasható be helyesen; a hívásnak sikertelen állapotban kell visszatérnie.
Most tudnunk kell, hogy mely elemeket tartalmazza, és hogyan vannak sorrendben az elemek. A zár első nyílásában van az Uptime, 2^64 mérettel. Ha ezt 2^32-vel próbáljuk beolvasni, a bitsorozat nem olvasható be teljesen. Nem használhatjuk az ilyen típusú részleges bináris adatokat, hacsak nem low-level trükköket fogunk írni.
64 bit bináris adat beolvasása után végre a második nyílásnál tartunk. Csak akkor olvasható be pontosan, ha beolvastuk az előző 64 bites méretű egészet.
Ezeknek a szigorú és logikai folyamatoknak a megismétlésével, hogy megfelelő információt szerezzünk a rendszerből, megfelelően tudjuk kezelni a beolvasott adatokat.
Hogyan hagyjuk figyelmen kívül a 'változóneveket'
Bár magukat a változókat nem tudjuk 'kihagyni', fontos megkülönböztetni a használt változókat és az elvetetteket. Ha a program felhasználása kellően egyértelmű, jobb névtelen változókat használni helykitöltőként, mint minden értéket felcímkézni, még akkor is, ha soha nem kerülnek felhasználásra. Nézzük meg ezt egy példával, a "Free Memory Checker"-rel (Szabad memória ellenőrző).
Példa - Szabad memória ellenőrző
Amikor a Szabad Memóriát/Swap-et ellenőrizzük, nincs szükségünk más információra, amely eltérő erőforrásokat jelez. A jobb átláthatóság érdekében névtelen változókat hozhat létre, hogy megtartsák a specifikus helyeket.
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 // anonymous, and unused ones are marked as _ (a névtelen és nem használtakat _ jelöli)
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}
Következésképpen a változók címkék nélkül kerülnek beolvasásra. Bár a névtelen értékek ténylegesen tárolódnak egy struktúrában, a kódon nincsenek címkék/olvasható jelölések.
Következtetés
- A Go
syscallésunsafehasználata még mindig biztonságosabb, mint a C/CGo - Ha egy hatalmas projektet ír, amelyet könnyen ki lehet bővíteni:
- Ne hozzon létre névtelen változókat; adjon nevet minden tagnak.
- Ha olyan projektet ír, amely korlátozott felhasználású:
- Használhat névtelen változókat az olyan helyek megtartására, amelyek ténylegesen kihasználatlanok.
- A Go
syscallhatékony és modern a low-level hívások kezelésére