GoSuda

Go syscall on loistava korvike matalan tason I/O:lle

By Yunjin Lee
views ...

Yhteenveto

Opimme suorista järjestelmäkutsuista Go-kielellä. Koska Go tarjoaa tiukat kääntäjävirheet ja jäykän GC:n, on paljon parempi korvata matalan tason kutsut puhtaalla Go-kielellä. Onneksi suurin osa C-funktiokutsuista on toteutettu Go-kielellä uudelleen täysin, hyvällä ja nykyaikaisella tavalla. Tarkastellaan sitä.

Järjestelmäkutsu

Järjestelmäkutsu on suora pyyntö käyttöjärjestelmälle. Koska järjestelmä on yleensä kirjoitettu jäykällä, vanhanaikaisella tyylillä, koska se toimii suoraan laitteistolla, meidän on otettava huomioon, että sen kutsun on toimitettava pyyntö tiukassa ja oikeassa muodossa. Joten, vaikka emme tarvitsisi joitakin muuttujia, meidän on silti täytettävä koko riippumatta käytöstä. Tarkastellaan tätä täysin toimivalla esimerkillä.

Täydellinen esimerkki

 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	// Kutsu sysinfo-järjestelmäkutsua
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}

Tämä esimerkki sisältää kaikki muuttujat ja tulostaa kattavan tiedon nykyisistä järjestelmätiedoista. Voimme verrata tätä koodia lukkoon ja avaimeen.syscall.SYS_SYSINFO on avain, joka avaa lukon, joka on ytimen sisällä. Siksi oikean avaimen käyttö lukkoon on tärkeää. Mitä tapahtuu, jos käytämme syscall.SYS_GETPID-kutsua tähän tarkoitukseen? Tämä on avain lukkoon, joka sisältää prosessin ID:n. Tämä yrittää hakea PID:n järjestelmätietojen tilasta. Tämän seurauksena mitään tietoja ei voida lukea oikein; kutsun on palautettava epäonnistunut tila.

Nyt meidän on tiedettävä, mitkä kohteet sisältyvät ja miten kohteet on järjestetty. Lukon ensimmäisessä paikassa meillä on Uptime, jonka koko on 2^64. Jos yritämme lukea tämän 2^32:lla, bittijonoa ei lueta kokonaan. Emme voi käyttää tällaisia osittaisia binäärejä, ellemme aio kirjoittaa matalan tason temppuja.

Luettuaan 64 bittiä binääritietoa olemme lopulta toisessa paikassa. Se voidaan lukea tarkasti vain, kun olemme lukeneet edellisen 64-bittisen kokonaisluvun.

Toistamalla näitä tiukkoja ja loogisia virtoja oikean tiedon saamiseksi järjestelmästä voimme käsitellä luettua dataa asianmukaisesti.

Kuinka ohittaa 'muuttujanimet'

Vaikka emme voi "ohittaa" itse muuttujia, on tärkeää erottaa käytetyt muuttujat hylätyistä. Jos ohjelman käyttö on riittävän selkeää, on parempi käyttää nimettömiä muuttujia paikanpitäjinä kuin nimetä jokaista arvoa, vaikka niitä ei koskaan käytettäisikään. Tarkastellaan tätä esimerkkiä, "Vapaan muistin tarkistaja".

Esimerkki - Vapaan muistin tarkistaja

Tarkistaessamme vapaata muistia/vaihtotiedostoja emme tarvitse muita tietoja, jotka osoittavat erilaisia resursseja. Paremman näkyvyyden saavuttamiseksi voit luoda anonyymejä muuttujia pitämään tiettyjä tiloja.

 1package main
 2
 3import (
 4	"fmt"
 5	"syscall"
 6	"unsafe"
 7)
 8
 9type sysinfo_t struct {
10	_          int64 // Anonyymi, ja käyttämättömät on merkitty _
11	_         [3]uint64
12	Totalram  uint64
13	Freeram   uint64
14	Sharedram uint64
15	Bufferram uint64
16	Totalswap uint64
17	Freeswap  uint64
18	_         uint16  
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	// Kutsu sysinfo-järjestelmäkutsua
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}

Näin ollen muuttujat luetaan ilman tunnisteita. Vaikka anonyymit arvot tallennetaan itse asiassa rakenteeseen, koodissa ei ole tunnisteita/luettavia merkintöjä.

Johtopäätös

  • Gon syscall- ja unsafe-pakettien käyttö on edelleen turvallisempaa kuin C/CGo:n.
  • Jos kirjoitat valtavaa projektia, jota voidaan helposti laajentaa:
    • Älä tee anonyymejä muuttujia; anna jokaiselle jäsenelle oma nimi.
  • Jos kirjoitat projektia, jolla on rajoitettu käyttö:
    • Voit käyttää anonyymejä muuttujia varaamaan tiloja, jotka ovat tosiasiallisesti käyttämättömiä.
  • Gon syscall on tehokas ja moderni matalan tason kutsujen käsittelyyn.

Lue lisää

syscall unsafe x/sys/unix