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