📄 memory.c
字号:
return p;#endif /* TARGET */ return NULL;}/* Initialise the fields of a meminfo structure to describe the details * of the underlying memory architecture. */MP_GLOBALvoid__mp_newmemory(meminfo *i){#if MP_WATCH_SUPPORT char b[64];#endif /* MP_WATCH_SUPPORT */#if MP_ARRAY_SUPPORT memorysize = 0;#endif /* MP_ARRAY_SUPPORT */ i->align = minalign(); i->page = pagesize(); i->stackdir = stackdirection(NULL); i->prog = progname();#if MP_MMAP_SUPPORT /* On UNIX systems that support the mmap() function call, we default to * using sbrk() for user memory and mmap() for internal memory. If the * MP_MMAP_ANONYMOUS macro is set then we don't need to open a file for * mapping. */#if MP_MMAP_ANONYMOUS i->mfile = 0;#else /* MP_MMAP_ANONYMOUS */ i->mfile = open(MP_MMAP_FILENAME, O_RDWR);#endif /* MP_MMAP_ANONYMOUS */#else /* MP_MMAP_SUPPORT */ i->mfile = -1;#endif /* MP_MMAP_SUPPORT */#if MP_WATCH_SUPPORT sprintf(b, MP_PROCFS_CTLNAME, __mp_processid()); i->wfile = open(b, O_WRONLY);#else /* MP_WATCH_SUPPORT */ i->wfile = -1;#endif /* MP_WATCH_SUPPORT */ i->flags = 0;}/* Free up any resources used by the meminfo structure. */MP_GLOBALvoid__mp_endmemory(meminfo *i){#if MP_MMAP_SUPPORT if (i->mfile != -1) {#if !MP_MMAP_ANONYMOUS close(i->mfile);#endif /* MP_MMAP_ANONYMOUS */ i->mfile = -1; }#endif /* MP_MMAP_SUPPORT */#if MP_WATCH_SUPPORT if (i->wfile != -1) { close(i->wfile); i->wfile = -1; }#endif /* MP_WATCH_SUPPORT */}/* Return the process identifier. */MP_GLOBALunsigned long__mp_processid(void){#if TARGET == TARGET_UNIX || TARGET == TARGET_WINDOWS return (unsigned long) getpid();#elif TARGET == TARGET_AMIGA return (unsigned long) FindTask(NULL);#elif TARGET == TARGET_NETWARE return (unsigned long) GetThreadId();#else /* TARGET */ /* We just assume that any other operating systems have no support for * multiple processes and so anything we return here is irrelevant. */ return 1;#endif /* TARGET */}#if MP_ARRAY_SUPPORT/* Provide sbrk()-like functionality for systems that have no system functions * for allocating heap memory. The simulated heap grows upwards in this * implementation. */staticvoid *getmemory(long l){ void *p; p = memoryarray + memorysize; if (l > 0) if (memorysize + l > MP_ARRAY_SIZE) p = (void *) -1; else memorysize += l; else if (l < 0) if (memorysize < -l) p = (void *) -1; else memorysize += l; return p;}#elif TARGET == TARGET_UNIX#define getmemory(l) sbrk(l)#endif /* MP_ARRAY_SUPPORT && TARGET *//* Allocate a specified size of general-purpose memory from the system * with a required alignment. */MP_GLOBALvoid *__mp_memalloc(meminfo *i, size_t *l, size_t a, int u){ void *p;#if MP_ARRAY_SUPPORT || TARGET == TARGET_UNIX void *t; unsigned long n;#endif /* MP_ARRAY_SUPPORT && TARGET */ if (*l == 0) *l = 1;#if MP_ARRAY_SUPPORT || TARGET == TARGET_UNIX || TARGET == TARGET_NETWARE /* Round up the size of the allocation to a multiple of the system page * size. */ *l = __mp_roundup(*l, i->page);#elif TARGET == TARGET_WINDOWS /* The VirtualAlloc() function on Windows only seems to allocate memory in * blocks of 65536 bytes, so we round up the size of the allocation to this * amount since otherwise the space would be wasted. */ *l = __mp_roundup(*l, 0x10000);#elif TARGET == TARGET_AMIGA /* We aren't guaranteed to allocate a block of memory that is page * aligned on the Amiga, so we have to assume the worst case scenario * and allocate more memory for the specified alignment. */ if (a > i->page) a = i->page; if (a > MEM_BLOCKSIZE) *l += __mp_poweroftwo(a) - MEM_BLOCKSIZE;#endif /* MP_ARRAY_SUPPORT && TARGET */#if MP_ARRAY_SUPPORT || TARGET == TARGET_UNIX /* UNIX has a contiguous heap for a process, but we are not guaranteed to * have full control over it, so we must assume that each separate memory * allocation is independent. If we are using sbrk() to allocate memory * then we also try to ensure that all of our memory allocations are blocks * of pages. */#if MP_MMAP_SUPPORT /* Decide if we are using mmap() or sbrk() to allocate the memory. Requests * for user memory will be allocated in the opposite way to internal memory. */ if ((((i->flags & FLG_USEMMAP) != 0) == (u != 0)) && (i->mfile != -1)) u = 1; else u = 0; if (u != 0) {#if MP_MMAP_ANONYMOUS if ((p = mmap(NULL, *l, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) == (void *) -1)#else /* MP_MMAP_ANONYMOUS */ if ((p = mmap(NULL, *l, PROT_READ | PROT_WRITE, MAP_PRIVATE, i->mfile, 0)) == (void *) -1)#endif /* MP_MMAP_ANONYMOUS */ p = NULL; } else#endif /* MP_MMAP_SUPPORT */ { if (((t = getmemory(0)) == (void *) -1) || ((p = getmemory(*l)) == (void *) -1)) p = NULL; else { if (p < t) /* The heap has grown down, which is quite unusual except on * some weird systems where the stack grows up. */ n = (unsigned long) p - __mp_rounddown((unsigned long) p, i->page); else { t = p; n = __mp_roundup((unsigned long) p, i->page) - (unsigned long) p; } if (n > 0) /* We need to allocate a little more memory in order to make the * allocation page-aligned. */ if ((p = getmemory(n)) == (void *) -1) { /* We failed to allocate more memory, but we try to be nice * and return our original allocation back to the system. */ getmemory(-*l); p = NULL; } else if (p >= t) p = (char *) t + n; } }#elif TARGET == TARGET_AMIGA p = AllocMem(*l, MEMF_ANY | MEMF_CLEAR);#elif TARGET == TARGET_WINDOWS /* The VirtualProtect() function won't allow us to protect a range of pages * that span the allocation boundaries made by VirtualAlloc(). As mpatrol * tries to merge all bordering free memory areas, we must prevent the * pages allocated by different calls to VirtualAlloc() from being merged. * The easiest way to do this is to reserve a page of virtual memory after * each call to VirtualAlloc() since this won't actually take up any * physical memory. It's a bit of a hack, though! */ p = VirtualAlloc(NULL, *l, MEM_COMMIT, PAGE_READWRITE); VirtualAlloc(NULL, 0x10000, MEM_RESERVE, PAGE_NOACCESS);#elif TARGET == TARGET_NETWARE p = NXPageAlloc(*l / i->page, 0);#endif /* MP_ARRAY_SUPPORT && TARGET */#if MP_ARRAY_SUPPORT || TARGET == TARGET_UNIX || TARGET == TARGET_NETWARE /* UNIX's sbrk() and Netware's NXPageAlloc() do not zero the allocated * memory, so we do this here for predictable behaviour. This is also the * case if we are using a simulated heap. */#if MP_MMAP_SUPPORT if ((p != NULL) && (u == 0))#else /* MP_MMAP_SUPPORT */ if (p != NULL)#endif /* MP_MMAP_SUPPORT */ __mp_memset(p, 0, *l);#endif /* MP_ARRAY_SUPPORT && TARGET */ if (p == NULL) errno = ENOMEM; return p;}/* Return a block of allocated memory back to the system. */MP_GLOBALvoid__mp_memfree(meminfo *i, void *p, size_t l){#if !MP_ARRAY_SUPPORT#if TARGET == TARGET_UNIX || TARGET == TARGET_WINDOWS || \ TARGET == TARGET_NETWARE void *t;#endif /* TARGET */#endif /* MP_ARRAY_SUPPORT */ /* This function is hardly ever called except when the process is * terminating as the heap manager will take care of reusing unused * memory. There is also no point in doing anything when we are using * a simulated heap as it will automatically be returned to the system. */#if !MP_ARRAY_SUPPORT if (l == 0) return;#if TARGET == TARGET_UNIX || TARGET == TARGET_WINDOWS || \ TARGET == TARGET_NETWARE t = (void *) __mp_rounddown((unsigned long) p, i->page);#endif /* TARGET */#if TARGET == TARGET_UNIX /* If we used sbrk() to allocate this memory then we can't shrink the * break point since someone else might have allocated memory in between * our allocations. The next best thing is to unmap our freed allocations * so that they no longer need to be handled by the virtual memory system. * If we used mmap() to allocate this memory then we don't need to worry * about the above problem. */ l = __mp_roundup(l + ((char *) p - (char *) t), i->page); mprotect(t, l, PROT_NONE); munmap(t, l);#elif TARGET == TARGET_AMIGA FreeMem(p, l);#elif TARGET == TARGET_WINDOWS VirtualFree(t, 0, MEM_RELEASE);#elif TARGET == TARGET_NETWARE NXPageFree(t);#endif /* TARGET */#endif /* MP_ARRAY_SUPPORT */}#if TARGET == TARGET_UNIX/* Handles any signals that result from illegal memory accesses whilst * querying the permissions of addresses. */staticvoidmemoryhandler(int s){ longjmp(memorystate, 1);}#endif /* TARGET *//* Return the access permission of an address. */MP_GLOBALmemaccess__mp_memquery(meminfo *i, void *p){#if TARGET == TARGET_UNIX#if MP_SIGINFO_SUPPORT struct sigaction s;#endif /* MP_SIGINFO_SUPPORT */ char c;#elif TARGET == TARGET_WINDOWS MEMORY_BASIC_INFORMATION m;#endif /* TARGET */ memaccess r; r = MA_READWRITE;#if TARGET == TARGET_UNIX#if MP_MINCORE_SUPPORT /* The mincore() system call allows us to determine if a page is in core, * and if it is not and ENOMEM is set then it means that the page is not * mapped. Unfortunately, we can't tell if it's read-only. */ if ((mincore((char *) __mp_rounddown((unsigned long) p, i->page), 1, &c) == -1) && (errno == ENOMEM)) return MA_NOACCESS;#endif /* MP_MINCORE_SUPPORT */ /* One generic way to determine the access permission of an address across * all UNIX systems is to attempt to read from and write to the address and * check the results using signals. */#if MP_SIGINFO_SUPPORT s.sa_flags = 0; (void *) s.sa_handler = (void *) memoryhandler; sigfillset(&s.sa_mask); sigaction(SIGBUS, &s, &membushandler); sigaction(SIGSEGV, &s, &memsegvhandler);#else /* MP_SIGINFO_SUPPORT */ membushandler = signal(SIGBUS, memoryhandler); memsegvhandler = signal(SIGSEGV, memoryhandler);#endif /* MP_SIGINFO_SUPPORT */ if (setjmp(memorystate)) r = MA_NOACCESS; else { c = *((char *) p); if (setjmp(memorystate)) r = MA_READONLY; else *((char *) p) = c; }#if MP_SIGINFO_SUPPORT sigaction(SIGBUS, &membushandler, NULL); sigaction(SIGSEGV, &memsegvhandler, NULL);#else /* MP_SIGINFO_SUPPORT */ signal(SIGBUS, membushandler); signal(SIGSEGV, memsegvhandler);#endif /* MP_SIGINFO_SUPPORT */#elif TARGET == TARGET_WINDOWS /* On Windows, the VirtualQuery() function allows us to determine the * access permission of the page the address belongs to. */ if (VirtualQuery(p, &m, sizeof(m)) >= sizeof(m)) if (!(m.State & MEM_COMMIT) || (m.Protect & PAGE_NOACCESS) || (m.Protect & PAGE_EXECUTE)) r = MA_NOACCESS; else if ((m.Protect & PAGE_READONLY) || (m.Protect & PAGE_EXECUTE_READ)) r = MA_READONLY;#endif /* TARGET */ return r;}/* Protect a block of allocated memory with the supplied access permission. */MP_GLOBALint__mp_memprotect(meminfo *i, void *p, size_t l, memaccess a){#if TARGET == TARGET_UNIX || TARGET == TARGET_WINDOWS void *t; int n;#endif /* TARGET */#if TARGET == TARGET_UNIX || TARGET == TARGET_WINDOWS if (l == 0) return 1; t = (void *) __mp_rounddown((unsigned long) p, i->page);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -