📄 os_dep.c
字号:
# if defined(SUNOS5SIGS) || defined(IRIX5) \ || defined(OSF1) || defined(HURD) || defined(NETBSD) (void) sigaction(SIGSEGV, &old_segv_act, 0);# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \ || defined(HPUX) || defined(HURD) || defined(NETBSD) (void) sigaction(SIGBUS, &old_bus_act, 0);# endif# else (void) signal(SIGSEGV, old_segv_handler);# ifdef SIGBUS (void) signal(SIGBUS, old_bus_handler);# endif# endif } /* Return the first nonaddressible location > p (up) or */ /* the smallest location q s.t. [q,p) is addressable (!up). */ /* We assume that p (up) or p-1 (!up) is addressable. */ /* Requires allocation lock. */ ptr_t GC_find_limit_with_bound(ptr_t p, GC_bool up, ptr_t bound) { static volatile ptr_t result; /* Safer if static, since otherwise it may not be */ /* preserved across the longjmp. Can safely be */ /* static since it's only called with the */ /* allocation lock held. */ GC_ASSERT(I_HOLD_LOCK()); GC_setup_temporary_fault_handler(); if (SETJMP(GC_jmp_buf) == 0) { result = (ptr_t)(((word)(p)) & ~(MIN_PAGE_SIZE-1)); for (;;) { if (up) { result += MIN_PAGE_SIZE; if (result >= bound) return bound; } else { result -= MIN_PAGE_SIZE; if (result <= bound) return bound; } GC_noop1((word)(*result)); } } GC_reset_fault_handler(); if (!up) { result += MIN_PAGE_SIZE; } return(result); } ptr_t GC_find_limit(ptr_t p, GC_bool up) { if (up) { return GC_find_limit_with_bound(p, up, (ptr_t)(word)(-1)); } else { return GC_find_limit_with_bound(p, up, 0); } }# endif#if defined(ECOS) || defined(NOSYS) ptr_t GC_get_main_stack_base(void) { return STACKBOTTOM; }#endif#ifdef HPUX_STACKBOTTOM#include <sys/param.h>#include <sys/pstat.h> ptr_t GC_get_register_stack_base(void) { struct pst_vm_status vm_status; int i = 0; while (pstat_getprocvm(&vm_status, sizeof(vm_status), 0, i++) == 1) { if (vm_status.pst_type == PS_RSESTACK) { return (ptr_t) vm_status.pst_vaddr; } } /* old way to get the register stackbottom */ return (ptr_t)(((word)GC_stackbottom - BACKING_STORE_DISPLACEMENT - 1) & ~(BACKING_STORE_ALIGNMENT - 1)); }#endif /* HPUX_STACK_BOTTOM */#ifdef LINUX_STACKBOTTOM#include <sys/types.h>#include <sys/stat.h># define STAT_SKIP 27 /* Number of fields preceding startstack */ /* field in /proc/self/stat */#ifdef USE_LIBC_PRIVATES# pragma weak __libc_stack_end extern ptr_t __libc_stack_end;#endif# ifdef IA64# ifdef USE_LIBC_PRIVATES# pragma weak __libc_ia64_register_backing_store_base extern ptr_t __libc_ia64_register_backing_store_base;# endif ptr_t GC_get_register_stack_base(void) { ptr_t result;# ifdef USE_LIBC_PRIVATES if (0 != &__libc_ia64_register_backing_store_base && 0 != __libc_ia64_register_backing_store_base) { /* Glibc 2.2.4 has a bug such that for dynamically linked */ /* executables __libc_ia64_register_backing_store_base is */ /* defined but uninitialized during constructor calls. */ /* Hence we check for both nonzero address and value. */ return __libc_ia64_register_backing_store_base; }# endif result = backing_store_base_from_proc(); if (0 == result) { result = GC_find_limit(GC_save_regs_in_stack(), FALSE); /* Now seems to work better than constant displacement */ /* heuristic used in 6.X versions. The latter seems to */ /* fail for 2.6 kernels. */ } return result; }# endif ptr_t GC_linux_stack_base(void) { /* We read the stack base value from /proc/self/stat. We do this */ /* using direct I/O system calls in order to avoid calling malloc */ /* in case REDIRECT_MALLOC is defined. */ # define STAT_BUF_SIZE 4096# define STAT_READ read /* Should probably call the real read, if read is wrapped. */ char stat_buf[STAT_BUF_SIZE]; int f; char c; word result = 0; size_t i, buf_offset = 0; /* First try the easy way. This should work for glibc 2.2 */ /* This fails in a prelinked ("prelink" command) executable */ /* since the correct value of __libc_stack_end never */ /* becomes visible to us. The second test works around */ /* this. */ # ifdef USE_LIBC_PRIVATES if (0 != &__libc_stack_end && 0 != __libc_stack_end ) {# if defined(IA64) /* Some versions of glibc set the address 16 bytes too */ /* low while the initialization code is running. */ if (((word)__libc_stack_end & 0xfff) + 0x10 < 0x1000) { return __libc_stack_end + 0x10; } /* Otherwise it's not safe to add 16 bytes and we fall */ /* back to using /proc. */# elif defined(SPARC) /* Older versions of glibc for 64-bit Sparc do not set * this variable correctly, it gets set to either zero * or one. */ if (__libc_stack_end != (ptr_t) (unsigned long)0x1) return __libc_stack_end;# else return __libc_stack_end;# endif }# endif f = open("/proc/self/stat", O_RDONLY); if (f < 0 || STAT_READ(f, stat_buf, STAT_BUF_SIZE) < 2 * STAT_SKIP) { ABORT("Couldn't read /proc/self/stat"); } c = stat_buf[buf_offset++]; /* Skip the required number of fields. This number is hopefully */ /* constant across all Linux implementations. */ for (i = 0; i < STAT_SKIP; ++i) { while (isspace(c)) c = stat_buf[buf_offset++]; while (!isspace(c)) c = stat_buf[buf_offset++]; } while (isspace(c)) c = stat_buf[buf_offset++]; while (isdigit(c)) { result *= 10; result += c - '0'; c = stat_buf[buf_offset++]; } close(f); if (result < 0x10000000) ABORT("Absurd stack bottom value"); return (ptr_t)result; }#endif /* LINUX_STACKBOTTOM */#ifdef FREEBSD_STACKBOTTOM/* This uses an undocumented sysctl call, but at least one expert *//* believes it will stay. */#include <unistd.h>#include <sys/types.h>#include <sys/sysctl.h> ptr_t GC_freebsd_stack_base(void) { int nm[2] = {CTL_KERN, KERN_USRSTACK}; ptr_t base; size_t len = sizeof(ptr_t); int r = sysctl(nm, 2, &base, &len, NULL, 0); if (r) ABORT("Error getting stack base"); return base; }#endif /* FREEBSD_STACKBOTTOM */#if !defined(BEOS) && !defined(AMIGA) && !defined(MSWIN32) \ && !defined(MSWINCE) && !defined(OS2) && !defined(NOSYS) && !defined(ECOS) \ && !defined(CYGWIN32)ptr_t GC_get_main_stack_base(void){# if defined(HEURISTIC1) || defined(HEURISTIC2) word dummy;# endif ptr_t result;# define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)# ifdef STACKBOTTOM return(STACKBOTTOM);# else# ifdef HEURISTIC1# ifdef STACK_GROWS_DOWN result = (ptr_t)((((word)(&dummy)) + STACKBOTTOM_ALIGNMENT_M1) & ~STACKBOTTOM_ALIGNMENT_M1);# else result = (ptr_t)(((word)(&dummy)) & ~STACKBOTTOM_ALIGNMENT_M1);# endif# endif /* HEURISTIC1 */# ifdef LINUX_STACKBOTTOM result = GC_linux_stack_base();# endif# ifdef FREEBSD_STACKBOTTOM result = GC_freebsd_stack_base();# endif# ifdef HEURISTIC2# ifdef STACK_GROWS_DOWN result = GC_find_limit((ptr_t)(&dummy), TRUE);# ifdef HEURISTIC2_LIMIT if (result > HEURISTIC2_LIMIT && (ptr_t)(&dummy) < HEURISTIC2_LIMIT) { result = HEURISTIC2_LIMIT; }# endif# else result = GC_find_limit((ptr_t)(&dummy), FALSE);# ifdef HEURISTIC2_LIMIT if (result < HEURISTIC2_LIMIT && (ptr_t)(&dummy) > HEURISTIC2_LIMIT) { result = HEURISTIC2_LIMIT; }# endif# endif# endif /* HEURISTIC2 */# ifdef STACK_GROWS_DOWN if (result == 0) result = (ptr_t)(signed_word)(-sizeof(ptr_t));# endif return(result);# endif /* STACKBOTTOM */}# endif /* ! AMIGA, !OS 2, ! MS Windows, !BEOS, !NOSYS, !ECOS */#if defined(GC_LINUX_THREADS) && !defined(HAVE_GET_STACK_BASE)#include <pthread.h>#ifdef IA64 ptr_t GC_greatest_stack_base_below(ptr_t bound); /* From pthread_support.c */#endifint GC_get_stack_base(struct GC_stack_base *b){ pthread_attr_t attr; size_t size; if (pthread_getattr_np(pthread_self(), &attr) != 0) { WARN("pthread_getattr_np failed\n", 0); return GC_UNIMPLEMENTED; } if (pthread_attr_getstack(&attr, &(b -> mem_base), &size) != 0) { ABORT("pthread_attr_getstack failed"); }# ifdef STACK_GROWS_DOWN b -> mem_base = (char *)(b -> mem_base) + size;# endif# ifdef IA64 /* We could try backing_store_base_from_proc, but that's safe */ /* only if no mappings are being asynchronously created. */ /* Subtracting the size from the stack base doesn't work for at */ /* least the main thread. */ LOCK(); { ptr_t bsp = GC_save_regs_in_stack(); ptr_t next_stack = GC_greatest_stack_base_below(bsp); if (0 == next_stack) { b -> reg_base = GC_find_limit(bsp, FALSE); } else { /* Avoid walking backwards into preceding memory stack and */ /* growing it. */ b -> reg_base = GC_find_limit_with_bound(bsp, FALSE, next_stack); } } UNLOCK();# endif return GC_SUCCESS;}#define HAVE_GET_STACK_BASE#endif /* GC_LINUX_THREADS */#ifndef HAVE_GET_STACK_BASE/* Retrieve stack base. *//* Using the GC_find_limit version is risky. *//* On IA64, for example, there is no guard page between the *//* stack of one thread and the register backing store of the *//* next. Thus this is likely to identify way too large a *//* "stack" and thus at least result in disastrous performance. *//* FIXME - Implement better strategies here. */int GC_get_stack_base(struct GC_stack_base *b){ int dummy;# ifdef NEED_FIND_LIMIT# ifdef STACK_GROWS_DOWN b -> mem_base = GC_find_limit((ptr_t)(&dummy), TRUE);# ifdef IA64 b -> reg_base = GC_find_limit(GC_save_regs_in_stack(), FALSE);# endif# else b -> mem_base = GC_find_limit(&dummy, FALSE);# endif return GC_SUCCESS;# else return GC_UNIMPLEMENTED;# endif}#endif/* * Register static data segment(s) as roots. * If more data segments are added later then they need to be registered * add that point (as we do with SunOS dynamic loading), * or GC_mark_roots needs to check for them (as we do with PCR). * Called with allocator lock held. */# ifdef OS2void GC_register_data_segments(void){ PTIB ptib; PPIB ppib; HMODULE module_handle;# define PBUFSIZ 512 UCHAR path[PBUFSIZ]; FILE * myexefile; struct exe_hdr hdrdos; /* MSDOS header. */ struct e32_exe hdr386; /* Real header for my executable */ struct o32_obj seg; /* Currrent segment */ int nsegs; if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) { GC_err_printf("DosGetInfoBlocks failed\n"); ABORT("DosGetInfoBlocks failed\n"); } module_handle = ppib -> pib_hmte; if (DosQueryModuleName(module_handle, PBUFSIZ, path) != NO_ERROR) { GC_err_printf("DosQueryModuleName failed\n"); ABORT("DosGetInfoBlocks failed\n"); } myexefile = fopen(path, "rb"); if (myexefile == 0) { GC_err_puts("Couldn't open executable "); GC_err_puts(path); GC_err_puts("\n"); ABORT("Failed to open executable\n"); } if (fread((char *)(&hdrdos), 1, sizeof hdrdos, myexefile) < sizeof hdrdos) { GC_err_puts("Couldn't read MSDOS header from "); GC_err_puts(path); GC_err_puts("\n"); ABORT("Couldn't read MSDOS header"); } if (E_MAGIC(hdrdos) != EMAGIC) { GC_err_puts("Executable has wrong DOS magic number: "); GC_err_puts(path); GC_err_puts("\n"); ABORT("Bad DOS magic number"); } if (fseek(myexefile, E_LFANEW(hdrdos), SEEK_SET) != 0) { GC_err_puts("Seek to new header failed in "); GC_err_puts(path); GC_err_puts("\n"); ABORT("Bad DOS magic number"); } if (fread((char *)(&hdr386), 1, sizeof hdr386, myexefile) < sizeof hdr386) { GC_err_puts("Couldn't read MSDOS header from "); GC_err_puts(path); GC_err_puts("\n"); ABORT("Couldn't read OS/2 header"); } if (E32_MAGIC1(hdr386) != E32MAGIC1 || E32_MAGIC2(hdr386) != E32MAGIC2) { GC_err_puts("Executable has wrong OS/2 magic number:"); GC_err_puts(path); GC_err_puts("\n"); ABORT("Bad OS/2 magic number"); } if ( E32_BORDER(hdr386) != E32LEBO || E32_WORDER(hdr386) != E32LEWO) { GC_err_puts("Executable %s has wrong byte order: "); GC_err_puts(path); GC_err_puts("\n"); ABORT("Bad byte order"); } if ( E32_CPU(hdr386) == E32CPU286) { GC_err_puts("GC can't handle 80286 executables: "); GC_err_puts(path); GC_err_puts("\n"); EXIT(); } if (fseek(myexefile, E_LFANEW(hdrdos) + E32_OBJTAB(hdr386), SEEK_SET) != 0) { GC_err_puts("Seek to object table failed: "); GC_err_puts(path); GC_err_puts("\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -