WRAPPER(int , munmap, void *start, size_t length) { DECLARE(int, munmap, void *, size_t); int result; BEGIN_PROTECT (munmap, start, length); result = CALL_REAL (munmap, start, length); /* VERBOSE_TRACE ("munmap (%08lx, %08lx, ...) => %08lx\n", (uintptr_t) start, (uintptr_t) length, (uintptr_t) result); */ if (result == 0) { /* Unregister each page as a heap object. */ size_t ps = getpagesize (); uintptr_t base = (uintptr_t) start & (~ (ps - 1)); /* page align */ uintptr_t offset; for (offset=0; offset<length; offset+=ps) __mf_unregister ((void *) CLAMPADD (base, offset), ps, __MF_TYPE_HEAP_I); } return result; }
int main () { #ifndef MAP_ANONYMOUS #define MAP_ANONYMOUS MAP_ANON #endif #ifdef HAVE_MMAP volatile unsigned char *p; unsigned num = getpagesize (); unsigned i; int rc; /* Get a bit of usable address space. We really want an 2**N+1-sized object, so the low/high addresses wrap when hashed into the lookup cache. So we will manually unregister the entire mmap, then re-register a slice. */ p = mmap (NULL, num, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); if (p == NULL) return 1; /* Now unregister it, as if munmap was called. But don't actually munmap, so we can write into the memory. */ __mf_unregister ((void *) p, num, __MF_TYPE_HEAP_I); /* Now register it under a slightly inflated, 2**N+1 size. */ __mf_register ((void *) p, num+1, __MF_TYPE_HEAP_I, "fake mmap registration"); /* Traverse array to ensure that entire lookup cache is made to point at it. */ for (i=0; i<num; i++) p[i] = 0; /* Unregister it. This should clear the entire lookup cache, even though hash(low) == hash (high) (and probably == 0) */ __mf_unregister ((void *) p, num+1, __MF_TYPE_HEAP_I); /* Now touch the middle portion of the ex-array. If the lookup cache was well and truly cleaned, then this access should trap. */ p[num/2] = 1; return 0; #else return 1; #endif }
static void __mf_pthread_cleanup (void *arg) { struct pthread_info *pi = arg; /* XXX: This unregistration is not safe on platforms where distinct threads share errno (or at least its virtual address). */ if (pi->thread_errno != NULL) __mf_unregister (pi->thread_errno, sizeof (int), __MF_TYPE_GUESS); /* XXX: Only detached threads should designate themselves as dead here. Non-detached threads are marked dead after their personalized pthread_join() call. */ pi->state = reentrant; pi->dead_p = 1; VERBOSE_TRACE ("thread pi %p exiting\n", pi); }
/* This wrapper is a little different, as it's called indirectly from __mf_fini also to clean up pending allocations. */ void * __mf_wrap_alloca_indirect (size_t c) { DECLARE (void *, malloc, size_t); DECLARE (void, free, void *); /* This struct, a linked list, tracks alloca'd objects. The newest object is at the head of the list. If we detect that we've popped a few levels of stack, then the listed objects are freed as needed. NB: The tracking struct is allocated with real_malloc; the user data with wrap_malloc. */ struct alloca_tracking { void *ptr; void *stack; struct alloca_tracking* next; }; static struct alloca_tracking *alloca_history = NULL; void *stack = __builtin_frame_address (0); void *result; struct alloca_tracking *track; TRACE ("%s\n", __PRETTY_FUNCTION__); VERBOSE_TRACE ("alloca stack level %p\n", (void *) stack); /* XXX: thread locking! */ /* Free any previously alloca'd blocks that belong to deeper-nested functions, which must therefore have exited by now. */ #define DEEPER_THAN < /* XXX: for x86; steal find_stack_direction() from libiberty/alloca.c */ while (alloca_history && ((uintptr_t) alloca_history->stack DEEPER_THAN (uintptr_t) stack)) { struct alloca_tracking *next = alloca_history->next; __mf_unregister (alloca_history->ptr, 0, __MF_TYPE_HEAP); BEGIN_MALLOC_PROTECT (); CALL_REAL (free, alloca_history->ptr); CALL_REAL (free, alloca_history); END_MALLOC_PROTECT (); alloca_history = next; } /* Allocate new block. */ result = NULL; if (LIKELY (c > 0)) /* alloca(0) causes no allocation. */ { BEGIN_MALLOC_PROTECT (); track = (struct alloca_tracking *) CALL_REAL (malloc, sizeof (struct alloca_tracking)); END_MALLOC_PROTECT (); if (LIKELY (track != NULL)) { BEGIN_MALLOC_PROTECT (); result = CALL_REAL (malloc, c); END_MALLOC_PROTECT (); if (UNLIKELY (result == NULL)) { BEGIN_MALLOC_PROTECT (); CALL_REAL (free, track); END_MALLOC_PROTECT (); /* Too bad. XXX: What about errno? */ } else { __mf_register (result, c, __MF_TYPE_HEAP, "alloca region"); track->ptr = result; track->stack = stack; track->next = alloca_history; alloca_history = track; } } } return result; }
WRAPPER(void, free, void *buf) { /* Use a circular queue to delay some number (__mf_opts.free_queue_length) of free()s. */ static void *free_queue [__MF_FREEQ_MAX]; static unsigned free_ptr = 0; static int freeq_initialized = 0; DECLARE(void, free, void *); if (UNLIKELY(buf == NULL)) return; BEGIN_PROTECT (free, buf); #if PIC /* Check whether the given buffer might have come from a __mf_0fn_malloc/calloc call that for whatever reason was not redirected back to __mf_0fn_free. If so, we just ignore the call. */ if (UNLIKELY((uintptr_t) buf >= (uintptr_t) __mf_0fn_bufs && (uintptr_t) buf < ((uintptr_t) __mf_0fn_bufs + sizeof(__mf_0fn_bufs)))) { VERBOSE_TRACE ("skipping free of boot (0fn) alloc buffer %p\n", buf); return; } #endif LOCKTH (); if (UNLIKELY(!freeq_initialized)) { memset (free_queue, 0, __MF_FREEQ_MAX * sizeof (void *)); freeq_initialized = 1; } UNLOCKTH (); __mf_unregister (buf, 0, __MF_TYPE_HEAP_I); /* NB: underlying region may have been __MF_TYPE_HEAP. */ if (UNLIKELY(__mf_opts.free_queue_length > 0)) { char *freeme = NULL; LOCKTH (); if (free_queue [free_ptr] != NULL) { freeme = free_queue [free_ptr]; freeme -= __mf_opts.crumple_zone; } free_queue [free_ptr] = buf; free_ptr = (free_ptr == (__mf_opts.free_queue_length-1) ? 0 : free_ptr + 1); UNLOCKTH (); if (freeme) { if (__mf_opts.trace_mf_calls) { VERBOSE_TRACE ("freeing deferred pointer %p (crumple %u)\n", (void *) freeme, __mf_opts.crumple_zone); } BEGIN_MALLOC_PROTECT (); CALL_REAL (free, freeme); END_MALLOC_PROTECT (); } } else { /* back pointer up a bit to the beginning of crumple zone */ char *base = (char *)buf; base -= __mf_opts.crumple_zone; if (__mf_opts.trace_mf_calls) { VERBOSE_TRACE ("freeing pointer %p = %p - %u\n", (void *) base, (void *) buf, __mf_opts.crumple_zone); } BEGIN_MALLOC_PROTECT (); CALL_REAL (free, base); END_MALLOC_PROTECT (); } }
void HostScreen_setWindowSize(int width, int height, int bpp) { int screenwidth, screenheight, maxw, maxh; int scalex, scaley, sbarheight; if (bpp == 24) bpp = 32; /* constrain size request to user's desktop size */ Resolution_GetDesktopSize(&maxw, &maxh); scalex = scaley = 1; while (width > maxw*scalex) { scalex *= 2; } while (height > maxh*scalex) { scalex *= 2; } if (scalex * scaley > 1) { fprintf(stderr, "WARNING: too large screen size %dx%d -> divided by %dx%d!\n", width, height, scalex, scaley); width /= scalex; height /= scaley; } Resolution_GetLimits(&maxw, &maxh, &bpp); nScreenZoomX = nScreenZoomY = 1; if (ConfigureParams.Screen.bAspectCorrect) { /* Falcon (and TT) pixel scaling factors seem to 2^x * (quarter/half pixel, interlace/double line), so * do aspect correction as 2's exponent. */ while (nScreenZoomX*width < height && 2*nScreenZoomX*width < maxw) { nScreenZoomX *= 2; } while (2*nScreenZoomY*height < width && 2*nScreenZoomY*height < maxh) { nScreenZoomY *= 2; } if (nScreenZoomX*nScreenZoomY > 2) { fprintf(stderr, "WARNING: strange screen size %dx%d -> aspect corrected by %dx%d!\n", width, height, nScreenZoomX, nScreenZoomY); } } /* then select scale as close to target size as possible * without having larger size than it */ scalex = maxw/(nScreenZoomX*width); scaley = maxh/(nScreenZoomY*height); if (scalex > 1 && scaley > 1) { /* keep aspect ratio */ if (scalex < scaley) { nScreenZoomX *= scalex; nScreenZoomY *= scalex; } else { nScreenZoomX *= scaley; nScreenZoomY *= scaley; } } hs_width_req = width; hs_height_req = height; width *= nScreenZoomX; height *= nScreenZoomY; /* get statusbar size for this screen size */ sbarheight = Statusbar_GetHeightForSize(width, height); screenheight = height + sbarheight; screenwidth = width; /* get resolution corresponding to these */ Resolution_Search(&screenwidth, &screenheight, &bpp); /* re-calculate statusbar height for this resolution */ sbarheight = Statusbar_SetHeight(screenwidth, screenheight-sbarheight); hs_bpp = bpp; /* videl.c might scale things differently in fullscreen than * in windowed mode because this uses screensize instead of using * the aspect scaled sizes directly, but it works better this way. */ hs_width = screenwidth; hs_height = screenheight - sbarheight; if (sdlscrn && (!bpp || sdlscrn->format->BitsPerPixel == bpp) && sdlscrn->w == (signed)screenwidth && sdlscrn->h == (signed)screenheight && (sdlscrn->flags&SDL_FULLSCREEN) == (sdl_videoparams&SDL_FULLSCREEN)) { /* same host screen size despite Atari resolution change, * -> no time consuming host video mode change needed */ if (screenwidth > width || screenheight > height+sbarheight) { /* Atari screen smaller than host -> clear screen */ SDL_Rect rect; rect.x = 0; rect.y = 0; rect.w = sdlscrn->w; rect.h = sdlscrn->h - sbarheight; SDL_FillRect(sdlscrn, &rect, SDL_MapRGB(sdlscrn->format, 0, 0, 0)); /* re-calculate variables in case height + statusbar height * don't anymore match SDL surface size (there's an assert * for that) */ Statusbar_Init(sdlscrn); } // check in case switched from VDI to Hostscreen doUpdate = ( sdlscrn->flags & SDL_HWSURFACE ) == 0; return; } if (bInFullScreen) { /* un-embed the Hatari WM window for fullscreen */ Control_ReparentWindow(screenwidth, screenheight, bInFullScreen); sdl_videoparams = SDL_SWSURFACE|SDL_HWPALETTE|SDL_FULLSCREEN; } else { sdl_videoparams = SDL_SWSURFACE|SDL_HWPALETTE; } #ifdef _MUDFLAP if (sdlscrn) { __mf_unregister(sdlscrn->pixels, sdlscrn->pitch*sdlscrn->h, __MF_TYPE_GUESS); } #endif sdlscrn = SDL_SetVideoMode(screenwidth, screenheight, bpp, sdl_videoparams); #ifdef _MUDFLAP __mf_register(sdlscrn->pixels, sdlscrn->pitch*sdlscrn->h, __MF_TYPE_GUESS, "SDL pixels"); #endif if (!bInFullScreen) { /* re-embed the new Hatari SDL window */ Control_ReparentWindow(screenwidth, screenheight, bInFullScreen); } // In case surface format changed, update SDL palette & remap the native palette HostScreen_updatePalette(256); HostScreen_remapPalette(); // redraw statusbar Statusbar_Init(sdlscrn); Dprintf(("Surface Pitch = %d, width = %d, height = %d\n", sdlscrn->pitch, sdlscrn->w, sdlscrn->h)); Dprintf(("Must Lock? %s\n", SDL_MUSTLOCK(sdlscrn) ? "YES" : "NO")); // is the SDL_update needed? doUpdate = ( sdlscrn->flags & SDL_HWSURFACE ) == 0; Dprintf(("Pixel format:bitspp=%d, tmasks r=%04x g=%04x b=%04x" ", tshifts r=%d g=%d b=%d" ", tlosses r=%d g=%d b=%d\n", sdlscrn->format->BitsPerPixel, sdlscrn->format->Rmask, sdlscrn->format->Gmask, sdlscrn->format->Bmask, sdlscrn->format->Rshift, sdlscrn->format->Gshift, sdlscrn->format->Bshift, sdlscrn->format->Rloss, sdlscrn->format->Gloss, sdlscrn->format->Bloss)); Main_WarpMouse(sdlscrn->w/2,sdlscrn->h/2); }
/** * Initialize SDL screen surface / set resolution. */ static void Screen_SetResolution(void) { int Width, Height, nZoom, SBarHeight, BitCount, maxW, maxH; bool bDoubleLowRes = false; BitCount = 0; /* host native */ nBorderPixelsTop = nBorderPixelsBottom = 0; nBorderPixelsLeft = nBorderPixelsRight = 0; nScreenZoomX = 1; nScreenZoomY = 1; Width = 1120; Height = 832; nZoom = 1; /* Statusbar height for doubled screen size */ SBarHeight = Statusbar_GetHeightForSize(1120, 832); Resolution_GetLimits(&maxW, &maxH, &BitCount); Screen_SetSTScreenOffsets(); Height += Statusbar_SetHeight(Width, Height); /* Check if we really have to change the video mode: */ if (!sdlscrn || sdlscrn->w != Width || sdlscrn->h != Height || (BitCount && sdlscrn->format->BitsPerPixel != BitCount)) { #ifdef _MUDFLAP if (sdlscrn) { __mf_unregister(sdlscrn->pixels, sdlscrn->pitch*sdlscrn->h, __MF_TYPE_GUESS); } #endif if (bInFullScreen) { /* unhide the Hatari WM window for fullscreen */ Control_ReparentWindow(Width, Height, bInFullScreen); } /* Set new video mode */ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); fprintf(stderr, "SDL screen request: %d x %d @ %d (%s)\n", Width, Height, BitCount, bInFullScreen?"fullscreen":"windowed"); sdlWindow = SDL_CreateWindow(PROG_NAME, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, Width, Height, 0); sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0); if (!sdlWindow || !sdlRenderer) { fprintf(stderr,"Failed to create window or renderer!\n"); exit(-1); } SDL_RenderSetLogicalSize(sdlRenderer, Width, Height); sdlscrn = SDL_CreateRGBSurface(SDL_SWSURFACE, Width, Height, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000); sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STREAMING, Width, Height); fprintf(stderr, "SDL screen granted: %d x %d @ %d\n", sdlscrn->w, sdlscrn->h, sdlscrn->format->BitsPerPixel); /* Exit if we can not open a screen */ if (!sdlscrn) { fprintf(stderr, "Could not set video mode:\n %s\n", SDL_GetError() ); SDL_Quit(); exit(-2); } #ifdef _MUDFLAP __mf_register(sdlscrn->pixels, sdlscrn->pitch*sdlscrn->h, __MF_TYPE_GUESS, "SDL pixels"); #endif if (!bInFullScreen) { /* re-embed the new Hatari SDL window */ Control_ReparentWindow(Width, Height, bInFullScreen); } /* Re-init screen palette: */ if (sdlscrn->format->BitsPerPixel == 8) Screen_Handle8BitPalettes(); /* Initialize new 8 bit palette */ else Screen_SetupRGBTable(); /* Create color convertion table */ Statusbar_Init(sdlscrn); /* screen area without the statusbar */ NEXTScreenRect.x = 0; NEXTScreenRect.y = 0; NEXTScreenRect.w = sdlscrn->w; NEXTScreenRect.h = sdlscrn->h - Statusbar_GetHeight(); } /* Set drawing functions */ Screen_SetDrawFunctions(sdlscrn->format->BitsPerPixel, bDoubleLowRes); Screen_SetFullUpdate(); /* Cause full update of screen */ }
WRAPPER(void, free, void *buf) { /* Use a circular queue to delay some number (__mf_opts.free_queue_length) of free()s. */ static void *free_queue [__MF_FREEQ_MAX]; static unsigned free_ptr = 0; static int freeq_initialized = 0; DECLARE(void, free, void *); BEGIN_PROTECT (free, buf); if (UNLIKELY(buf == NULL)) return; LOCKTH (); if (UNLIKELY(!freeq_initialized)) { memset (free_queue, 0, __MF_FREEQ_MAX * sizeof (void *)); freeq_initialized = 1; } UNLOCKTH (); __mf_unregister (buf, 0, __MF_TYPE_HEAP_I); /* NB: underlying region may have been __MF_TYPE_HEAP. */ if (UNLIKELY(__mf_opts.free_queue_length > 0)) { char *freeme = NULL; LOCKTH (); if (free_queue [free_ptr] != NULL) { freeme = free_queue [free_ptr]; freeme -= __mf_opts.crumple_zone; } free_queue [free_ptr] = buf; free_ptr = (free_ptr == (__mf_opts.free_queue_length-1) ? 0 : free_ptr + 1); UNLOCKTH (); if (freeme) { if (__mf_opts.trace_mf_calls) { VERBOSE_TRACE ("freeing deferred pointer %p (crumple %u)\n", (void *) freeme, __mf_opts.crumple_zone); } BEGIN_MALLOC_PROTECT (); CALL_REAL (free, freeme); END_MALLOC_PROTECT (); } } else { /* back pointer up a bit to the beginning of crumple zone */ char *base = (char *)buf; base -= __mf_opts.crumple_zone; if (__mf_opts.trace_mf_calls) { VERBOSE_TRACE ("freeing pointer %p = %p - %u\n", (void *) base, (void *) buf, __mf_opts.crumple_zone); } BEGIN_MALLOC_PROTECT (); CALL_REAL (free, base); END_MALLOC_PROTECT (); } }