replace stgMallocBytesRWX() with our own allocator
[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 #include "PosixSource.h"
10
11 #include "Rts.h"
12 #include "RtsAPI.h"
13 #include "RtsFlags.h"
14 #include "RtsUtils.h"
15 #include "Ticky.h"
16
17 #ifdef HAVE_TIME_H
18 #include <time.h>
19 #endif
20
21 #ifdef HAVE_FCNTL_H
22 #include <fcntl.h>
23 #endif
24
25 #ifdef HAVE_GETTIMEOFDAY
26 #include <sys/time.h>
27 #endif
28
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdarg.h>
32 #include <stdio.h>
33
34 #ifdef HAVE_SIGNAL_H
35 #include <signal.h>
36 #endif
37
38 #if defined(THREADED_RTS) && defined(openbsd_HOST_OS) && defined(HAVE_PTHREAD_H)
39 #include <pthread.h>
40 #endif
41
42
43 #if defined(_WIN32)
44 #include <windows.h>
45 #endif
46
47 /* -----------------------------------------------------------------------------
48    Result-checking malloc wrappers.
49    -------------------------------------------------------------------------- */
50
51 void *
52 stgMallocBytes (int n, char *msg)
53 {
54     char *space;
55
56     if ((space = (char *) malloc((size_t) n)) == NULL) {
57       /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
58       MallocFailHook((W_) n, msg); /*msg*/
59       stg_exit(EXIT_INTERNAL_ERROR);
60     }
61     return space;
62 }
63
64 void *
65 stgReallocBytes (void *p, int n, char *msg)
66 {
67     char *space;
68
69     if ((space = (char *) realloc(p, (size_t) n)) == NULL) {
70       /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
71       MallocFailHook((W_) n, msg); /*msg*/
72       stg_exit(EXIT_INTERNAL_ERROR);
73     }
74     return space;
75 }
76
77 void *
78 stgCallocBytes (int n, int m, char *msg)
79 {
80     char *space;
81
82     if ((space = (char *) calloc((size_t) n, (size_t) m)) == NULL) {
83       /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
84       MallocFailHook((W_) n*m, msg); /*msg*/
85       stg_exit(EXIT_INTERNAL_ERROR);
86     }
87     return space;
88 }
89
90 /* To simplify changing the underlying allocator used
91  * by stgMallocBytes(), provide stgFree() as well.
92  */
93 void
94 stgFree(void* p)
95 {
96   free(p);
97 }
98
99 /* -----------------------------------------------------------------------------
100    Stack overflow
101    
102    Not sure if this belongs here.
103    -------------------------------------------------------------------------- */
104
105 void
106 stackOverflow(void)
107 {
108   StackOverflowHook(RtsFlags.GcFlags.maxStkSize * sizeof(W_));
109
110 #if defined(TICKY_TICKY)
111   if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo();
112 #endif
113 }
114
115 void
116 heapOverflow(void)
117 {
118   /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
119   OutOfHeapHook(0/*unknown request size*/, 
120                 RtsFlags.GcFlags.maxHeapSize * BLOCK_SIZE);
121   
122 #if defined(TICKY_TICKY)
123   if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo();
124 #endif
125
126   stg_exit(EXIT_HEAPOVERFLOW);
127 }
128
129 /* -----------------------------------------------------------------------------
130    Out-of-line strlen.
131
132    Used in addr2Integer because the C compiler on x86 chokes on
133    strlen, trying to inline it with not enough registers available.
134    -------------------------------------------------------------------------- */
135
136 nat stg_strlen(char *s)
137 {
138    char *p = s;
139
140    while (*p) p++;
141    return p-s;
142 }
143
144
145 /* -----------------------------------------------------------------------------
146    genSym stuff, used by GHC itself for its splitting unique supply.
147
148    ToDo: put this somewhere sensible.
149    -------------------------------------------------------------------------  */
150
151 static I_ __GenSymCounter = 0;
152
153 I_
154 genSymZh(void)
155 {
156     return(__GenSymCounter++);
157 }
158 I_
159 resetGenSymZh(void) /* it's your funeral */
160 {
161     __GenSymCounter=0;
162     return(__GenSymCounter);
163 }
164
165 /* -----------------------------------------------------------------------------
166    Get the current time as a string.  Used in profiling reports.
167    -------------------------------------------------------------------------- */
168
169 #if defined(PROFILING) || defined(DEBUG) || defined(PAR) || defined(GRAN)
170 char *
171 time_str(void)
172 {
173     static time_t now = 0;
174     static char nowstr[26];
175
176     if (now == 0) {
177         time(&now);
178 #if HAVE_CTIME_R
179         ctime_r(&now, nowstr);
180 #else
181         strcpy(nowstr, ctime(&now));
182 #endif
183         memmove(nowstr+16,nowstr+19,7);
184         nowstr[21] = '\0';  // removes the \n
185     }
186     return nowstr;
187 }
188 #endif
189
190 /* -----------------------------------------------------------------------------
191  * Reset a file handle to blocking mode.  We do this for the standard
192  * file descriptors before exiting, because the shell doesn't always
193  * clean up for us.
194  * -------------------------------------------------------------------------- */
195
196 #if !defined(mingw32_HOST_OS)
197 void
198 resetNonBlockingFd(int fd)
199 {
200   long fd_flags;
201
202   /* clear the non-blocking flag on this file descriptor */
203   fd_flags = fcntl(fd, F_GETFL);
204   if (fd_flags & O_NONBLOCK) {
205     fcntl(fd, F_SETFL, fd_flags & ~O_NONBLOCK);
206   }
207 }
208
209 void
210 setNonBlockingFd(int fd)
211 {
212   long fd_flags;
213
214   /* clear the non-blocking flag on this file descriptor */
215   fd_flags = fcntl(fd, F_GETFL);
216   if (!(fd_flags & O_NONBLOCK)) {
217     fcntl(fd, F_SETFL, fd_flags | O_NONBLOCK);
218   }
219 }
220 #else
221 /* Stub defns -- async / non-blocking IO is not done 
222  * via O_NONBLOCK and select() under Win32. 
223  */
224 void resetNonBlockingFd(int fd STG_UNUSED) {}
225 void setNonBlockingFd(int fd STG_UNUSED) {}
226 #endif
227
228 #ifdef PAR
229 static ullong startTime = 0;
230
231 /* used in a parallel setup */
232 ullong
233 msTime(void)
234 {
235 # if defined(HAVE_GETCLOCK) && !defined(alpha_HOST_ARCH) && !defined(hppa1_1_HOST_ARCH)
236     struct timespec tv;
237
238     if (getclock(TIMEOFDAY, &tv) != 0) {
239         fflush(stdout);
240         fprintf(stderr, "Clock failed\n");
241         stg_exit(EXIT_FAILURE);
242     }
243     return tv.tv_sec * LL(1000) + tv.tv_nsec / LL(1000000) - startTime;
244 # elif HAVE_GETTIMEOFDAY && !defined(alpha_HOST_ARCH)
245     struct timeval tv;
246  
247     if (gettimeofday(&tv, NULL) != 0) {
248         fflush(stdout);
249         fprintf(stderr, "Clock failed\n");
250         stg_exit(EXIT_FAILURE);
251     }
252     return tv.tv_sec * LL(1000) + tv.tv_usec / LL(1000) - startTime;
253 # else
254     time_t t;
255     if ((t = time(NULL)) == (time_t) -1) {
256         fflush(stdout);
257         fprintf(stderr, "Clock failed\n");
258         stg_exit(EXIT_FAILURE);
259     }
260     return t * LL(1000) - startTime;
261 # endif
262 }
263 #endif /* PAR */
264
265 /* -----------------------------------------------------------------------------
266    Print large numbers, with punctuation.
267    -------------------------------------------------------------------------- */
268
269 char *
270 ullong_format_string(ullong x, char *s, rtsBool with_commas)
271 {
272     if (x < (ullong)1000) 
273         sprintf(s, "%lu", (lnat)x);
274     else if (x < (ullong)1000000)
275         sprintf(s, (with_commas) ? "%lu,%3.3lu" : "%lu%3.3lu",
276                 (lnat)((x)/(ullong)1000),
277                 (lnat)((x)%(ullong)1000));
278     else if (x < (ullong)1000000000)
279         sprintf(s, (with_commas) ? "%lu,%3.3lu,%3.3lu" :  "%lu%3.3lu%3.3lu",
280                 (lnat)((x)/(ullong)1000000),
281                 (lnat)((x)/(ullong)1000%(ullong)1000),
282                 (lnat)((x)%(ullong)1000));
283     else
284         sprintf(s, (with_commas) ? "%lu,%3.3lu,%3.3lu,%3.3lu" : "%lu%3.3lu%3.3lu%3.3lu",
285                 (lnat)((x)/(ullong)1000000000),
286                 (lnat)((x)/(ullong)1000000%(ullong)1000),
287                 (lnat)((x)/(ullong)1000%(ullong)1000), 
288                 (lnat)((x)%(ullong)1000));
289     return s;
290 }
291
292
293 // Can be used as a breakpoint to set on every heap check failure.
294 #ifdef DEBUG
295 void
296 heapCheckFail( void )
297 {
298 }
299 #endif
300
301 /* 
302  * It seems that pthreads and signals interact oddly in OpenBSD & FreeBSD
303  * pthreads (and possibly others). When linking with -lpthreads, we
304  * have to use pthread_kill to send blockable signals. So use that
305  * when we have a threaded rts. So System.Posix.Signals will call
306  * genericRaise(), rather than raise(3).
307  */
308 int genericRaise(int sig) {
309 #if defined(THREADED_RTS) && (defined(openbsd_HOST_OS) || defined(freebsd_HOST_OS))
310         return pthread_kill(pthread_self(), sig);
311 #else
312         return raise(sig);
313 #endif
314 }