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