When debugging, have the allocator help us a bit
[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    Debugging allocator
49    -------------------------------------------------------------------------- */
50
51 #if defined(DEBUG)
52
53 typedef struct Allocated_ {
54     void *addr;
55     size_t len;
56     struct Allocated_ *next;
57 } Allocated;
58
59 static Allocated *allocs = NULL;
60
61 #ifdef THREADED_RTS
62 static Mutex allocator_mutex;
63 #endif
64
65 void
66 initAllocator(void)
67 {
68     Allocated *a;
69     size_t alloc_size;
70
71 #ifdef THREADED_RTS
72     initMutex(&allocator_mutex);
73 #endif
74     alloc_size = sizeof(Allocated);
75     if ((a = (Allocated *) malloc(alloc_size)) == NULL) {
76       /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
77       MallocFailHook((W_) alloc_size, "initialising debugging allocator");
78       stg_exit(EXIT_INTERNAL_ERROR);
79     }
80     a->addr = NULL;
81     a->len = 0;
82     a->next = NULL;
83     allocs = a;
84 }
85
86 void
87 shutdownAllocator(void)
88 {
89 #ifdef THREADED_RTS
90     closeMutex(&allocator_mutex);
91 #endif
92 }
93
94 static void allocate(void *addr, size_t len) {
95     Allocated *a;
96     size_t alloc_size;
97
98     alloc_size = sizeof(Allocated);
99     if ((a = (Allocated *) malloc(alloc_size)) == NULL) {
100       /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
101       MallocFailHook((W_) alloc_size, "creating info for debugging allocator");
102       stg_exit(EXIT_INTERNAL_ERROR);
103     }
104     a->addr = addr;
105     a->len = len;
106     ACQUIRE_LOCK(&allocator_mutex);
107     a->next = allocs->next;
108     allocs->next = a;
109     RELEASE_LOCK(&allocator_mutex);
110 }
111
112 static void deallocate(void *addr) {
113     Allocated *prev, *a;
114
115     if (addr == NULL) {
116         barf("Freeing NULL!");
117     }
118
119     ACQUIRE_LOCK(&allocator_mutex);
120     prev = allocs;
121     a = prev->next;
122     while (a != NULL) {
123         if (a->addr == addr) {
124             prev->next = a->next;
125             memset(addr, 0xaa, a->len);
126             free(a);
127             RELEASE_LOCK(&allocator_mutex);
128             return;
129         }
130         prev = a;
131         a = a->next;
132     }
133     barf("Freeing non-allocated memory at %p", addr);
134 }
135 #endif
136
137 /* -----------------------------------------------------------------------------
138    Result-checking malloc wrappers.
139    -------------------------------------------------------------------------- */
140
141 void *
142 stgMallocBytes (int n, char *msg)
143 {
144     char *space;
145     size_t n2;
146
147     n2 = (size_t) n;
148     if ((space = (char *) malloc(n2)) == NULL) {
149       /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
150       MallocFailHook((W_) n, msg); /*msg*/
151       stg_exit(EXIT_INTERNAL_ERROR);
152     }
153 #if defined(DEBUG)
154     allocate(space, n2);
155 #endif
156     return space;
157 }
158
159 void *
160 stgReallocBytes (void *p, int n, char *msg)
161 {
162     char *space;
163     size_t n2;
164
165     n2 = (size_t) n;
166     if ((space = (char *) realloc(p, (size_t) n2)) == NULL) {
167       /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
168       MallocFailHook((W_) n, msg); /*msg*/
169       stg_exit(EXIT_INTERNAL_ERROR);
170     }
171 #if defined(DEBUG)
172     deallocate(p);
173     allocate(space, n2);
174 #endif
175     return space;
176 }
177
178 void *
179 stgCallocBytes (int n, int m, char *msg)
180 {
181     char *space;
182
183     if ((space = (char *) calloc((size_t) n, (size_t) m)) == NULL) {
184       /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
185       MallocFailHook((W_) n*m, msg); /*msg*/
186       stg_exit(EXIT_INTERNAL_ERROR);
187     }
188 #if defined(DEBUG)
189     allocate(space, (size_t) n * (size_t) m);
190 #endif
191     return space;
192 }
193
194 /* To simplify changing the underlying allocator used
195  * by stgMallocBytes(), provide stgFree() as well.
196  */
197 void
198 stgFree(void* p)
199 {
200 #if defined(DEBUG)
201   deallocate(p);
202 #endif
203   free(p);
204 }
205
206 /* -----------------------------------------------------------------------------
207    Stack overflow
208    
209    Not sure if this belongs here.
210    -------------------------------------------------------------------------- */
211
212 void
213 stackOverflow(void)
214 {
215   StackOverflowHook(RtsFlags.GcFlags.maxStkSize * sizeof(W_));
216
217 #if defined(TICKY_TICKY)
218   if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo();
219 #endif
220 }
221
222 void
223 heapOverflow(void)
224 {
225   /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
226   OutOfHeapHook(0/*unknown request size*/, 
227                 RtsFlags.GcFlags.maxHeapSize * BLOCK_SIZE);
228   
229 #if defined(TICKY_TICKY)
230   if (RtsFlags.TickyFlags.showTickyStats) PrintTickyInfo();
231 #endif
232
233   stg_exit(EXIT_HEAPOVERFLOW);
234 }
235
236 /* -----------------------------------------------------------------------------
237    Out-of-line strlen.
238
239    Used in addr2Integer because the C compiler on x86 chokes on
240    strlen, trying to inline it with not enough registers available.
241    -------------------------------------------------------------------------- */
242
243 nat stg_strlen(char *s)
244 {
245    char *p = s;
246
247    while (*p) p++;
248    return p-s;
249 }
250
251
252 /* -----------------------------------------------------------------------------
253    genSym stuff, used by GHC itself for its splitting unique supply.
254
255    ToDo: put this somewhere sensible.
256    -------------------------------------------------------------------------  */
257
258 static I_ __GenSymCounter = 0;
259
260 I_
261 genSymZh(void)
262 {
263     return(__GenSymCounter++);
264 }
265 I_
266 resetGenSymZh(void) /* it's your funeral */
267 {
268     __GenSymCounter=0;
269     return(__GenSymCounter);
270 }
271
272 /* -----------------------------------------------------------------------------
273    Get the current time as a string.  Used in profiling reports.
274    -------------------------------------------------------------------------- */
275
276 #if defined(PROFILING) || defined(DEBUG) || defined(PAR) || defined(GRAN)
277 char *
278 time_str(void)
279 {
280     static time_t now = 0;
281     static char nowstr[26];
282
283     if (now == 0) {
284         time(&now);
285 #if HAVE_CTIME_R
286         ctime_r(&now, nowstr);
287 #else
288         strcpy(nowstr, ctime(&now));
289 #endif
290         memmove(nowstr+16,nowstr+19,7);
291         nowstr[21] = '\0';  // removes the \n
292     }
293     return nowstr;
294 }
295 #endif
296
297 /* -----------------------------------------------------------------------------
298  * Reset a file handle to blocking mode.  We do this for the standard
299  * file descriptors before exiting, because the shell doesn't always
300  * clean up for us.
301  * -------------------------------------------------------------------------- */
302
303 #if !defined(mingw32_HOST_OS)
304 void
305 resetNonBlockingFd(int fd)
306 {
307   long fd_flags;
308
309   /* clear the non-blocking flag on this file descriptor */
310   fd_flags = fcntl(fd, F_GETFL);
311   if (fd_flags & O_NONBLOCK) {
312     fcntl(fd, F_SETFL, fd_flags & ~O_NONBLOCK);
313   }
314 }
315
316 void
317 setNonBlockingFd(int fd)
318 {
319   long fd_flags;
320
321   /* clear the non-blocking flag on this file descriptor */
322   fd_flags = fcntl(fd, F_GETFL);
323   if (!(fd_flags & O_NONBLOCK)) {
324     fcntl(fd, F_SETFL, fd_flags | O_NONBLOCK);
325   }
326 }
327 #else
328 /* Stub defns -- async / non-blocking IO is not done 
329  * via O_NONBLOCK and select() under Win32. 
330  */
331 void resetNonBlockingFd(int fd STG_UNUSED) {}
332 void setNonBlockingFd(int fd STG_UNUSED) {}
333 #endif
334
335 #ifdef PAR
336 static ullong startTime = 0;
337
338 /* used in a parallel setup */
339 ullong
340 msTime(void)
341 {
342 # if defined(HAVE_GETCLOCK) && !defined(alpha_HOST_ARCH) && !defined(hppa1_1_HOST_ARCH)
343     struct timespec tv;
344
345     if (getclock(TIMEOFDAY, &tv) != 0) {
346         fflush(stdout);
347         fprintf(stderr, "Clock failed\n");
348         stg_exit(EXIT_FAILURE);
349     }
350     return tv.tv_sec * LL(1000) + tv.tv_nsec / LL(1000000) - startTime;
351 # elif HAVE_GETTIMEOFDAY && !defined(alpha_HOST_ARCH)
352     struct timeval tv;
353  
354     if (gettimeofday(&tv, NULL) != 0) {
355         fflush(stdout);
356         fprintf(stderr, "Clock failed\n");
357         stg_exit(EXIT_FAILURE);
358     }
359     return tv.tv_sec * LL(1000) + tv.tv_usec / LL(1000) - startTime;
360 # else
361     time_t t;
362     if ((t = time(NULL)) == (time_t) -1) {
363         fflush(stdout);
364         fprintf(stderr, "Clock failed\n");
365         stg_exit(EXIT_FAILURE);
366     }
367     return t * LL(1000) - startTime;
368 # endif
369 }
370 #endif /* PAR */
371
372 /* -----------------------------------------------------------------------------
373    Print large numbers, with punctuation.
374    -------------------------------------------------------------------------- */
375
376 char *
377 ullong_format_string(ullong x, char *s, rtsBool with_commas)
378 {
379     if (x < (ullong)1000) 
380         sprintf(s, "%lu", (lnat)x);
381     else if (x < (ullong)1000000)
382         sprintf(s, (with_commas) ? "%lu,%3.3lu" : "%lu%3.3lu",
383                 (lnat)((x)/(ullong)1000),
384                 (lnat)((x)%(ullong)1000));
385     else if (x < (ullong)1000000000)
386         sprintf(s, (with_commas) ? "%lu,%3.3lu,%3.3lu" :  "%lu%3.3lu%3.3lu",
387                 (lnat)((x)/(ullong)1000000),
388                 (lnat)((x)/(ullong)1000%(ullong)1000),
389                 (lnat)((x)%(ullong)1000));
390     else
391         sprintf(s, (with_commas) ? "%lu,%3.3lu,%3.3lu,%3.3lu" : "%lu%3.3lu%3.3lu%3.3lu",
392                 (lnat)((x)/(ullong)1000000000),
393                 (lnat)((x)/(ullong)1000000%(ullong)1000),
394                 (lnat)((x)/(ullong)1000%(ullong)1000), 
395                 (lnat)((x)%(ullong)1000));
396     return s;
397 }
398
399
400 // Can be used as a breakpoint to set on every heap check failure.
401 #ifdef DEBUG
402 void
403 heapCheckFail( void )
404 {
405 }
406 #endif
407
408 /* 
409  * It seems that pthreads and signals interact oddly in OpenBSD & FreeBSD
410  * pthreads (and possibly others). When linking with -lpthreads, we
411  * have to use pthread_kill to send blockable signals. So use that
412  * when we have a threaded rts. So System.Posix.Signals will call
413  * genericRaise(), rather than raise(3).
414  */
415 int genericRaise(int sig) {
416 #if defined(THREADED_RTS) && (defined(openbsd_HOST_OS) || defined(freebsd_HOST_OS))
417         return pthread_kill(pthread_self(), sig);
418 #else
419         return raise(sig);
420 #endif
421 }