add a CVS snapshot, to thoroughly test on the Debian side
[alioth/jupp.git] / vfile.c
1 /* $MirOS: contrib/code/jupp/vfile.c,v 1.8 2013/08/19 22:03:20 tg Exp $ */
2 /*
3  *      Software virtual memory system
4  *      Copyright
5  *              (C) 1992 Joseph H. Allen
6  *
7  *      This file is part of JOE (Joe's Own Editor)
8  */
9 #include "config.h"
10 #include "types.h"
11
12 #ifdef HAVE_SYS_TYPES_H
13 #include <sys/types.h>
14 #endif
15 #ifdef HAVE_SYS_STAT_H
16 #include <sys/stat.h>
17 #endif
18 #include <fcntl.h>
19 #ifdef HAVE_STDLIB_H
20 #include <stdlib.h>
21 #endif
22 #include <unistd.h>
23
24 #include "blocks.h"
25 #include "queue.h"
26 #include "path.h"
27 #include "utils.h"
28 #include "vfile.h"
29 #include "vs.h"
30
31 static VFILE vfiles = { {&vfiles, &vfiles} };   /* Known vfiles */
32 static VPAGE *freepages = NULL; /* Linked list of free pages */
33 static VPAGE *htab[HTSIZE];     /* Hash table of page headers */
34 static long curvalloc = 0;      /* Amount of memory in use */
35 static long maxvalloc = ILIMIT; /* Maximum allowed */
36 unsigned char *vbase;                   /* Data first entry in vheader refers to */
37 VPAGE **vheaders = NULL;        /* Array of header addresses */
38 static int vheadsz = 0;         /* No. entries allocated to vheaders */
39
40 static unsigned int joe_random(void);
41
42 void vflsh(void)
43 {
44         VPAGE *vp;
45         VPAGE *vlowest;
46         long addr;
47         long last;
48         VFILE *vfile;
49         int x;
50
51         for (vfile = vfiles.link.next; vfile != &vfiles; vfile = vfile->link.next) {
52                 last = -1;
53               loop:
54                 addr = MAXLONG;
55                 vlowest = NULL;
56                 for (x = 0; x != HTSIZE; x++)
57                         for (vp = htab[x]; vp; vp = vp->next)
58                                 if (vp->addr < addr && vp->addr > last && vp->vfile == vfile && (vp->addr >= vfile->size || (vp->dirty && !vp->count))) {
59                                         addr = vp->addr;
60                                         vlowest = vp;
61                                 }
62                 if (vlowest) {
63                         if (!vfile->name)
64                                 vfile->name = mktmp(NULL,
65                                     vfile->fd ? NULL : &vfile->fd);
66                         if (!vfile->fd)
67                                 vfile->fd = open((char *)(vfile->name), O_RDWR);
68                         lseek(vfile->fd, addr, 0);
69                         if (addr + PGSIZE > vsize(vfile)) {
70                                 joe_write(vfile->fd, vlowest->data, vsize(vfile) - addr);
71                                 vfile->size = vsize(vfile);
72                         } else {
73                                 joe_write(vfile->fd, vlowest->data, PGSIZE);
74                                 if (addr + PGSIZE > vfile->size)
75                                         vfile->size = addr + PGSIZE;
76                         }
77                         vlowest->dirty = 0;
78                         last = addr;
79                         goto loop;
80                 }
81         }
82 }
83
84 void vflshf(VFILE *vfile)
85 {
86         VPAGE *vp;
87         VPAGE *vlowest;
88         long addr;
89         int x;
90
91       loop:
92         addr = MAXLONG;
93         vlowest = NULL;
94         for (x = 0; x != HTSIZE; x++)
95                 for (vp = htab[x]; vp; vp = vp->next)
96                         if (vp->addr < addr && vp->dirty && vp->vfile == vfile && !vp->count) {
97                                 addr = vp->addr;
98                                 vlowest = vp;
99                         }
100         if (vlowest) {
101                 if (!vfile->name)
102                         vfile->name = mktmp(NULL,
103                             vfile->fd ? NULL : &vfile->fd);
104                 if (!vfile->fd) {
105                         vfile->fd = open((char *)(vfile->name), O_RDWR);
106                 }
107                 lseek(vfile->fd, addr, 0);
108                 if (addr + PGSIZE > vsize(vfile)) {
109                         joe_write(vfile->fd, vlowest->data, vsize(vfile) - addr);
110                         vfile->size = vsize(vfile);
111                 } else {
112                         joe_write(vfile->fd, vlowest->data, PGSIZE);
113                         if (addr + PGSIZE > vfile->size)
114                                 vfile->size = addr + PGSIZE;
115                 }
116                 vlowest->dirty = 0;
117                 goto loop;
118         }
119 }
120
121 static unsigned char *mema(int align, int size)
122 {
123         unsigned char *z = (unsigned char *) joe_malloc(align + size);
124
125         return z + align - physical(z) % align;
126 }
127
128 unsigned char *vlock(VFILE *vfile, unsigned long addr)
129 {
130         VPAGE *vp, *pp;
131         int x, y;
132         long ofst = (addr & (PGSIZE - 1));
133
134         addr -= ofst;
135
136         for (vp = htab[((addr >> LPGSIZE) + (unsigned long) vfile) & (HTSIZE - 1)]; vp; vp = vp->next)
137                 if (vp->vfile == vfile && (unsigned long)vp->addr == addr) {
138                         ++vp->count;
139                         return vp->data + ofst;
140                 }
141
142         if (freepages) {
143                 vp = freepages;
144                 freepages = vp->next;
145                 goto gotit;
146         }
147
148         if (curvalloc + PGSIZE <= maxvalloc) {
149                 vp = (VPAGE *) joe_malloc(sizeof(VPAGE) * INC);
150                 if (vp) {
151                         vp->data = (unsigned char *) mema(PGSIZE, PGSIZE * INC);
152                         if (vp->data) {
153                                 int q;
154
155                                 curvalloc += PGSIZE * INC;
156                                 if (!vheaders) {
157                                         vheaders = (VPAGE **) joe_malloc((vheadsz = INC) * sizeof(VPAGE *));
158                                         vbase = vp->data;
159                                 } else if (physical(vp->data) < physical(vbase)) {
160                                         VPAGE **t = vheaders;
161                                         int amnt = (physical(vbase) - physical(vp->data)) >> LPGSIZE;
162
163                                         vheaders = (VPAGE **) joe_malloc((amnt + vheadsz) * sizeof(VPAGE *));
164                                         mmove(vheaders + amnt, t, vheadsz * sizeof(VPAGE *));
165                                         vheadsz += amnt;
166                                         vbase = vp->data;
167                                         joe_free(t);
168                                 } else if (((physical(vp->data + PGSIZE * INC) - physical(vbase)) >> LPGSIZE) > (unsigned long)vheadsz) {
169                                         vheaders = (VPAGE **)
170                                             joe_realloc(vheaders, (vheadsz = (((physical(vp->data + PGSIZE * INC) - physical(vbase)) >> LPGSIZE))) * sizeof(VPAGE *));
171                                 }
172                                 for (q = 1; q != INC; ++q) {
173                                         vp[q].next = freepages;
174                                         freepages = vp + q;
175                                         vp[q].data = vp->data + q * PGSIZE;
176                                         vheader(vp->data + q * PGSIZE) = vp + q;
177                                 }
178                                 vheader(vp->data) = vp;
179                                 goto gotit;
180                         }
181                         joe_free(vp);
182                         vp = NULL;
183                 }
184         }
185
186         for (y = HTSIZE, x = (joe_random() & (HTSIZE - 1)); y; x = ((x + 1) & (HTSIZE - 1)), --y)
187                 for (pp = (VPAGE *) (htab + x), vp = pp->next; vp; pp = vp, vp = vp->next)
188                         if (!vp->count && !vp->dirty) {
189                                 pp->next = vp->next;
190                                 goto gotit;
191                         }
192         vflsh();
193         for (y = HTSIZE, x = (joe_random() & (HTSIZE - 1)); y; x = ((x + 1) & (HTSIZE - 1)), --y)
194                 for (pp = (VPAGE *) (htab + x), vp = pp->next; vp; pp = vp, vp = vp->next)
195                         if (!vp->count && !vp->dirty) {
196                                 pp->next = vp->next;
197                                 goto gotit;
198                         }
199         if (write(2, "vfile: out of memory\n", 21)) {}
200         exit(1);
201
202       gotit:
203         vp->addr = addr;
204         vp->vfile = vfile;
205         vp->dirty = 0;
206         vp->count = 1;
207         vp->next = htab[((addr >> LPGSIZE) + (unsigned long)vfile) & (HTSIZE - 1)];
208         htab[((addr >> LPGSIZE) + (unsigned long)vfile) & (HTSIZE - 1)] = vp;
209
210         if (addr < (unsigned long)vfile->size) {
211                 if (!vfile->fd) {
212                         vfile->fd = open((char *)(vfile->name), O_RDWR);
213                 }
214                 lseek(vfile->fd, addr, 0);
215                 if (addr + PGSIZE > (unsigned long)vfile->size) {
216                         joe_read(vfile->fd, vp->data, vfile->size - addr);
217                         mset(vp->data + vfile->size - addr, 0, PGSIZE - (int) (vfile->size - addr));
218                 } else
219                         joe_read(vfile->fd, vp->data, PGSIZE);
220         } else
221                 mset(vp->data, 0, PGSIZE);
222
223         return vp->data + ofst;
224 }
225
226 VFILE *vtmp(void)
227 {
228         VFILE *new = (VFILE *) joe_malloc(sizeof(VFILE));
229
230         new->fd = 0;
231         new->name = NULL;
232         new->alloc = 0;
233         new->size = 0;
234         new->left = 0;
235         new->lv = 0;
236         new->vpage = NULL;
237         new->flags = 1;
238         new->vpage1 = NULL;
239         new->addr = -1;
240         return enqueb_f(VFILE, link, &vfiles, new);
241 }
242
243 void vclose(VFILE *vfile)
244 {
245         VPAGE *vp, *pp;
246         int x;
247
248         if (vfile->vpage)
249                 vunlock(vfile->vpage);
250         if (vfile->vpage1)
251                 vunlock(vfile->vpage1);
252         if (vfile->name) {
253                 if (vfile->flags)
254                         unlink((char *)vfile->name);
255                 else
256                         vflshf(vfile);
257                 vsrm(vfile->name);
258         }
259         if (vfile->fd)
260                 close(vfile->fd);
261         joe_free(deque_f(VFILE, link, vfile));
262         for (x = 0; x != HTSIZE; x++)
263                 for (pp = (VPAGE *) (htab + x), vp = pp->next; vp;)
264                         if (vp->vfile == vfile) {
265                                 pp->next = vp->next;
266                                 vp->next = freepages;
267                                 freepages = vp;
268                                 vp = pp->next;
269                         } else {
270                                 pp = vp;
271                                 vp = vp->next;
272                         }
273 }
274
275 long my_valloc(VFILE *vfile, long int size)
276 {
277         long start = vsize(vfile);
278
279         vfile->alloc = start + size;
280         if (vfile->lv) {
281                 if (vheader(vfile->vpage)->addr + PGSIZE > vfile->alloc)
282                         vfile->lv = PGSIZE - (vfile->alloc - vheader(vfile->vpage)->addr);
283                 else
284                         vfile->lv = 0;
285         }
286         return start;
287 }
288
289 #if ((HTSIZE) <= 0x8000)
290 /* Borland LCG */
291 static unsigned int
292 joe_random(void)
293 {
294         static unsigned int lcg_state = 5381;
295
296         return (((lcg_state = 22695477 * lcg_state + 1) >> 16) & 0x7FFF);
297 }
298 #endif