xref: /plan9/sys/src/cmd/acme/disk.c (revision ff8c3af2f44d95267f67219afa20ba82ff6cf7e4)
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <thread.h>
5 #include <cursor.h>
6 #include <mouse.h>
7 #include <keyboard.h>
8 #include <frame.h>
9 #include <fcall.h>
10 #include <plumb.h>
11 #include "dat.h"
12 #include "fns.h"
13 
14 static	Block	*blist;
15 
16 int
17 tempfile(void)
18 {
19 	char buf[128];
20 	int i, fd;
21 
22 	snprint(buf, sizeof buf, "/tmp/X%d.%.4sacme", getpid(), getuser());
23 	for(i='A'; i<='Z'; i++){
24 		buf[5] = i;
25 		if(access(buf, AEXIST) == 0)
26 			continue;
27 		fd = create(buf, ORDWR|ORCLOSE|OCEXEC, 0600);
28 		if(fd >= 0)
29 			return fd;
30 	}
31 	return -1;
32 }
33 
34 Disk*
35 diskinit()
36 {
37 	Disk *d;
38 
39 	d = emalloc(sizeof(Disk));
40 	d->fd = tempfile();
41 	if(d->fd < 0){
42 		fprint(2, "acme: can't create temp file: %r\n");
43 		threadexitsall("diskinit");
44 	}
45 	return d;
46 }
47 
48 static
49 uint
50 ntosize(uint n, uint *ip)
51 {
52 	uint size;
53 
54 	if(n > Maxblock)
55 		error("internal error: ntosize");
56 	size = n;
57 	if(size & (Blockincr-1))
58 		size += Blockincr - (size & (Blockincr-1));
59 	/* last bucket holds blocks of exactly Maxblock */
60 	if(ip)
61 		*ip = size/Blockincr;
62 	return size * sizeof(Rune);
63 }
64 
65 Block*
66 disknewblock(Disk *d, uint n)
67 {
68 	uint i, j, size;
69 	Block *b;
70 
71 	size = ntosize(n, &i);
72 	b = d->free[i];
73 	if(b)
74 		d->free[i] = b->next;
75 	else{
76 		/* allocate in chunks to reduce malloc overhead */
77 		if(blist == nil){
78 			blist = emalloc(100*sizeof(Block));
79 			for(j=0; j<100-1; j++)
80 				blist[j].next = &blist[j+1];
81 		}
82 		b = blist;
83 		blist = b->next;
84 		b->addr = d->addr;
85 		d->addr += size;
86 	}
87 	b->n = n;
88 	return b;
89 }
90 
91 void
92 diskrelease(Disk *d, Block *b)
93 {
94 	uint i;
95 
96 	ntosize(b->n, &i);
97 	b->next = d->free[i];
98 	d->free[i] = b;
99 }
100 
101 void
102 diskwrite(Disk *d, Block **bp, Rune *r, uint n)
103 {
104 	int size, nsize;
105 	Block *b;
106 
107 	b = *bp;
108 	size = ntosize(b->n, nil);
109 	nsize = ntosize(n, nil);
110 	if(size != nsize){
111 		diskrelease(d, b);
112 		b = disknewblock(d, n);
113 		*bp = b;
114 	}
115 	if(pwrite(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune))
116 		error("write error to temp file");
117 	b->n = n;
118 }
119 
120 void
121 diskread(Disk *d, Block *b, Rune *r, uint n)
122 {
123 	if(n > b->n)
124 		error("internal error: diskread");
125 
126 	ntosize(b->n, nil);
127 	if(pread(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune))
128 		error("read error from temp file");
129 }
130