📄 gdk_posix.c
字号:
}voidMT_mmap_unpin(void *base, size_t len){ int i; (void) pthread_mutex_lock(&MT_mmap_lock); i = MT_mmap_idx(base, len); if (i >= 0) { MT_mmap_tab[i].pincnt--; } (void) pthread_mutex_unlock(&MT_mmap_lock);}void *MT_mmap(char *path, int mode, off_t off, size_t len){ MT_mmap_hdl hdl; void *ret = MT_mmap_open(&hdl, path, mode, off, len, 0); MT_mmap_close(&hdl); return ret;}#ifndef NATIVE_WIN32#ifdef HAVE_POSIX_FADVISE#ifdef HAVE_UNAME#include <sys/utsname.h>#endif#endif#if !defined(WIN32) && defined(PROFILE) #ifdef HAVE_PTHREAD_H#undef pthread_create/* for profiling purposes (btw configure with --enable-profile *and* --disable-shared --enable-static) * without setting the ITIMER_PROF per thread, all profiling info for everything except the main thread is lost. */#include <stdlib.h>/* Our data structure passed to the wrapper */typedef struct wrapper_s{ void * (*start_routine)(void *); void * arg; pthread_mutex_t lock; pthread_cond_t wait; struct itimerval itimer;} wrapper_t;/* The wrapper function in charge for setting the itimer value */static void * wrapper_routine(void * data){ /* Put user data in thread-local variables */ void * (*start_routine)(void *) = ((wrapper_t*)data)->start_routine; void * arg = ((wrapper_t*)data)->arg; /* Set the profile timer value */ setitimer(ITIMER_PROF, &((wrapper_t*)data)->itimer, NULL); /* Tell the calling thread that we don't need its data anymore */ pthread_mutex_lock(&((wrapper_t*)data)->lock); pthread_cond_signal(&((wrapper_t*)data)->wait); pthread_mutex_unlock(&((wrapper_t*)data)->lock); /* Call the real function */ return start_routine(arg);}/* Our wrapper function for the real pthread_create() */int gprof_pthread_create(pthread_t *__restrict thread, __const pthread_attr_t *__restrict attr, void * (*start_routine)(void *), void *__restrict arg){ wrapper_t wrapper_data; int i_return; /* Initialize the wrapper structure */ wrapper_data.start_routine = start_routine; wrapper_data.arg = arg; getitimer(ITIMER_PROF, &wrapper_data.itimer); pthread_cond_init(&wrapper_data.wait, NULL); pthread_mutex_init(&wrapper_data.lock, NULL); pthread_mutex_lock(&wrapper_data.lock); /* The real pthread_create call */ i_return = pthread_create(thread, attr, &wrapper_routine, &wrapper_data); /* If the thread was successfully spawned, wait for the data to be released */ if(i_return == 0) { pthread_cond_wait(&wrapper_data.wait, &wrapper_data.lock); } pthread_mutex_unlock(&wrapper_data.lock); pthread_mutex_destroy(&wrapper_data.lock); pthread_cond_destroy(&wrapper_data.wait); return i_return;}#endif#endifvoidMT_init_posix(int alloc_map){#ifdef HAVE_POSIX_FADVISE#ifdef HAVE_UNAME struct utsname ubuf; /* do not use posix_fadvise on Linux systems running a 2.4 or older kernel */ do_not_use_posix_fadvise = uname(&ubuf) == 0 && strcmp(ubuf.sysname, "Linux") == 0 && strncmp(ubuf.release, "2.4", 3) <= 0;#endif#endif MT_heapbase = (char *) sbrk(0);#ifdef DEBUG_ALLOC static void MT_alloc_init(void); if (alloc_map) MT_alloc_init();#else (void)alloc_map;#endif MT_mmap_init();}size_tMT_getrss(void){ /* get RSS -- linux only for the moment */ static char MT_mmap_procfile[128] = { 0 }; int fd; if (MT_mmap_procfile[0] == 0) { /* getpid returns pid_t, cast to long to be sure */ sprintf(MT_mmap_procfile, "/proc/%ld/stat", (long) getpid()); } fd = open(MT_mmap_procfile, O_RDONLY); if (fd >= 0) { char buf[1024], *r = buf; size_t i, sz = read(fd, buf, 1024); close(fd); if (sz > 0) { for (i = 0; i < 23; i++) { while (*r && (*r == ' ' || *r == '\t')) r++; while (*r && (*r != ' ' && *r != '\t')) r++; } while (*r && (*r == ' ' || *r == '\t')) r++; return ((size_t) atol(r)) * MT_pagesize(); } } return 0;}char *MT_heapcur(void){ return (char *) sbrk(0);}void*MT_mmap_open(MT_mmap_hdl *hdl, char *path, int mode, off_t off, size_t len, size_t nremaps){ int fd = open(path, O_CREAT | ((mode & MMAP_WRITE) ? O_RDWR : O_RDONLY)); void *ret = (void *) -1L; (void) nremaps; if (fd >= 0) { hdl->mode = mode; hdl->fixed = NULL; hdl->hdl = (void *) (ssize_t) fd; ret = MT_mmap_remap(hdl, off, len); } if (ret != (void *) -1L) { hdl->fixed = ret; fd = MT_mmap_new(path, ret, len, fd, (mode & MMAP_WRITABLE)); if (fd <= 0) hdl->hdl = (void *) 0; /* MT_mmap_new keeps the fd */ } return ret;}void *MT_mmap_remap(MT_mmap_hdl *hdl, off_t off, size_t len){ void *ret; ret = mmap(hdl->fixed, len, ((hdl->mode & MMAP_WRITABLE) ? PROT_WRITE : 0) | PROT_READ, ((hdl->mode & MMAP_COPY) ? (MAP_PRIVATE|MAP_NORESERVE) : MAP_SHARED) | (hdl->fixed ? MAP_FIXED : 0), (int) (ssize_t) hdl->hdl, off); if (ret != (void *) -1L) { if (hdl->mode & MMAP_ADVISE) { (void) MT_madvise(ret, len, hdl->mode & MMAP_ADVISE); } hdl->fixed = (void *) ((char *) ret + len); } return ret;}voidMT_mmap_close(MT_mmap_hdl *hdl){ int fd = (int) (ssize_t) hdl->hdl; if (fd) close(fd); hdl->hdl = NULL;}intMT_munmap(void *p, size_t len){ int ret = munmap(p, len);#ifdef MMAP_DEBUG stream_printf(GDKerr, "munmap(" LLFMT "," LLFMT ",%d) = %d\n", (long long) p, (long long) len, ret);#endif MT_mmap_del(p, len); return ret;}intMT_msync(void *p, size_t len, int mode){ int ret = msync(p, len, (mode & MMAP_SYNC) ? MS_SYNC : ((mode & MMAP_ASYNC) ? MS_ASYNC : MS_INVALIDATE));#ifdef MMAP_DEBUG stream_printf(GDKerr, "msync(" LLFMT "," LLFMT ",%s) = %d\n", (long long) p, (long long) len, (mode & MMAP_SYNC) ? "MS_SYNC" : ((mode & MMAP_ASYNC) ? "MS_ASYNC" : "MS_INVALIDATE"), ret);#endif if (ret < 0) return errno; return ret;}intMT_madvise(void *p, size_t len, int advise){ int ret = posix_madvise(p, len, advise);#ifdef MMAP_DEBUG stream_printf(GDKerr, "posix_madvise(" LLFMT "," LLFMT ",%d) = %d\n", (long long) p, (long long) len, advise, ret);#endif if (MT_fadvise(p, len, advise)) ret = -1; return ret;}struct mallinfoMT_mallinfo(void){ struct mallinfo _ret;#ifdef HAVE_MALLINFO _ret = mallinfo();#else memset(&_ret, 0, sizeof(_ret));#endif if (_ret.uordblks + _ret.fordblks > _ret.arena) { MT_alloc_register(MT_heapbase, _ret.arena, 'H'); } return _ret;}intMT_path_absolute(char *pathname){ return (*pathname == DIR_SEP);}#ifdef WIN32#include <windows.h>#endif#else /* WIN32 native */#ifndef BUFSIZ#define BUFSIZ 1024#endif#undef _errno#undef stat#undef rmdir#undef mkdir#undef NAME_MAX#include <windows.h>#ifdef _MSC_VER#include <io.h>#endif /* _MSC_VER */#define MT_SMALLBLOCK 256voidMT_init_posix(int alloc_map){ MT_heapbase = 0;/* _set_sbh_threshold(MT_SMALLBLOCK);*/#ifdef DEBUG_ALLOC static void MT_alloc_init(void); if (alloc_map) MT_alloc_init();#else (void)alloc_map;#endif MT_mmap_init();}size_tMT_getrss(){#if (_WIN32_WINNT >= 0x0500) MEMORYSTATUSEX state; state.dwLength = sizeof(state); GlobalMemoryStatusEx (&state); return (size_t) (state.ullTotalPhys - state.ullAvailPhys);#else MEMORYSTATUS state; GlobalMemoryStatus (&state); return state.dwTotalPhys - state.dwAvailPhys;#endif}char *MT_heapcur(void){ return (char *) 0;}/* Windows mmap keeps a global list of base addresses for complex (remapped) memory maps * the reason is that each remapped segment needs to be unmapped separately in the end. */typedef struct _remap_t { struct _remap_t * next; char* start; char* end; size_t cnt; void *bases[1]; /* EXTENDS (cnt-1) BEYOND THE END OF THE STRUCT */} remap_t;remap_t *remaps = NULL;static remap_t *remap_find(char* base, int delete) { remap_t *map, *prev=NULL; (void) pthread_mutex_lock(&MT_mmap_lock); for(map=remaps; map; map=map->next) { if (base >= map->start && base < map->end) { if (delete) { if (prev) prev->next = map->next; else remaps = map->next; map->next = NULL; } break; } } (void) pthread_mutex_unlock(&MT_mmap_lock); return map;} void*MT_mmap_open(MT_mmap_hdl *hdl, char *path, int mode, off_t off, size_t len, size_t nremaps){ void *ret = NULL; int mode0 = GENERIC_READ; int mode1 = FILE_SHARE_READ; int mode2 = mode & MMAP_ADVISE; int mode3 = PAGE_READONLY; int mode4 = FILE_MAP_READ; SECURITY_ATTRIBUTES sa; HANDLE h1, h2; remap_t *map; memset(hdl, 0, sizeof(MT_mmap_hdl)); if (mode & MMAP_WRITE) { mode0 |= GENERIC_WRITE; mode1 |= FILE_SHARE_WRITE; } if (mode2 == MMAP_RANDOM || mode2 == MMAP_DONTNEED) { mode2 = FILE_FLAG_RANDOM_ACCESS; } else if (mode2 == MMAP_SEQUENTIAL || mode2 == MMAP_WILLNEED) { mode2 = FILE_FLAG_SEQUENTIAL_SCAN; } else { mode2 = FILE_FLAG_NO_BUFFERING; } if (mode & MMAP_SYNC) { mode2 |= FILE_FLAG_WRITE_THROUGH; } if (mode & MMAP_COPY) { mode3 = PAGE_WRITECOPY; mode4 = FILE_MAP_COPY; } else if (mode & MMAP_WRITE) { mode3 = PAGE_READWRITE; mode4 = FILE_MAP_WRITE; } sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = 0; h1 = CreateFile(path, mode0, mode1, &sa, OPEN_ALWAYS, mode2, NULL); if (h1 == INVALID_HANDLE_VALUE) { GDKsyserror("MT_mmap: CreateFile('%s', %d, %d, &sa, %d, %d, NULL) failed\n", path, mode0, mode1, OPEN_ALWAYS, mode2); return (void *) -1; } h2 = CreateFileMapping(h1, &sa, mode3, (DWORD) ((((gdk_int64) off + (gdk_int64) len) >> 32) & LL_CONSTANT(0xFFFFFFFF)), (DWORD) ((off + len) & LL_CONSTANT(0xFFFFFFFF)), NULL); if (h2 == NULL) { GDKsyserror("MT_mmap: CreateFileMapping(" PTRFMT ", &sa, %d, %d, %u, NULL) failed\n", PTRFMTCAST h1, mode3, (DWORD) ((((gdk_int64) off + (gdk_int64) len) >> 32) & LL_CONSTANT(0xFFFFFFFF)), (DWORD) ((off + len) & LL_CONSTANT(0xFFFFFFFF))); CloseHandle(h1); return (void *) -1; } hdl->hdl = (void *) h2; hdl->mode = mode4; CloseHandle(h1); if (nremaps == 0) { return MT_mmap_remap(hdl, off, len); /* normal mmap(). no further remaps */ } /* for complex mmaps we now make it very likely that the MapViewOfFileEx-es to a predetermined VM address will all succeed */ ret = VirtualAlloc(NULL, len, MEM_RESERVE, PAGE_READWRITE); if (ret == NULL) return (void*) -1; hdl->fixed = ret; /* now we have a VM region that is large enough */ /* ensure exclusive VM access to MapViewOfFile and VirtualAlloc (almost.. malloc() may trigger it -- ignored) */ (void) pthread_mutex_lock(&MT_mmap_lock); hdl->hasLock = 1; /* release the range, so we can MapViewOfFileEx into it later */ VirtualFree(ret, 0, MEM_RELEASE); /* allocate a map record to administer all your bases (they are belong to us!) */ map = malloc(sizeof(remap_t) + sizeof(void *) * nremaps); if (map == NULL) return (void *) -1; hdl->map = (void *) map; map->cnt = 0; map->start = (char *) hdl->fixed; map->end = map->start + len; return ret;}void *MT_mmap_remap(MT_mmap_hdl *hdl, off_t off, size_t len){ remap_t *map = (remap_t*) hdl->map; void *ret; ret = MapViewOfFileEx((HANDLE) hdl->hdl, hdl->mode, (DWORD) ((gdk_int64) off >> 32), (DWORD) off, len, (void *) ((char *) hdl->fixed)); if (ret == NULL) { GDKsyserror("MT_mmap: MapViewOfFileEx(" PTRFMT ", %d, %d, %u, %d, " PTRFMT ") failed\n", PTRFMTCAST hdl->hdl, hdl->mode, (DWORD) ((gdk_int64) off >> 32), (DWORD) off, len, PTRFMTCAST hdl->fixed); return (void *) -1; } if (map) map->bases[map->cnt++] = ret; /* administer new base */ hdl->fixed = (void *) ((char *) ret + len); return ret;}voidMT_mmap_close(MT_mmap_hdl *hdl){ if (hdl->hasLock) { (void) pthread_mutex_unlock(&MT_mmap_lock); } if (hdl->hdl) { CloseHandle((HANDLE) hdl->hdl); hdl->hdl = NULL; }}intMT_munmap(void *p, size_t dummy){ remap_t *map = remap_find(p, TRUE); int ret = 0; (void)dummy; if (map) { /* remapped region; has multiple bases on which we must invoke the Windows API */ size_t i; for(i=0; i<map->cnt; i++) if (UnmapViewOfFile(map->bases[i]) == 0) ret = -1; free(map); } else { /* Windows' UnmapViewOfFile returns success!=0, error== 0, * while Unix's munmap returns success==0, error==-1. */ if (UnmapViewOfFile(p) == 0) ret = -1; } return ret;}intMT_msync(void *p, size_t len, int mode){ remap_t *map = remap_find(p, FALSE); int ret = 0; (void)mode;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -