⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 os_dep.c

📁 Boost provides free peer-reviewed portable C++ source libraries. We emphasize libraries that work
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved. * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved. * Copyright (c) 1999 by Hewlett-Packard Company.  All rights reserved. * * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK. * * Permission is hereby granted to use or copy this program * for any purpose,  provided the above notices are retained on all copies. * Permission to modify the code and to distribute modified code is granted, * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. */# include "private/gc_priv.h"# ifdef THREADS#   include "atomic_ops.h"# endif# if defined(LINUX) && !defined(POWERPC)#   include <linux/version.h>#   if (LINUX_VERSION_CODE <= 0x10400)      /* Ugly hack to get struct sigcontext_struct definition.  Required      */      /* for some early 1.3.X releases.  Will hopefully go away soon. */      /* in some later Linux releases, asm/sigcontext.h may have to   */      /* be included instead.                                         */#     define __KERNEL__#     include <asm/signal.h>#     undef __KERNEL__#   else      /* Kernels prior to 2.1.1 defined struct sigcontext_struct instead of */      /* struct sigcontext.  libc6 (glibc2) uses "struct sigcontext" in     */      /* prototypes, so we have to include the top-level sigcontext.h to    */      /* make sure the former gets defined to be the latter if appropriate. */#     include <features.h>#     if 2 <= __GLIBC__#       if 2 == __GLIBC__ && 0 == __GLIBC_MINOR__	  /* glibc 2.1 no longer has sigcontext.h.  But signal.h	*/	  /* has the right declaration for glibc 2.1.			*/#         include <sigcontext.h>#       endif /* 0 == __GLIBC_MINOR__ */#     else /* not 2 <= __GLIBC__ */        /* libc5 doesn't have <sigcontext.h>: go directly with the kernel   */        /* one.  Check LINUX_VERSION_CODE to see which we should reference. */#       include <asm/sigcontext.h>#     endif /* 2 <= __GLIBC__ */#   endif# endif# if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS) \    && !defined(MSWINCE)#   include <sys/types.h>#   if !defined(MSWIN32)#   	include <unistd.h>#   endif# endif# include <stdio.h># if defined(MSWINCE)#   define SIGSEGV 0 /* value is irrelevant */# else#   include <signal.h># endif#ifdef UNIX_LIKE# include <fcntl.h>#endif#if defined(LINUX) || defined(LINUX_STACKBOTTOM)# include <ctype.h>#endif/* Blatantly OS dependent routines, except for those that are related 	*//* to dynamic loading.							*/#ifdef AMIGA# define GC_AMIGA_DEF# include "AmigaOS.c"# undef GC_AMIGA_DEF#endif#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)# define WIN32_LEAN_AND_MEAN# define NOSERVICE# include <windows.h>  /* It's not clear this is completely kosher under Cygwin.  But it	*/  /* allows us to get a working GC_get_stack_base.			*/#endif#ifdef MACOS# include <Processes.h>#endif#ifdef IRIX5# include <sys/uio.h># include <malloc.h>   /* for locking */#endif#if defined(LINUX) || defined(FREEBSD) || defined(SOLARIS) || defined(IRIX5) \	|| defined(USE_MMAP) || defined(USE_MUNMAP)# define MMAP_SUPPORTED#endif#if defined(MMAP_SUPPORTED) || defined(ADD_HEAP_GUARD_PAGES)# if defined(USE_MUNMAP) && !defined(USE_MMAP)    --> USE_MUNMAP requires USE_MMAP# endif# include <sys/types.h># include <sys/mman.h># include <sys/stat.h># include <errno.h>#endif#ifdef DARWIN/* for get_etext and friends */#include <mach-o/getsect.h>#endif#ifdef DJGPP  /* Apparently necessary for djgpp 2.01.  May cause problems with	*/  /* other versions.							*/  typedef long unsigned int caddr_t;#endif#ifdef PCR# include "il/PCR_IL.h"# include "th/PCR_ThCtl.h"# include "mm/PCR_MM.h"#endif#if !defined(NO_EXECUTE_PERMISSION)# define OPT_PROT_EXEC PROT_EXEC#else# define OPT_PROT_EXEC 0#endif#if defined(LINUX) && \    (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64) || !defined(SMALL_CONFIG))# define NEED_PROC_MAPS#endif#ifdef NEED_PROC_MAPS/* We need to parse /proc/self/maps, either to find dynamic libraries,	*//* and/or to find the register backing store base (IA64).  Do it once	*//* here.								*/#define READ read/* Repeatedly perform a read call until the buffer is filled or	*//* we encounter EOF.						*/ssize_t GC_repeat_read(int fd, char *buf, size_t count){    ssize_t num_read = 0;    ssize_t result;        while (num_read < count) {	result = READ(fd, buf + num_read, count - num_read);	if (result < 0) return result;	if (result == 0) break;	num_read += result;    }    return num_read;}/* Determine the length of a file by incrementally reading it into a 	*//* This would be sily to use on a file supporting lseek, but Linux	*//* /proc files usually do not.						*/size_t GC_get_file_len(int f){    size_t total = 0;    ssize_t result;#   define GET_FILE_LEN_BUF_SZ 500    char buf[GET_FILE_LEN_BUF_SZ];    do {	result = read(f, buf, GET_FILE_LEN_BUF_SZ);	if (result == -1) return 0;	total += result;    } while (result > 0);    return total;}size_t GC_get_maps_len(void){    int f = open("/proc/self/maps", O_RDONLY);    size_t result = GC_get_file_len(f);    close(f);    return result;}/* * Copy the contents of /proc/self/maps to a buffer in our address space. * Return the address of the buffer, or zero on failure. * This code could be simplified if we could determine its size * ahead of time. */char * GC_get_maps(void){    int f;    int result;    static char init_buf[1];    static char *maps_buf = init_buf;    static size_t maps_buf_sz = 1;    size_t maps_size, old_maps_size = 0;    /* The buffer is essentially static, so there must be a single client. */    GC_ASSERT(I_HOLD_LOCK());    /* Note that in the presence of threads, the maps file can	*/    /* essentially shrink asynchronously and unexpectedly as 	*/    /* threads that we already think of as dead release their	*/    /* stacks.  And there is no easy way to read the entire	*/    /* file atomically.  This is arguably a misfeature of the	*/    /* /proc/.../maps interface.				*/    /* Since we dont believe the file can grow			*/    /* asynchronously, it should suffice to first determine	*/    /* the size (using lseek or read), and then to reread the	*/    /* file.  If the size is inconsistent we have to retry.	*/    /* This only matters with threads enabled, and if we use 	*/    /* this to locate roots (not the default).			*/    /* Determine the initial size of /proc/self/maps.		*/    /* Note that lseek doesn't work, at least as of 2.6.15.	*/#   ifdef THREADS	maps_size = GC_get_maps_len();	if (0 == maps_size) return 0;#   else	maps_size = 4000;	/* Guess */#   endif    /* Read /proc/self/maps, growing maps_buf as necessary.	*/    /* Note that we may not allocate conventionally, and	*/    /* thus can't use stdio.					*/	do {	    while (maps_size >= maps_buf_sz) {	      /* Grow only by powers of 2, since we leak "too small" buffers. */	      while (maps_size >= maps_buf_sz) maps_buf_sz *= 2;	      maps_buf = GC_scratch_alloc(maps_buf_sz);#	      ifdef THREADS	        /* Recompute initial length, since we allocated.	*/	        /* This can only happen a few times per program		*/	        /* execution.						*/	        maps_size = GC_get_maps_len();	        if (0 == maps_size) return 0;#	      endif	      if (maps_buf == 0) return 0;	    }	    GC_ASSERT(maps_buf_sz >= maps_size + 1);	    f = open("/proc/self/maps", O_RDONLY);	    if (-1 == f) return 0;#	    ifdef THREADS	      old_maps_size = maps_size;#	    endif	    maps_size = 0;	    do {	        result = GC_repeat_read(f, maps_buf, maps_buf_sz-1);	        if (result <= 0) return 0;	        maps_size += result;	    } while (result == maps_buf_sz-1);	    close(f);#	    ifdef THREADS	      if (maps_size > old_maps_size) {		GC_err_printf("Old maps size = %d, new maps size = %d\n",			      old_maps_size, maps_size);		ABORT("Unexpected asynchronous /proc/self/maps growth: "		      "Unregistered thread?");	      }#	    endif	} while (maps_size >= maps_buf_sz || maps_size < old_maps_size);		/* In the single-threaded case, the second clause is false.	*/        maps_buf[maps_size] = '\0';	    /* Apply fn to result. */	return maps_buf;}////  GC_parse_map_entry parses an entry from /proc/self/maps so we can//  locate all writable data segments that belong to shared libraries.//  The format of one of these entries and the fields we care about//  is as follows://  XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537     name of mapping...\n//  ^^^^^^^^ ^^^^^^^^ ^^^^          ^^//  start    end      prot          maj_dev////  Note that since about august 2003 kernels, the columns no longer have//  fixed offsets on 64-bit kernels.  Hence we no longer rely on fixed offsets//  anywhere, which is safer anyway.///* * Assign various fields of the first line in buf_ptr to *start, *end, * *prot, *maj_dev and *mapping_name.  Mapping_name may be NULL. * *prot and *mapping_name are assigned pointers into the original * buffer. */char *GC_parse_map_entry(char *buf_ptr, ptr_t *start, ptr_t *end,                                char **prot, unsigned int *maj_dev,				char **mapping_name){    char *start_start, *end_start, *maj_dev_start;    char *p;    char *endp;    if (buf_ptr == NULL || *buf_ptr == '\0') {        return NULL;    }    p = buf_ptr;    while (isspace(*p)) ++p;    start_start = p;    GC_ASSERT(isxdigit(*start_start));    *start = (ptr_t)strtoul(start_start, &endp, 16); p = endp;    GC_ASSERT(*p=='-');    ++p;    end_start = p;    GC_ASSERT(isxdigit(*end_start));    *end = (ptr_t)strtoul(end_start, &endp, 16); p = endp;    GC_ASSERT(isspace(*p));    while (isspace(*p)) ++p;    GC_ASSERT(*p == 'r' || *p == '-');    *prot = p;    /* Skip past protection field to offset field */       while (!isspace(*p)) ++p; while (isspace(*p)) ++p;    GC_ASSERT(isxdigit(*p));    /* Skip past offset field, which we ignore */          while (!isspace(*p)) ++p; while (isspace(*p)) ++p;    maj_dev_start = p;    GC_ASSERT(isxdigit(*maj_dev_start));    *maj_dev = strtoul(maj_dev_start, NULL, 16);    if (mapping_name == 0) {      while (*p && *p++ != '\n');    } else {      while (*p && *p != '\n' && *p != '/' && *p != '[') p++;      *mapping_name = p;      while (*p && *p++ != '\n');    }    return p;}/* Try to read the backing store base from /proc/self/maps.		*//* Return the bounds of the writable mapping with a 0 major device,	*//* which includes the address passed as data.				*//* Return FALSE if there is no such mapping.				*/GC_bool GC_enclosing_mapping(ptr_t addr, ptr_t *startp, ptr_t *endp){  char *prot;  ptr_t my_start, my_end;  unsigned int maj_dev;  char *maps = GC_get_maps();  char *buf_ptr = maps;    if (0 == maps) return(FALSE);  for (;;) {    buf_ptr = GC_parse_map_entry(buf_ptr, &my_start, &my_end,		    	         &prot, &maj_dev, 0);    if (buf_ptr == NULL) return FALSE;    if (prot[1] == 'w' && maj_dev == 0) {        if (my_end > addr && my_start <= addr) {    	  *startp = my_start;	  *endp = my_end;	  return TRUE;	}    }  }  return FALSE;}/* Find the text(code) mapping for the library whose name starts with nm. */GC_bool GC_text_mapping(char *nm, ptr_t *startp, ptr_t *endp){  size_t nm_len = strlen(nm);  char *prot;  char *map_path;  ptr_t my_start, my_end;  unsigned int maj_dev;  char *maps = GC_get_maps();  char *buf_ptr = maps;    if (0 == maps) return(FALSE);  for (;;) {    buf_ptr = GC_parse_map_entry(buf_ptr, &my_start, &my_end,		    	         &prot, &maj_dev, &map_path);    if (buf_ptr == NULL) return FALSE;    if (prot[0] == 'r' && prot[1] == '-' && prot[2] == 'x' &&	strncmp(nm, map_path, nm_len) == 0) {    	  *startp = my_start;	  *endp = my_end;	  return TRUE;    }  }  return FALSE;}#ifdef IA64static ptr_t backing_store_base_from_proc(void){    ptr_t my_start, my_end;    if (!GC_enclosing_mapping(GC_save_regs_in_stack(), &my_start, &my_end)) {	if (GC_print_stats) {	    GC_log_printf("Failed to find backing store base from /proc\n");	}	return 0;    }    return my_start;}#endif#endif /* NEED_PROC_MAPS */	#if defined(SEARCH_FOR_DATA_START)  /* The I386 case can be handled without a search.  The Alpha case	*/  /* used to be handled differently as well, but the rules changed	*/  /* for recent Linux versions.  This seems to be the easiest way to	*/  /* cover all versions.						*/# if defined(LINUX) || defined(HURD)    /* Some Linux distributions arrange to define __data_start.  Some	*/    /* define data_start as a weak symbol.  The latter is technically	*/    /* broken, since the user program may define data_start, in which	*/    /* case we lose.  Nonetheless, we try both, prefering __data_start.	*/    /* We assume gcc-compatible pragmas.	*/#   pragma weak __data_start    extern int __data_start[];#   pragma weak data_start    extern int data_start[];# endif /* LINUX */  extern int _end[];  ptr_t GC_data_start;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -