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  }