9fans.net/go@v0.0.7/cmd/sam/disk.go (about) 1 // #include "sam.h" 2 3 package main 4 5 import ( 6 "io" 7 "reflect" 8 "unsafe" 9 ) 10 11 var blist *Block 12 13 func diskinit() *Disk { 14 d := new(Disk) 15 d.fd = tempdisk() 16 return d 17 } 18 19 func ntosize(n int, ip *int) int { 20 if n > Maxblock { 21 panic_("internal error: ntosize") 22 } 23 size := n 24 if size&(Blockincr-1) != 0 { 25 size += Blockincr - (size & (Blockincr - 1)) 26 } 27 /* last bucket holds blocks of exactly Maxblock */ 28 if ip != nil { 29 *ip = size / Blockincr 30 } 31 return size * RUNESIZE 32 } 33 34 func disknewblock(d *Disk, n int) *Block { 35 var i int 36 size := ntosize(n, &i) 37 b := d.free[i] 38 if b != nil { 39 d.free[i] = b.u.next 40 } else { 41 /* allocate in chunks to reduce malloc overhead */ 42 if blist == nil { 43 bb := make([]Block, 100) 44 for j := 0; j < 100-1; j++ { 45 bb[j].u.next = &bb[j+1] 46 } 47 blist = &bb[0] 48 } 49 b = blist 50 blist = b.u.next 51 b.addr = d.addr 52 if d.addr+int64(size) < d.addr { 53 panic_("temp file overflow") 54 } 55 d.addr += int64(size) 56 } 57 b.u.n = n 58 return b 59 } 60 61 func diskrelease(d *Disk, b *Block) { 62 var i int 63 ntosize(b.u.n, &i) 64 b.u.next = d.free[i] 65 d.free[i] = b 66 } 67 68 func runedata(r []rune) []byte { 69 var b []byte 70 h := (*reflect.SliceHeader)(unsafe.Pointer(&b)) 71 h.Data = uintptr(unsafe.Pointer(&r[0])) 72 h.Len = RUNESIZE * len(r) 73 h.Cap = RUNESIZE * cap(r) 74 return b 75 } 76 77 func diskwrite(d *Disk, bp **Block, r []rune) { 78 n := len(r) 79 b := *bp 80 size := ntosize(b.u.n, nil) 81 nsize := ntosize(n, nil) 82 if size != nsize { 83 diskrelease(d, b) 84 b = disknewblock(d, n) 85 *bp = b 86 } 87 if nw, err := d.fd.WriteAt(runedata(r), b.addr); nw != n*RUNESIZE || err != nil { 88 if err == nil { 89 err = io.ErrShortWrite 90 } 91 panic_("writing temp file: %v", err) 92 } 93 b.u.n = n 94 } 95 96 func diskread(d *Disk, b *Block, r []rune) { 97 n := len(r) 98 if n > b.u.n { 99 panic_("internal error: diskread") 100 } 101 102 ntosize(b.u.n, nil) /* called only for sanity check on Maxblock */ 103 if nr, err := d.fd.ReadAt(runedata(r), b.addr); nr != n*RUNESIZE || err != nil { 104 panic_("read error from temp file") 105 } 106 }