Clean up RCS ids
[projects/cmucl/cmucl.git] / src / lisp / hpux-os.c
1 /*
2  *
3  * OS-dependent routines.  This file (along with os.h) exports an
4  * OS-independent interface to the operating system VM facilities.
5  * Suprisingly, this interface looks a lot like the Mach interface
6  * (but simpler in some places).  For some operating systems, a subset
7  * of these functions will have to be emulated.
8  *
9  */
10
11 /* Assumptions these routines are based on:
12 os_validate: Not called with NULL for an addr.
13 os_invalidate: Never called.
14 os_map: Files are only mapped at the beginning of one of the areas passed
15         to os_validate.
16 os_protect: Only called on an entire region when giving permissions and only
17             called from some point in a segment to the end of the segment
18             when removing them.
19             Only called with all protections or no protections.
20 os_zero: Only ever zeroed from some point in a segment to the end of the
21          segment.
22 os_allocate_at: Calls to here are disjoint from those around it (the others
23         in os-common.c) since it calls os_validate and the others (in 
24         os-common.c) use malloc, etc.
25 Note that os_validate does not actually allocate memory until it has to map
26 the particular section in.
27 */
28
29 /* #define DEBUG */
30
31 #include <stdio.h>
32 #include <assert.h>
33 #include <signal.h>
34 #include <sys/file.h>
35 #include <unistd.h>
36 #include "os.h"
37 #include <sys/resource.h>
38 #include "interrupt.h"
39 #include <netdb.h>
40 #include <sys/times.h>
41 #include <errno.h>
42
43 os_vm_size_t os_vm_page_size = (-1);
44
45 #define MAX_SEGMENTS 20
46 #define ALLOC_SIZE 0x10000
47 static struct segment {
48     os_vm_address_t base;
49     os_vm_size_t len;
50     os_vm_address_t valid;
51     os_vm_address_t protected;
52 } segments[MAX_SEGMENTS];
53
54 void
55 os_init0(const char *argv[], const char *envp[])
56 {}
57
58 void
59 os_init(const char *argv[], const char *envp[])
60 {
61     int i;
62
63     os_vm_page_size = sysconf(_SC_PAGE_SIZE);
64     for (i = 0; i < MAX_SEGMENTS; i++)
65         segments[i].len = 0;
66 }
67
68
69 os_vm_address_t os_validate(os_vm_address_t addr, os_vm_size_t len)
70 {
71     int fd, i;
72     caddr_t ret;
73
74     addr = os_trunc_to_page(addr);
75     len = os_round_up_size_to_page(len);
76
77 #ifdef DEBUG
78     printf("os_validate: addr: 0x%X, len: 0x%X, end: 0x%X\n", addr, len,
79            addr + len);
80 #endif
81     assert(addr != NULL);
82     assert(len != 0);
83
84     for (i = 0; i < MAX_SEGMENTS; i++)
85         if (segments[i].len == 0)
86             break;
87
88     assert(i != MAX_SEGMENTS);
89
90     segments[i].base = addr;
91     segments[i].len = len;
92     segments[i].valid = addr;
93     segments[i].protected = addr + len;
94     return addr;
95 }
96
97 void
98 os_invalidate(os_vm_address_t addr, os_vm_size_t len)
99 {
100     assert(FALSE);
101 }
102
103 os_vm_address_t
104 os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
105 {
106     int i;
107
108     addr = os_trunc_to_page(addr);
109     len = os_round_up_size_to_page(len);
110
111     if (mmap(addr, len, OS_VM_PROT_ALL, MAP_FILE | MAP_FIXED | MAP_PRIVATE, fd,
112              (off_t) offset) == (os_vm_address_t) - 1) {
113         perror("mmap");
114         return NULL;
115     }
116
117     for (i = 0; i < MAX_SEGMENTS; i++)
118         if (segments[i].len != 0 && segments[i].base == addr)
119             break;
120
121     assert(i != MAX_SEGMENTS);
122     assert(segments[i].valid == addr);
123
124     segments[i].valid = addr + len;
125 #ifdef DEBUG
126     printf("os_map: addr: 0x%X, len: 0x%X, end: 0x%X\n", addr, len, addr + len);
127 #endif
128     return addr;
129 }
130
131 void
132 os_flush_icache(os_vm_address_t address, os_vm_size_t length)
133 {
134     sanctify_for_execution(address, length);
135 }
136
137 void
138 os_protect(os_vm_address_t addr, os_vm_size_t len, os_vm_prot_t prot)
139 {
140     int i;
141
142     addr = os_trunc_to_page(addr);
143     len = os_round_up_size_to_page(len);
144
145     for (i = 0; i < MAX_SEGMENTS; i++)
146         if (segments[i].base <= addr
147             && addr < segments[i].base + segments[i].len) break;
148
149     assert(i != MAX_SEGMENTS);
150
151     if (prot) {
152         assert(segments[i].base == addr && segments[i].len == len);
153         segments[i].protected = addr + len;
154     } else {
155         assert(segments[i].protected == addr + len);
156         segments[i].protected = addr;
157     }
158
159     if (addr < segments[i].valid)
160         if (mprotect(addr, segments[i].valid - addr, prot) == -1) {
161             perror("mprotect");
162             printf("segments[i].base: 0x%X\n", segments[i].base);
163             printf("segments[i].len: 0x%X\n", segments[i].len);
164             printf("segments[i].valid: 0x%X\n", segments[i].valid);
165             printf("addr: 0x%X, segments[i].valid-addr: 0x%X\n", addr,
166                    segments[i].valid - addr);
167             printf("prot: 0x%X, len 0x%X\n", prot, len);
168             assert(FALSE);
169         }
170 #ifdef DEBUG
171     printf("os_protect: addr: 0x%X, len: 0x%X, end: 0x%X, prot 0x%X\n",
172            addr, len, addr + len, prot);
173 #endif
174 }
175
176 boolean valid_addr(os_vm_address_t addr)
177 {
178     int i;
179
180     for (i = 0; i < MAX_SEGMENTS; i++)
181         if (segments[i].base <= addr
182             && addr < segments[i].base + segments[i].len) return TRUE;
183     return FALSE;
184 }
185
186 void
187 segv_handler(int signal, int code, struct sigcontext *context)
188 {
189     int i;
190     os_vm_address_t addr, nvalid;
191
192     sigsetmask(BLOCKABLE);
193
194     addr = (os_vm_address_t) context->sc_sl.sl_ss.ss_cr21;      /* verify this!!! */
195     for (i = 0; i < MAX_SEGMENTS; i++)
196         if (segments[i].len != 0 && segments[i].base <= addr &&
197             addr < segments[i].base + segments[i].len)
198             break;
199     if (i == MAX_SEGMENTS || addr < segments[i].valid)
200         interrupt_handle_now(signal, code, context);
201     else if (segments[i].protected <= addr) {
202         if (!interrupt_maybe_gc(signal, code, context))
203             interrupt_handle_now(signal, code, context);
204     } else {
205         nvalid =
206             ((os_vm_address_t)
207              (((long) (addr + ALLOC_SIZE)) & ~((long) (ALLOC_SIZE - 1))));
208         if (nvalid > segments[i].protected)
209             nvalid = segments[i].protected;
210
211 #ifdef DEBUG
212         printf("Mapping: addr: 0x%08x, old: 0x%08x, new: 0x%08x\n",
213                addr, segments[i].valid, nvalid);
214 #endif
215
216         if (mmap(segments[i].valid, nvalid - segments[i].valid,
217                  OS_VM_PROT_ALL, MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, -1,
218                  0) == (os_vm_address_t) - 1) {
219             perror("mmap");
220             printf("segments[i].base: 0x%X\n", segments[i].base);
221             printf("segments[i].len: 0x%X\n", segments[i].len);
222             printf("segments[i].valid: 0x%X\n", segments[i].valid);
223             printf("segments[i].protected: 0x%X\n", segments[i].protected);
224             printf("nvalid: 0x%X\n", nvalid);
225             printf("nvalid-segments[i].valid: 0x%X\n",
226                    nvalid - segments[i].valid);
227             assert(FALSE);
228         }
229         segments[i].valid = nvalid;
230     }
231 }
232
233 void
234 sigbus_handler(int signal, int code, struct sigcontext *context)
235 {
236 #ifdef DEBUG
237     printf("Bus Error at 0x%X\n", context->sc_sl.sl_ss.ss_cr21);
238 #endif
239
240     if (!interrupt_maybe_gc(signal, code, context))
241         interrupt_handle_now(signal, code, context);
242 }
243
244 void
245 os_install_interrupt_handlers(void)
246 {
247     interrupt_install_low_level_handler(SIGSEGV, segv_handler);
248     interrupt_install_low_level_handler(SIGBUS, sigbus_handler);
249 }
250
251 void
252 os_zero(os_vm_address_t addr, os_vm_size_t length)
253 {
254     os_vm_address_t block_start;
255     os_vm_size_t block_size;
256     int i;
257
258 #ifdef PRINTNOISE
259     fprintf(stderr, "os_zero: addr: 0x%08x, len: 0x%08x, end: 0x%X\n", addr,
260             length, addr + length);
261 #endif
262
263     block_start = os_round_up_to_page(addr);
264
265     length -= block_start - addr;
266     block_size = os_trunc_size_to_page(length);
267
268     if (block_start > addr)
269         memset((char *) addr, 0, block_start - addr);
270     if (block_size < length)
271         assert(FALSE);
272
273     if (block_size != 0) {
274         /* Now deallocate and allocate the block so that it */
275         /* faults in  zero-filled. */
276
277         for (i = 0; i < MAX_SEGMENTS; i++)
278             if (segments[i].base <= block_start &&
279                 block_start < segments[i].base + segments[i].len)
280                 break;
281         assert(i != MAX_SEGMENTS);
282         assert(block_start + block_size == segments[i].base + segments[i].len);
283
284         if (segments[i].valid > block_start) {
285             if (munmap(block_start, segments[i].valid - block_start) == -1) {
286                 perror("munmap");
287                 return;
288             }
289             segments[i].valid = block_start;
290         }
291     }
292 }
293
294 os_vm_address_t os_allocate(os_vm_size_t len)
295 {
296     return (os_vm_address_t) malloc(len);
297 }
298
299 os_vm_address_t os_allocate_at(os_vm_address_t addr, os_vm_size_t len)
300 {
301     return os_validate(addr, len);
302 }
303
304 void
305 os_deallocate(os_vm_address_t addr, os_vm_size_t len)
306 {
307     free(addr);
308 }
309
310 os_vm_address_t
311 os_reallocate(os_vm_address_t addr, os_vm_size_t old_len, os_vm_size_t len)
312 {
313     addr = (os_vm_address_t) realloc(addr, len);
314     assert(addr != NULL);
315     return addr;
316 }
317
318 int
319 getrusage(int who, struct rusage *rusage)
320 {
321     static long ticks_per_sec = 0;
322     static long usec_per_tick = 0;
323     struct tms buf;
324     clock_t uticks, sticks;
325
326     memset(rusage, 0, sizeof(struct rusage));
327
328     if (ticks_per_sec == 0) {
329         ticks_per_sec = sysconf(_SC_CLK_TCK);
330         usec_per_tick = 1000000 / ticks_per_sec;
331     }
332
333     if (times(&buf) == -1)
334         return -1;
335
336     if (who == RUSAGE_SELF) {
337         uticks = buf.tms_utime;
338         sticks = buf.tms_stime;
339     } else if (who == RUSAGE_CHILDREN) {
340         uticks = buf.tms_utime;
341         sticks = buf.tms_stime;
342     } else {
343         errno = EINVAL;
344         return -1;
345     }
346
347     rusage->ru_utime.tv_sec = uticks / ticks_per_sec;
348     rusage->ru_utime.tv_usec = (uticks % ticks_per_sec) * usec_per_tick;
349     rusage->ru_stime.tv_sec = sticks / ticks_per_sec;
350     rusage->ru_stime.tv_usec = (sticks % ticks_per_sec) * usec_per_tick;
351
352     return 0;
353 }
354
355 int
356 getdtablesize(void)
357 {
358     struct rlimit rlp;
359
360     assert(getrlimit(RLIMIT_NOFILE, &rlp) == 0);
361     return rlp.rlim_cur;
362 }
363
364 unsigned long
365 gethostid(void)
366 {
367     char hostname[256];
368     struct hostent *hostent;
369     static unsigned long addr = NULL;
370
371     if (addr)
372         return addr;
373
374     if (gethostname(hostname, sizeof(hostname)) == -1) {
375         perror("gethostname");
376         return 0;
377     }
378
379     hostent = gethostbyname(hostname);
380     if (hostent == NULL) {
381         perror("gethostbyname");
382         return 0;
383     }
384
385     addr = ((unsigned char *) (hostent->h_addr))[0] << 24 |
386         ((unsigned char *) (hostent->h_addr))[1] << 16 |
387         ((unsigned char *) (hostent->h_addr))[2] << 8 |
388         ((unsigned char *) (hostent->h_addr))[3];
389
390     return addr;
391 }
392
393 int
394 getpagesize(void)
395 {
396     return os_vm_page_size;
397 }