📄 gdk_posix.mx
字号:
/* Cygwin implementation: struct flock is there, but lockf() is missing. */static intlockf(int fd, int cmd, off_t len){ struct flock l; if (cmd == F_LOCK || cmd == F_TLOCK) l.l_type = F_WRLCK; else if (cmd == F_ULOCK) l.l_type = F_UNLCK; l.l_whence = SEEK_CUR; l.l_start = 0; l.l_len = len; return fcntl(fd, cmd == F_TLOCK ? F_SETLKW : F_SETLK, &l);}#endif/* returns -1 when locking failed, * returns -2 when the lock file could not be opened/created * returns the (open) file descriptor to the file otherwise */intMT_lockf(char *filename, int mode, off_t off, off_t len){ int ret = -1, fd = open(filename, O_CREAT | O_RDWR, 0662); if (fd < 0) return -2; if (lseek(fd, off, SEEK_SET) == off) { if (lockf(fd, mode, len) == 0) { ret = fd; } else { close(fd); } } else { close(fd); } /* do not close else we lose the lock we want */ return ret;}voidMT_sleep_ms(unsigned int ms){#ifdef HAVE_NANOSLEEP struct timespec ts; ts.tv_sec = (time_t) (ms / 1000); ts.tv_nsec = 1000000 * (ms % 1000); while (nanosleep(&ts, &ts) == -1 && errno == EINTR) ;#else struct timeval tv; tv.tv_sec = ms / 1000; tv.tv_usec = ms % 1000; (void) select(0, NULL, NULL, NULL, &tv);#endif}#else /* WIN32 */#define MT_PAGESIZE(s) (((((s)-1) >> 12) + 1) << 12)#define MT_SEGSIZE(s) ((((((s)-1) >> 16) & 65535) + 1) << 16)#ifndef MEM_TOP_DOWN#define MEM_TOP_DOWN 0#endifvoid *MT_vmalloc(size_t size, size_t * maxsize){ void *p, *a = NULL; int mode = 0; size = MT_PAGESIZE(size); if (*maxsize < size) { *maxsize = size; } *maxsize = MT_SEGSIZE(*maxsize); if (*maxsize < 1000000) { mode = MEM_TOP_DOWN; /* help NT in keeping memory defragmented */ } (void) pthread_mutex_lock(&MT_mmap_lock); if (*maxsize > size) { a = (void *) VirtualAlloc(NULL, *maxsize, MEM_RESERVE | mode, PAGE_NOACCESS); if (a == NULL) { *maxsize = size; } } p = (void *) VirtualAlloc(a, size, MEM_COMMIT | mode, PAGE_READWRITE); (void) pthread_mutex_unlock(&MT_mmap_lock); if (p == NULL) { stream_printf(GDKerr, "VirtualAlloc(" PTRFMT "," SZFMT ",MEM_COMMIT,PAGE_READWRITE): failed\n", PTRFMTCAST a, size); } return p;}voidMT_vmfree(void *p, size_t size){ if (VirtualFree(p, size, MEM_DECOMMIT) == 0) stream_printf(GDKerr, "VirtualFree(" PTRFMT "," SZFMT ",MEM_DECOMMIT): failed\n", PTRFMTCAST p, size); if (VirtualFree(p, 0, MEM_RELEASE) == 0) stream_printf(GDKerr, "VirtualFree(" PTRFMT ",0,MEM_RELEASE): failed\n", PTRFMTCAST p);}void *MT_vmrealloc(void *v, size_t oldsize, size_t newsize, size_t oldmaxsize, size_t * newmaxsize){ char *p = (char *) v, *a = p; /* sanitize sizes */ oldsize = MT_PAGESIZE(oldsize); newsize = MT_PAGESIZE(newsize); oldmaxsize = MT_PAGESIZE(oldmaxsize); *newmaxsize = MT_PAGESIZE(*newmaxsize); if (*newmaxsize < newsize) { *newmaxsize = newsize; } if (oldsize > newsize) { size_t ret = VirtualFree(p + newsize, oldsize - newsize, MEM_DECOMMIT); if (ret == 0) stream_printf(GDKerr, "VirtualFree(" PTRFMT "," SSZFMT ",MEM_DECOMMIT): failed\n", PTRFMTCAST(p + newsize), (ssize_t) (oldsize - newsize)); } else if (oldsize < newsize) { (void) pthread_mutex_lock(&MT_mmap_lock); a = (char *) VirtualAlloc(p, newsize, MEM_COMMIT, PAGE_READWRITE); (void) pthread_mutex_unlock(&MT_mmap_lock); if (a != p) { char *q = a; if (a == NULL) { q = MT_vmalloc(newsize, newmaxsize); } if (q != NULL) { memcpy(q, p, oldsize); MT_vmfree(p, oldmaxsize); } if (a == NULL) return q; } } *newmaxsize = MAX(oldmaxsize, newsize); return a;}/* see contract of unix MT_lockf */intMT_lockf(char *filename, int mode, off_t off, off_t len){ int ret = 1, illegalmode = 0, fd = -1; OVERLAPPED ov; OSVERSIONINFO os; HANDLE fh = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&os); memset(&ov, 0, sizeof(ov)); ov.Offset = (unsigned int) off;#if 0 ov.OffsetHigh = off >> 32;#else ov.OffsetHigh = 0; /* sizeof(off) == 4, i.e. off >> 32 is not possible */#endif if (fh == NULL) { return -2; } if (mode == F_ULOCK) { if (os.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) ret = UnlockFileEx(fh, 0, 0, len, &ov); } else if (mode == F_TLOCK) { if (os.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) ret = LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY | LOCKFILE_EXCLUSIVE_LOCK, 0, 0, len, &ov); } else if (mode == F_LOCK) { if (os.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) ret = LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, 0, len, &ov); } else { illegalmode = 1; } CloseHandle(fh); if (illegalmode) { SetLastError(ERROR_INVALID_DATA); } if (ret != 0) { fd = open(filename, O_CREAT | O_RDWR, 0662); if (fd < 0) { /* this is nasty, but I "trust" windows that it in this case * also cannot open the file into a filehandle any more, so * unlocking is in vain. */ return -2; } else { return fd; } } else { return -1; }}voidMT_sleep_ms(unsigned int ms){ Sleep(ms);}@-cygnus1.1.X has a bug in the semaphore routines. we work around it by directly using the WIN32 primitives.@c#ifndef NATIVE_WIN32intsem_init(sem_t * sem, int pshared, unsigned int value){ (void) pshared; *sem = (sem_t) CreateSemaphore(NULL, value, 128, NULL); return (*sem) ? 0 : -1;}intsem_destroy(sem_t * sem){ return CloseHandle((HANDLE) * sem) ? 0 : -1;}intsem_wait(sem_t * sem){ return (WaitForSingleObject((HANDLE) * sem, (unsigned int) INFINITE) != WAIT_FAILED) ? 0 : -1;}intsem_post(sem_t * sem){ return (ReleaseSemaphore((HANDLE) * sem, 1, NULL) == 0) ? -1 : 0;}#endif#endif@}@+ Memory fragmentation monitoringOn 32-bits systems, Monet's aggressive use of virtual memory may bring it intotrouble as the limits of what is addressable in a 32-bits system are reached (an 32-bits OS only allows 2 to 4GB of memory to be used). In order to aid debuggingsituations where VM allocs fail (due to memory fragmentation), a monitoringsystem was established. To this purpose, a map is made for the VM addressesbetween 0 and 3GB, in tiles of MT_VMUNITSIZE (64KB). These tiles have a bytevalue from the following domain:@table @samp@item 0-9 thread stack space of thread <num>@item B in use for a large BAT heap.@item b free (last usage was B)@item S in use for a malloc block@item s free (last usage was S)@item P in use for the BBP array@item p free (last usage was P)@item M in use as memory mapped region@item m free (last usage was M)@item C in use as MIL context buffer@item c free (last usage was C)@end tableThe MT_alloc_printmap condenses the map by printing a char for each MB,hence combining info from 16 tiles. On NT, we can check in real-time which tiles are actually in use (in case our own tile administration is out-of-sync with reality, eg due to a memory leak). This real-life usage is printed in a second line with encoding .=free, *=inuse, X=unusable. On Unix systems,*=inuse is not testable (unless with complicated signal stuff). On 64-bitssystems, this administration is dysfunctional. @{@c#ifdef DEBUG_ALLOC#if SIZEOF_VOID_P == 4unsigned char MT_alloc_map[65536] = { 0 };#endifintMT_alloc_register(void *addr, size_t size, char mode){#if SIZEOF_VOID_P == 4 size_t p = (size_t) addr; if (size > 0) { size_t i, base = p >> 16; size = (size - 1) >> 16; assert(p && ((lng) p) + size < (LL_CONSTANT(1) << 32)); for (i = 0; i <= size; i++) MT_alloc_map[base + i] = (MT_alloc_map[base + i] & 128) | mode; }#else (void) addr; (void) size; (void) mode;#endif return 0;}#define INUSEMODE(x) ((x >= '0' && x <= ('9'+4)) || (x >= 'A' && x <= 'Z'))intMT_alloc_print(void){#if SIZEOF_VOID_P == 4#ifdef WIN32 char *p = NULL;#endif int i, j, k; if (MT_alloc_map[0] == 0) return 0; for (i = 0; i < 40; i++) { stream_printf(GDKout, "%02d00MB ", i); for (j = 0; j < 100; j++) { int mode = '.'; for (k = 0; k < 16; k++) { int m = MT_alloc_map[k + 16 * (j + 100 * i)] & 127; if (mode == '.' || INUSEMODE(m)) mode = m; } stream_printf(GDKout, "%c", mode); }#ifdef WIN32 stream_printf(GDKout, "\n "); for (j = 0; j < 100; j++) { int mode = '.'; for (k = 0; k < 16; k++, p += 1 << 16) if (!IsBadReadPtr(p, 1)) { mode = '*'; } else if (MT_alloc_map[k + 16 * (j + 100 * i)] & 128) { mode = 'X'; } stream_printf(GDKout, "%c", mode); }#endif stream_printf(GDKout, "\n"); }#endif return 0;}@-The memory table dump can also be produced in tuple formatto enable front-ends to analyze it more easily.@cstruct { char tag; char *color; char *info;} Encoding[] = { { '.', "0x00FFFDFE", "free"}, { '0', "0x000035FC", "thread stack space of thread 0"}, { '1', "0x000067FE", "thread stack space of thread 1"}, { '2', "0x000095FE", "thread stack space of thread 2"}, { '3', "0x0000BDFC", "thread stack space of thread 3"}, { '4', "0x0000DCF8", "thread stack space of thread 4"}, { '5', "0x002735FC", "thread stack space of thread 5"}, { '6', "0x002767FE", "thread stack space of thread 6"}, { '7', "0x002795FE", "thread stack space of thread 7"}, { '8', "0x0027BDFC", "thread stack space of thread 8"}, { '9', "0x0027DCF8", "thread stack space of thread 9"}, { 'B', "0x0000672D", "in use for a large BAT heap."}, { 'b', "0x004EF2A7", "free (last usage was B)"}, { 'S', "0x00B4006E", "in use for a malloc block"}, { 's', "0x00F2BDE0", "free (last usage was S)"}, { 'P', "0x00F26716", "in use for the BBP array"}, { 'p', "0x00F2BD16", "free (last usage was P)"}, { 'M', "0x00959516", "in use as memory mapped region"}, { 'm', "0x00CEDC16", "free (last usage was M)"}, { 'C', "0x004EFDC7", "in use as MIL context buffer"}, { 'c', "0x00FFFD2D", "free (last usage was M)"}, { 0, "0x00FFFDFE", "free"}};intMT_alloc_table(void){#if SIZEOF_VOID_P == 4#ifdef WIN32 char *p = NULL;#endif int i, j, k; if (MT_alloc_map[0] == 0) return 0; stream_printf(GDKout, "# addr\tX\tY\tcolor\tmode\tcomment\t# name\n"); stream_printf(GDKout, "# str\tint\tint\tcolor\tstr\tstr\t# type\n"); for (i = 0; i < 40; i++) { for (j = 0; j < 100; j++) { int mode = '.'; for (k = 0; k < 16; k++) { int m = MT_alloc_map[k + 16 * (j + 100 * i)] & 127; if (mode == '.' || INUSEMODE(m)) mode = m; } for (k = 0; k >= 0; k++) if (Encoding[k].tag == mode || Encoding[k].tag == 0) { if (mode == 0) mode = ' '; stream_printf(GDKout, "[ \"%d\",\t%d,\t%d,\t", k + 16 * (j + 100 * i), j, i); stream_printf(GDKout, "\"%s\",\t", Encoding[k].color); stream_printf(GDKout, "\"%c\",\t\"%s\"\t]\n", mode, Encoding[k].info); break; } }#ifdef WIN32 stream_printf(GDKout, "\n "); for (j = 0; j < 100; j++) { int mode = '.'; for (k = 0; k < 16; k++, p += 1 << 16) if (!IsBadReadPtr(p, 1)) { mode = '*'; } else if (MT_alloc_map[k + 16 * (j + 100 * i)] & 128) { mode = 'X'; } stream_printf(GDKout, "%c", mode); } stream_printf(GDKout, "\n");#endif }#endif return 0;}static voidMT_alloc_init(void){#if SIZEOF_VOID_P == 4 char *p = NULL; int i; for (i = 0; i < 65536; i++, p += MT_VMUNITSIZE) { int mode = '.';#ifdef WIN32 if (!VirtualAlloc(p, MT_VMUNITSIZE, MEM_RESERVE, PAGE_NOACCESS)) { mode |= 128; } else { VirtualFree(p, 0, MEM_RELEASE); }#else MMAP_OPEN_DEV_ZERO; void *q = (char *) mmap(p, MT_VMUNITSIZE, PROT_NONE, MMAP_FLAGS(MAP_NORESERVE), MMAP_FD, 0); MMAP_CLOSE_DE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -