fix ctime_r problem on Solaris (I hope)
[ghc-hetmet.git] / rts / RtsUtils.c
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team, 1998-2004
4  *
5  * General utility functions used in the RTS.
6  *
7  * ---------------------------------------------------------------------------*/
8
9 /* gettimeofday isn't POSIX */
10 /* #include "PosixSource.h" */
11
12 #include "Rts.h"
13 #include "RtsAPI.h"
14 #include "RtsFlags.h"
15 #include "RtsUtils.h"
16 #include "Ticky.h"
17
18 #ifdef HAVE_TIME_H
19 #ifdef solaris2_HOST_OS
20 // Solaris requires this to get access to the POSIX ctime_r()
21 #define _POSIX_PTHREAD_SEMANTICS
22 #endif
23 #include <time.h>
24 #ifdef solaris2_HOST_OS
25 #undef _POSIX_PTHREAD_SEMANTICS
26 #endif
27 #endif
28
29 #ifdef HAVE_FCNTL_H
30 #include <fcntl.h>
31 #endif
32
33 #ifdef HAVE_GETTIMEOFDAY
34 #include <sys/time.h>
35 #endif
36
37 #include <stdlib.h>
38 #include <string.h>
39 #include <stdarg.h>
40 #include <stdio.h>
41
42 #ifdef HAVE_SIGNAL_H
43 #include <signal.h>
44 #endif
45
46 #if defined(THREADED_RTS) && defined(openbsd_HOST_OS) && defined(HAVE_PTHREAD_H)
47 #include <pthread.h>
48 #endif
49
50 #if defined(openbsd_HOST_OS) || defined(linux_HOST_OS) || defined(darwin_HOST_OS)
51 #include <unistd.h>
52 #include <sys/types.h>
53 #include <sys/mman.h>
54
55 /* no C99 header stdint.h on OpenBSD? */
56 #if defined(openbsd_HOST_OS)
57 typedef unsigned long my_uintptr_t;
58 #else
59 #include <stdint.h>
60 typedef uintptr_t my_uintptr_t;
61 #endif
62 #endif
63
64 #if defined(_WIN32)
65 #include <windows.h>
66 #endif
67
68 /* -----------------------------------------------------------------------------
69    Result-checking malloc wrappers.
70    -------------------------------------------------------------------------- */
71
72 void *
73 stgMallocBytes (int n, char *msg)
74 {
75     char *space;
76
77     if ((space = (char *) malloc((size_t) n)) == NULL) {
78       /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
79       MallocFailHook((W_) n, msg); /*msg*/
80       stg_exit(EXIT_INTERNAL_ERROR);
81     }
82     return space;
83 }
84
85 void *
86 stgReallocBytes (void *p, int n, char *msg)
87 {
88     char *space;
89
90     if ((space = (char *) realloc(p, (size_t) n)) == NULL) {
91       /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
92       MallocFailHook((W_) n, msg); /*msg*/
93       stg_exit(EXIT_INTERNAL_ERROR);
94     }
95     return space;
96 }
97
98 void *
99 stgCallocBytes (int n, int m, char *msg)
100 {
101     char *space;
102
103     if ((space = (char *) calloc((size_t) n, (size_t) m)) == NULL) {
104       /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
105       MallocFailHook((W_) n*m, msg); /*msg*/
106       stg_exit(EXIT_INTERNAL_ERROR);
107     }
108     return space;
109 }
110
111 /* To simplify changing the underlying allocator used
112  * by stgMallocBytes(), provide stgFree() as well.
113  */
114 void
115 stgFree(void* p)
116 {
117   free(p);
118 }
119
120 /* -----------------------------------------------------------------------------
121    Stack overflow
122    
123    Not sure if this belongs here.
124    -------------------------------------------------------------------------- */
125
126 void
127 stackOverflow(void)
128 {
129   StackOverflowHook(RtsFlags.GcFlags.maxStkSize * sizeof(W_));
130
131 #if defined(TICKY_TICKY)
132   if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo();
133 #endif
134 }
135
136 void
137 heapOverflow(void)
138 {
139   /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
140   OutOfHeapHook(0/*unknown request size*/, 
141                 RtsFlags.GcFlags.maxHeapSize * BLOCK_SIZE);
142   
143 #if defined(TICKY_TICKY)
144   if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo();
145 #endif
146
147   stg_exit(EXIT_HEAPOVERFLOW);
148 }
149
150 /* -----------------------------------------------------------------------------
151    Out-of-line strlen.
152
153    Used in addr2Integer because the C compiler on x86 chokes on
154    strlen, trying to inline it with not enough registers available.
155    -------------------------------------------------------------------------- */
156
157 nat stg_strlen(char *s)
158 {
159    char *p = s;
160
161    while (*p) p++;
162    return p-s;
163 }
164
165
166 /* -----------------------------------------------------------------------------
167    genSym stuff, used by GHC itself for its splitting unique supply.
168
169    ToDo: put this somewhere sensible.
170    -------------------------------------------------------------------------  */
171
172 static I_ __GenSymCounter = 0;
173
174 I_
175 genSymZh(void)
176 {
177     return(__GenSymCounter++);
178 }
179 I_
180 resetGenSymZh(void) /* it's your funeral */
181 {
182     __GenSymCounter=0;
183     return(__GenSymCounter);
184 }
185
186 /* -----------------------------------------------------------------------------
187    Get the current time as a string.  Used in profiling reports.
188    -------------------------------------------------------------------------- */
189
190 #if defined(PROFILING) || defined(DEBUG) || defined(PAR) || defined(GRAN)
191 char *
192 time_str(void)
193 {
194     static time_t now = 0;
195     static char nowstr[26];
196
197     if (now == 0) {
198         time(&now);
199 #if HAVE_CTIME_R
200         ctime_r(&now, nowstr);
201 #else
202         strcpy(nowstr, ctime(&now));
203 #endif
204         memmove(nowstr+16,nowstr+19,7);
205         nowstr[21] = '\0';  // removes the \n
206     }
207     return nowstr;
208 }
209 #endif
210
211 /* -----------------------------------------------------------------------------
212  * Reset a file handle to blocking mode.  We do this for the standard
213  * file descriptors before exiting, because the shell doesn't always
214  * clean up for us.
215  * -------------------------------------------------------------------------- */
216
217 #if !defined(mingw32_HOST_OS)
218 void
219 resetNonBlockingFd(int fd)
220 {
221   long fd_flags;
222
223   /* clear the non-blocking flag on this file descriptor */
224   fd_flags = fcntl(fd, F_GETFL);
225   if (fd_flags & O_NONBLOCK) {
226     fcntl(fd, F_SETFL, fd_flags & ~O_NONBLOCK);
227   }
228 }
229
230 void
231 setNonBlockingFd(int fd)
232 {
233   long fd_flags;
234
235   /* clear the non-blocking flag on this file descriptor */
236   fd_flags = fcntl(fd, F_GETFL);
237   if (!(fd_flags & O_NONBLOCK)) {
238     fcntl(fd, F_SETFL, fd_flags | O_NONBLOCK);
239   }
240 }
241 #else
242 /* Stub defns -- async / non-blocking IO is not done 
243  * via O_NONBLOCK and select() under Win32. 
244  */
245 void resetNonBlockingFd(int fd STG_UNUSED) {}
246 void setNonBlockingFd(int fd STG_UNUSED) {}
247 #endif
248
249 #ifdef PAR
250 static ullong startTime = 0;
251
252 /* used in a parallel setup */
253 ullong
254 msTime(void)
255 {
256 # if defined(HAVE_GETCLOCK) && !defined(alpha_HOST_ARCH) && !defined(hppa1_1_HOST_ARCH)
257     struct timespec tv;
258
259     if (getclock(TIMEOFDAY, &tv) != 0) {
260         fflush(stdout);
261         fprintf(stderr, "Clock failed\n");
262         stg_exit(EXIT_FAILURE);
263     }
264     return tv.tv_sec * LL(1000) + tv.tv_nsec / LL(1000000) - startTime;
265 # elif HAVE_GETTIMEOFDAY && !defined(alpha_HOST_ARCH)
266     struct timeval tv;
267  
268     if (gettimeofday(&tv, NULL) != 0) {
269         fflush(stdout);
270         fprintf(stderr, "Clock failed\n");
271         stg_exit(EXIT_FAILURE);
272     }
273     return tv.tv_sec * LL(1000) + tv.tv_usec / LL(1000) - startTime;
274 # else
275     time_t t;
276     if ((t = time(NULL)) == (time_t) -1) {
277         fflush(stdout);
278         fprintf(stderr, "Clock failed\n");
279         stg_exit(EXIT_FAILURE);
280     }
281     return t * LL(1000) - startTime;
282 # endif
283 }
284 #endif /* PAR */
285
286 /* -----------------------------------------------------------------------------
287    Print large numbers, with punctuation.
288    -------------------------------------------------------------------------- */
289
290 char *
291 ullong_format_string(ullong x, char *s, rtsBool with_commas)
292 {
293     if (x < (ullong)1000) 
294         sprintf(s, "%lu", (lnat)x);
295     else if (x < (ullong)1000000)
296         sprintf(s, (with_commas) ? "%lu,%3.3lu" : "%lu%3.3lu",
297                 (lnat)((x)/(ullong)1000),
298                 (lnat)((x)%(ullong)1000));
299     else if (x < (ullong)1000000000)
300         sprintf(s, (with_commas) ? "%lu,%3.3lu,%3.3lu" :  "%lu%3.3lu%3.3lu",
301                 (lnat)((x)/(ullong)1000000),
302                 (lnat)((x)/(ullong)1000%(ullong)1000),
303                 (lnat)((x)%(ullong)1000));
304     else
305         sprintf(s, (with_commas) ? "%lu,%3.3lu,%3.3lu,%3.3lu" : "%lu%3.3lu%3.3lu%3.3lu",
306                 (lnat)((x)/(ullong)1000000000),
307                 (lnat)((x)/(ullong)1000000%(ullong)1000),
308                 (lnat)((x)/(ullong)1000%(ullong)1000), 
309                 (lnat)((x)%(ullong)1000));
310     return s;
311 }
312
313
314 // Can be used as a breakpoint to set on every heap check failure.
315 #ifdef DEBUG
316 void
317 heapCheckFail( void )
318 {
319 }
320 #endif
321
322 /* 
323  * It seems that pthreads and signals interact oddly in OpenBSD & FreeBSD
324  * pthreads (and possibly others). When linking with -lpthreads, we
325  * have to use pthread_kill to send blockable signals. So use that
326  * when we have a threaded rts. So System.Posix.Signals will call
327  * genericRaise(), rather than raise(3).
328  */
329 int genericRaise(int sig) {
330 #if defined(THREADED_RTS) && (defined(openbsd_HOST_OS) || defined(freebsd_HOST_OS))
331         return pthread_kill(pthread_self(), sig);
332 #else
333         return raise(sig);
334 #endif
335 }
336
337 /* -----------------------------------------------------------------------------
338    Allocating executable memory
339    -------------------------------------------------------------------------- */
340
341 /* Heavily arch-specific, I'm afraid.. */
342
343 /*
344  * Allocate len bytes which are readable, writable, and executable.
345  *
346  * ToDo: If this turns out to be a performance bottleneck, one could
347  * e.g. cache the last VirtualProtect/mprotect-ed region and do
348  * nothing in case of a cache hit.
349  */
350 void*
351 stgMallocBytesRWX(int len)
352 {
353   void *addr = stgMallocBytes(len, "mallocBytesRWX");
354 #if defined(i386_HOST_ARCH) && defined(_WIN32)
355   /* This could be necessary for processors which distinguish between READ and
356      EXECUTE memory accesses, e.g. Itaniums. */
357   DWORD dwOldProtect = 0;
358   if (VirtualProtect (addr, len, PAGE_EXECUTE_READWRITE, &dwOldProtect) == 0) {
359     barf("mallocBytesRWX: failed to protect 0x%p; error=%lu; old protection: %lu\n",
360          addr, (unsigned long)GetLastError(), (unsigned long)dwOldProtect);
361   }
362 #elif defined(openbsd_HOST_OS) || defined(linux_HOST_OS) || defined(darwin_HOST_OS)
363   /* malloced memory isn't executable by default on OpenBSD */
364   my_uintptr_t pageSize         = sysconf(_SC_PAGESIZE);
365   my_uintptr_t mask             = ~(pageSize - 1);
366   my_uintptr_t startOfFirstPage = ((my_uintptr_t)addr          ) & mask;
367   my_uintptr_t startOfLastPage  = ((my_uintptr_t)addr + len - 1) & mask;
368   my_uintptr_t size             = startOfLastPage - startOfFirstPage + pageSize;
369   if (mprotect((void*)startOfFirstPage, (size_t)size, PROT_EXEC | PROT_READ | PROT_WRITE) != 0) {
370     barf("mallocBytesRWX: failed to protect 0x%p\n", addr);
371   }
372 #endif
373   return addr;
374 }