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