📄 pthread_support.c
字号:
GC_release_mark_lock();# endif GC_remove_all_threads_but_me();# ifdef PARALLEL_MARK /* Turn off parallel marking in the child, since we are probably */ /* just going to exec, and we would have to restart mark threads. */ GC_markers = 1; GC_parallel = FALSE;# endif /* PARALLEL_MARK */ UNLOCK();}#endif /* HANDLE_FORK */#if defined(GC_DGUX386_THREADS)/* Return the number of processors, or i<= 0 if it can't be determined. */int GC_get_nprocs(){ /* <takis@XFree86.Org> */ int numCpus; struct dg_sys_info_pm_info pm_sysinfo; int status =0; status = dg_sys_info((long int *) &pm_sysinfo, DG_SYS_INFO_PM_INFO_TYPE, DG_SYS_INFO_PM_CURRENT_VERSION); if (status < 0) /* set -1 for error */ numCpus = -1; else /* Active CPUs */ numCpus = pm_sysinfo.idle_vp_count;# ifdef DEBUG_THREADS GC_printf1("Number of active CPUs in this system: %d\n", numCpus);# endif return(numCpus);}#endif /* GC_DGUX386_THREADS *//* We hold the allocation lock. */void GC_thr_init(){# ifndef GC_DARWIN_THREADS int dummy;# endif GC_thread t; if (GC_thr_initialized) return; GC_thr_initialized = TRUE; # ifdef HANDLE_FORK /* Prepare for a possible fork. */ pthread_atfork(GC_fork_prepare_proc, GC_fork_parent_proc, GC_fork_child_proc);# endif /* HANDLE_FORK */ /* Add the initial thread, so we can stop it. */ t = GC_new_thread(pthread_self());# ifdef GC_DARWIN_THREADS t -> stop_info.mach_thread = mach_thread_self();# else t -> stop_info.stack_ptr = (ptr_t)(&dummy);# endif t -> flags = DETACHED | MAIN_THREAD; GC_stop_init(); /* Set GC_nprocs. */ { char * nprocs_string = GETENV("GC_NPROCS"); GC_nprocs = -1; if (nprocs_string != NULL) GC_nprocs = atoi(nprocs_string); } if (GC_nprocs <= 0) {# if defined(GC_HPUX_THREADS) GC_nprocs = pthread_num_processors_np();# endif# if defined(GC_OSF1_THREADS) || defined(GC_AIX_THREADS) GC_nprocs = sysconf(_SC_NPROCESSORS_ONLN); if (GC_nprocs <= 0) GC_nprocs = 1;# endif# if defined(GC_IRIX_THREADS) GC_nprocs = sysconf(_SC_NPROC_ONLN); if (GC_nprocs <= 0) GC_nprocs = 1;# endif# if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS) int ncpus = 1; size_t len = sizeof(ncpus); sysctl((int[2]) {CTL_HW, HW_NCPU}, 2, &ncpus, &len, NULL, 0); GC_nprocs = ncpus;# endif# if defined(GC_LINUX_THREADS) || defined(GC_DGUX386_THREADS) GC_nprocs = GC_get_nprocs();# endif } if (GC_nprocs <= 0) { WARN("GC_get_nprocs() returned %ld\n", GC_nprocs); GC_nprocs = 2;# ifdef PARALLEL_MARK GC_markers = 1;# endif } else {# ifdef PARALLEL_MARK { char * markers_string = GETENV("GC_MARKERS"); if (markers_string != NULL) { GC_markers = atoi(markers_string); } else { GC_markers = GC_nprocs; } }# endif }# ifdef PARALLEL_MARK# ifdef CONDPRINT if (GC_print_stats) { GC_printf2("Number of processors = %ld, " "number of marker threads = %ld\n", GC_nprocs, GC_markers); }# endif if (GC_markers == 1) { GC_parallel = FALSE;# ifdef CONDPRINT if (GC_print_stats) { GC_printf0("Single marker thread, turning off parallel marking\n"); }# endif } else { GC_parallel = TRUE; /* Disable true incremental collection, but generational is OK. */ GC_time_limit = GC_TIME_UNLIMITED; } /* If we are using a parallel marker, actually start helper threads. */ if (GC_parallel) start_mark_threads();# endif}/* Perform all initializations, including those that *//* may require allocation. *//* Called without allocation lock. *//* Must be called before a second thread is created. *//* Called without allocation lock. */void GC_init_parallel(){ if (parallel_initialized) return; parallel_initialized = TRUE; /* GC_init() calls us back, so set flag first. */ if (!GC_is_initialized) GC_init(); /* Initialize thread local free lists if used. */# if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL) LOCK(); GC_init_thread_local(GC_lookup_thread(pthread_self())); UNLOCK();# endif}#if !defined(GC_DARWIN_THREADS)int WRAP_FUNC(pthread_sigmask)(int how, const sigset_t *set, sigset_t *oset){ sigset_t fudged_set; if (set != NULL && (how == SIG_BLOCK || how == SIG_SETMASK)) { fudged_set = *set; sigdelset(&fudged_set, SIG_SUSPEND); set = &fudged_set; } return(REAL_FUNC(pthread_sigmask)(how, set, oset));}#endif /* !GC_DARWIN_THREADS *//* Wrappers for functions that are likely to block for an appreciable *//* length of time. Must be called in pairs, if at all. *//* Nothing much beyond the system call itself should be executed *//* between these. */void GC_start_blocking(void) {# define SP_SLOP 128 GC_thread me; LOCK(); me = GC_lookup_thread(pthread_self()); GC_ASSERT(!(me -> thread_blocked));# ifdef SPARC me -> stop_info.stack_ptr = (ptr_t)GC_save_regs_in_stack();# else# ifndef GC_DARWIN_THREADS me -> stop_info.stack_ptr = (ptr_t)GC_approx_sp();# endif# endif# ifdef IA64 me -> backing_store_ptr = (ptr_t)GC_save_regs_in_stack() + SP_SLOP;# endif /* Add some slop to the stack pointer, since the wrapped call may */ /* end up pushing more callee-save registers. */# ifndef GC_DARWIN_THREADS# ifdef STACK_GROWS_UP me -> stop_info.stack_ptr += SP_SLOP;# else me -> stop_info.stack_ptr -= SP_SLOP;# endif# endif me -> thread_blocked = TRUE; UNLOCK();}void GC_end_blocking(void) { GC_thread me; LOCK(); /* This will block if the world is stopped. */ me = GC_lookup_thread(pthread_self()); GC_ASSERT(me -> thread_blocked); me -> thread_blocked = FALSE; UNLOCK();} #if defined(GC_DGUX386_THREADS)#define __d10_sleep sleep#endif /* GC_DGUX386_THREADS *//* A wrapper for the standard C sleep function */int WRAP_FUNC(sleep) (unsigned int seconds){ int result; GC_start_blocking(); result = REAL_FUNC(sleep)(seconds); GC_end_blocking(); return result;}struct start_info { void *(*start_routine)(void *); void *arg; word flags; sem_t registered; /* 1 ==> in our thread table, but */ /* parent hasn't yet noticed. */};/* Called at thread exit. *//* Never called for main thread. That's OK, since it *//* results in at most a tiny one-time leak. And *//* linuxthreads doesn't reclaim the main threads *//* resources or id anyway. */void GC_thread_exit_proc(void *arg){ GC_thread me; LOCK(); me = GC_lookup_thread(pthread_self()); GC_destroy_thread_local(me); if (me -> flags & DETACHED) { GC_delete_thread(pthread_self()); } else { me -> flags |= FINISHED; }# if defined(THREAD_LOCAL_ALLOC) && !defined(USE_PTHREAD_SPECIFIC) \ && !defined(USE_COMPILER_TLS) && !defined(DBG_HDRS_ALL) GC_remove_specific(GC_thread_key);# endif /* The following may run the GC from "nonexistent" thread. */ GC_wait_for_gc_completion(FALSE); UNLOCK();}int WRAP_FUNC(pthread_join)(pthread_t thread, void **retval){ int result; GC_thread thread_gc_id; LOCK(); thread_gc_id = GC_lookup_thread(thread); /* This is guaranteed to be the intended one, since the thread id */ /* cant have been recycled by pthreads. */ UNLOCK(); result = REAL_FUNC(pthread_join)(thread, retval);# if defined (GC_FREEBSD_THREADS) /* On FreeBSD, the wrapped pthread_join() sometimes returns (what appears to be) a spurious EINTR which caused the test and real code to gratuitously fail. Having looked at system pthread library source code, I see how this return code may be generated. In one path of code, pthread_join() just returns the errno setting of the thread being joined. This does not match the POSIX specification or the local man pages thus I have taken the liberty to catch this one spurious return value properly conditionalized on GC_FREEBSD_THREADS. */ if (result == EINTR) result = 0;# endif if (result == 0) { LOCK(); /* Here the pthread thread id may have been recycled. */ GC_delete_gc_thread(thread, thread_gc_id); UNLOCK(); } return result;}intWRAP_FUNC(pthread_detach)(pthread_t thread){ int result; GC_thread thread_gc_id; LOCK(); thread_gc_id = GC_lookup_thread(thread); UNLOCK(); result = REAL_FUNC(pthread_detach)(thread); if (result == 0) { LOCK(); thread_gc_id -> flags |= DETACHED; /* Here the pthread thread id may have been recycled. */ if (thread_gc_id -> flags & FINISHED) { GC_delete_gc_thread(thread, thread_gc_id); } UNLOCK(); } return result;}GC_bool GC_in_thread_creation = FALSE;void * GC_start_routine(void * arg){ int dummy; struct start_info * si = arg; void * result; GC_thread me; pthread_t my_pthread; void *(*start)(void *); void *start_arg; my_pthread = pthread_self();# ifdef DEBUG_THREADS GC_printf1("Starting thread 0x%lx\n", my_pthread); GC_printf1("pid = %ld\n", (long) getpid()); GC_printf1("sp = 0x%lx\n", (long) &arg);# endif LOCK(); GC_in_thread_creation = TRUE; me = GC_new_thread(my_pthread); GC_in_thread_creation = FALSE;#ifdef GC_DARWIN_THREADS me -> stop_info.mach_thread = mach_thread_self();#else me -> stop_info.stack_ptr = 0;#endif me -> flags = si -> flags; /* me -> stack_end = GC_linux_stack_base(); -- currently (11/99) */ /* doesn't work because the stack base in /proc/self/stat is the */ /* one for the main thread. There is a strong argument that that's */ /* a kernel bug, but a pervasive one. */# ifdef STACK_GROWS_DOWN me -> stack_end = (ptr_t)(((word)(&dummy) + (GC_page_size - 1)) & ~(GC_page_size - 1));# ifndef GC_DARWIN_THREADS me -> stop_info.stack_ptr = me -> stack_end - 0x10;# endif /* Needs to be plausible, since an asynchronous stack mark */ /* should not crash. */# else me -> stack_end = (ptr_t)((word)(&dummy) & ~(GC_page_size - 1)); me -> stop_info.stack_ptr = me -> stack_end + 0x10;# endif /* This is dubious, since we may be more than a page into the stack, */ /* and hence skip some of it, though it's not clear that matters. */# ifdef IA64 me -> backing_store_end = (ptr_t) (GC_save_regs_in_stack() & ~(GC_page_size - 1)); /* This is also < 100% convincing. We should also read this */ /* from /proc, but the hook to do so isn't there yet. */# endif /* IA64 */ UNLOCK(); start = si -> start_routine;# ifdef DEBUG_THREADS GC_printf1("start_routine = 0x%lx\n", start);# endif start_arg = si -> arg; sem_post(&(si -> registered)); /* Last action on si. */ /* OK to deallocate. */ pthread_cleanup_push(GC_thread_exit_proc, 0);# if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL) LOCK(); GC_init_thread_local(me); UNLOCK();# endif result = (*start)(start_arg);#if DEBUG_THREADS GC_printf1("Finishing thread 0x%x\n", pthread_self());#endif me -> status = result; pthread_cleanup_pop(1); /* Cleanup acquires lock, ensuring that we can't exit */ /* while a collection that thinks we're alive is trying to stop */ /* us. */ return(result);}intWRAP_FUNC(pthread_create)(pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg){ int result;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -