📄 os_dep.c
字号:
void GC_init_linux_data_start() { extern ptr_t GC_find_limit(ptr_t, GC_bool);# if defined(LINUX) || defined(HURD) /* Try the easy approaches first: */ if ((ptr_t)__data_start != 0) { GC_data_start = (ptr_t)(__data_start); return; } if ((ptr_t)data_start != 0) { GC_data_start = (ptr_t)(data_start); return; }# endif /* LINUX */ GC_data_start = GC_find_limit((ptr_t)(_end), FALSE); }#endif# ifdef ECOS# ifndef ECOS_GC_MEMORY_SIZE# define ECOS_GC_MEMORY_SIZE (448 * 1024)# endif /* ECOS_GC_MEMORY_SIZE */// FIXME: This is a simple way of allocating memory which is// compatible with ECOS early releases. Later releases use a more// sophisticated means of allocating memory than this simple static// allocator, but this method is at least bound to work.static char memory[ECOS_GC_MEMORY_SIZE];static char *brk = memory;static void *tiny_sbrk(ptrdiff_t increment){ void *p = brk; brk += increment; if (brk > memory + sizeof memory) { brk -= increment; return NULL; } return p;}#define sbrk tiny_sbrk# endif /* ECOS */#if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__) ptr_t GC_data_start; void GC_init_netbsd_elf(void) { extern ptr_t GC_find_limit(ptr_t, GC_bool); extern char **environ; /* This may need to be environ, without the underscore, for */ /* some versions. */ GC_data_start = GC_find_limit((ptr_t)&environ, FALSE); }#endif# ifdef OS2# include <stddef.h># if !defined(__IBMC__) && !defined(__WATCOMC__) /* e.g. EMX */struct exe_hdr { unsigned short magic_number; unsigned short padding[29]; long new_exe_offset;};#define E_MAGIC(x) (x).magic_number#define EMAGIC 0x5A4D #define E_LFANEW(x) (x).new_exe_offsetstruct e32_exe { unsigned char magic_number[2]; unsigned char byte_order; unsigned char word_order; unsigned long exe_format_level; unsigned short cpu; unsigned short os; unsigned long padding1[13]; unsigned long object_table_offset; unsigned long object_count; unsigned long padding2[31];};#define E32_MAGIC1(x) (x).magic_number[0]#define E32MAGIC1 'L'#define E32_MAGIC2(x) (x).magic_number[1]#define E32MAGIC2 'X'#define E32_BORDER(x) (x).byte_order#define E32LEBO 0#define E32_WORDER(x) (x).word_order#define E32LEWO 0#define E32_CPU(x) (x).cpu#define E32CPU286 1#define E32_OBJTAB(x) (x).object_table_offset#define E32_OBJCNT(x) (x).object_countstruct o32_obj { unsigned long size; unsigned long base; unsigned long flags; unsigned long pagemap; unsigned long mapsize; unsigned long reserved;};#define O32_FLAGS(x) (x).flags#define OBJREAD 0x0001L#define OBJWRITE 0x0002L#define OBJINVALID 0x0080L#define O32_SIZE(x) (x).size#define O32_BASE(x) (x).base# else /* IBM's compiler *//* A kludge to get around what appears to be a header file bug */# ifndef WORD# define WORD unsigned short# endif# ifndef DWORD# define DWORD unsigned long# endif# define EXE386 1# include <newexe.h># include <exe386.h># endif /* __IBMC__ */# define INCL_DOSEXCEPTIONS# define INCL_DOSPROCESS# define INCL_DOSERRORS# define INCL_DOSMODULEMGR# define INCL_DOSMEMMGR# include <os2.h>/* Disable and enable signals during nontrivial allocations */void GC_disable_signals(void){ ULONG nest; DosEnterMustComplete(&nest); if (nest != 1) ABORT("nested GC_disable_signals");}void GC_enable_signals(void){ ULONG nest; DosExitMustComplete(&nest); if (nest != 0) ABORT("GC_enable_signals");}# else# if !defined(PCR) && !defined(AMIGA) && !defined(MSWIN32) \ && !defined(MSWINCE) \ && !defined(MACOS) && !defined(DJGPP) && !defined(DOS4GW) \ && !defined(NOSYS) && !defined(ECOS)# if 0 /* Use the traditional BSD interface */# define SIGSET_T int# define SIG_DEL(set, signal) (set) &= ~(sigmask(signal))# define SIG_FILL(set) (set) = 0x7fffffff /* Setting the leading bit appears to provoke a bug in some */ /* longjmp implementations. Most systems appear not to have */ /* a signal 32. */# define SIGSETMASK(old, new) (old) = sigsetmask(new)# endif /* Use POSIX/SYSV interface */# define SIGSET_T sigset_t# define SIG_DEL(set, signal) sigdelset(&(set), (signal))# define SIG_FILL(set) sigfillset(&set)# define SIGSETMASK(old, new) sigprocmask(SIG_SETMASK, &(new), &(old))static GC_bool mask_initialized = FALSE;static SIGSET_T new_mask;static SIGSET_T old_mask;static SIGSET_T dummy;#if defined(GC_ASSERTIONS) && !defined(THREADS)# define CHECK_SIGNALS int GC_sig_disabled = 0;#endifvoid GC_disable_signals(void){ if (!mask_initialized) { SIG_FILL(new_mask); SIG_DEL(new_mask, SIGSEGV); SIG_DEL(new_mask, SIGILL); SIG_DEL(new_mask, SIGQUIT);# ifdef SIGBUS SIG_DEL(new_mask, SIGBUS);# endif# ifdef SIGIOT SIG_DEL(new_mask, SIGIOT);# endif# ifdef SIGEMT SIG_DEL(new_mask, SIGEMT);# endif# ifdef SIGTRAP SIG_DEL(new_mask, SIGTRAP);# endif mask_initialized = TRUE; }# ifdef CHECK_SIGNALS if (GC_sig_disabled != 0) ABORT("Nested disables"); GC_sig_disabled++;# endif SIGSETMASK(old_mask,new_mask);}void GC_enable_signals(void){# ifdef CHECK_SIGNALS if (GC_sig_disabled != 1) ABORT("Unmatched enable"); GC_sig_disabled--;# endif SIGSETMASK(dummy,old_mask);}# endif /* !PCR */# endif /*!OS/2 *//* Ivan Demakov: simplest way (to me) */#if defined (DOS4GW) void GC_disable_signals() { } void GC_enable_signals() { }#endif/* Find the page size */word GC_page_size;# if defined(MSWIN32) || defined(MSWINCE) void GC_setpagesize(void) { GetSystemInfo(&GC_sysinfo); GC_page_size = GC_sysinfo.dwPageSize; }# else# if defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(USE_MMAP) void GC_setpagesize(void) { GC_page_size = GETPAGESIZE(); }# else /* It's acceptable to fake it. */ void GC_setpagesize(void) { GC_page_size = HBLKSIZE; }# endif# endif/* * Find the base of the stack. * Used only in single-threaded environment. * With threads, GC_mark_roots needs to know how to do this. * Called with allocator lock held. */# if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)# define is_writable(prot) ((prot) == PAGE_READWRITE \ || (prot) == PAGE_WRITECOPY \ || (prot) == PAGE_EXECUTE_READWRITE \ || (prot) == PAGE_EXECUTE_WRITECOPY)/* Return the number of bytes that are writable starting at p. *//* The pointer p is assumed to be page aligned. *//* If base is not 0, *base becomes the beginning of the *//* allocation region containing p. */word GC_get_writable_length(ptr_t p, ptr_t *base){ MEMORY_BASIC_INFORMATION buf; word result; word protect; result = VirtualQuery(p, &buf, sizeof(buf)); if (result != sizeof(buf)) ABORT("Weird VirtualQuery result"); if (base != 0) *base = (ptr_t)(buf.AllocationBase); protect = (buf.Protect & ~(PAGE_GUARD | PAGE_NOCACHE)); if (!is_writable(protect)) { return(0); } if (buf.State != MEM_COMMIT) return(0); return(buf.RegionSize);}int GC_get_stack_base(struct GC_stack_base *sb){ int dummy; ptr_t sp = (ptr_t)(&dummy); ptr_t trunc_sp = (ptr_t)((word)sp & ~(GC_page_size - 1)); word size = GC_get_writable_length(trunc_sp, 0); sb -> mem_base = trunc_sp + size; return GC_SUCCESS;}#define HAVE_GET_STACK_BASE/* This is always called from the main thread. */ptr_t GC_get_main_stack_base(void){ struct GC_stack_base sb; GC_get_stack_base(&sb); return (ptr_t)sb.mem_base;}# endif /* MS Windows */# ifdef BEOS# include <kernel/OS.h>ptr_t GC_get_main_stack_base(void){ thread_info th; get_thread_info(find_thread(NULL),&th); return th.stack_end;}# endif /* BEOS */# ifdef OS2ptr_t GC_get_main_stack_base(void){ PTIB ptib; PPIB ppib; if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) { GC_err_printf("DosGetInfoBlocks failed\n"); ABORT("DosGetInfoBlocks failed\n"); } return((ptr_t)(ptib -> tib_pstacklimit));}# endif /* OS2 */# ifdef AMIGA# define GC_AMIGA_SB# include "AmigaOS.c"# undef GC_AMIGA_SB# endif /* AMIGA */# if defined(NEED_FIND_LIMIT) || defined(UNIX_LIKE) typedef void (*handler)(int);# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) \ || defined(HURD) || defined(NETBSD) static struct sigaction old_segv_act;# if defined(_sigargs) /* !Irix6.x */ || defined(HPUX) \ || defined(HURD) || defined(NETBSD) static struct sigaction old_bus_act;# endif# else static handler old_segv_handler, old_bus_handler;# endif void GC_set_and_save_fault_handler(handler h) {# if defined(SUNOS5SIGS) || defined(IRIX5) \ || defined(OSF1) || defined(HURD) || defined(NETBSD) struct sigaction act; act.sa_handler = h;# if 0 /* Was necessary for Solaris 2.3 and very temporary */ /* NetBSD bugs. */ act.sa_flags = SA_RESTART | SA_NODEFER;# else act.sa_flags = SA_RESTART;# endif (void) sigemptyset(&act.sa_mask);# ifdef GC_IRIX_THREADS /* Older versions have a bug related to retrieving and */ /* and setting a handler at the same time. */ (void) sigaction(SIGSEGV, 0, &old_segv_act); (void) sigaction(SIGSEGV, &act, 0);# else (void) sigaction(SIGSEGV, &act, &old_segv_act);# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \ || defined(HPUX) || defined(HURD) || defined(NETBSD) /* Under Irix 5.x or HP/UX, we may get SIGBUS. */ /* Pthreads doesn't exist under Irix 5.x, so we */ /* don't have to worry in the threads case. */ (void) sigaction(SIGBUS, &act, &old_bus_act);# endif# endif /* GC_IRIX_THREADS */# else old_segv_handler = signal(SIGSEGV, h);# ifdef SIGBUS old_bus_handler = signal(SIGBUS, h);# endif# endif }# endif /* NEED_FIND_LIMIT || UNIX_LIKE */# if defined(NEED_FIND_LIMIT) || \ defined(USE_PROC_FOR_LIBRARIES) && defined(THREADS) /* Some tools to implement HEURISTIC2 */# define MIN_PAGE_SIZE 256 /* Smallest conceivable page size, bytes */ /*ARGSUSED*/ void GC_fault_handler(int sig) { LONGJMP(GC_jmp_buf, 1); } void GC_setup_temporary_fault_handler(void) { /* Handler is process-wide, so this should only happen in */ /* one thread at a time. */ GC_ASSERT(I_HOLD_LOCK()); GC_set_and_save_fault_handler(GC_fault_handler); } void GC_reset_fault_handler(void) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -