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

📄 pthread_support.c

📁 Boost provides free peer-reviewed portable C++ source libraries. We emphasize libraries that work
💻 C
📖 第 1 页 / 共 3 页
字号:
/*  * Copyright (c) 1994 by Xerox Corporation.  All rights reserved. * Copyright (c) 1996 by Silicon Graphics.  All rights reserved. * Copyright (c) 1998 by Fergus Henderson.  All rights reserved. * Copyright (c) 2000-2005 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. *//* * Support code originally for LinuxThreads, the clone()-based kernel * thread package for Linux which is included in libc6. * * This code no doubt makes some assumptions beyond what is * guaranteed by the pthread standard, though it now does * very little of that.  It now also supports NPTL, and many * other Posix thread implementations.  We are trying to merge * all flavors of pthread dupport code into this file. */ /* DG/UX ix86 support <takis@xfree86.org> *//* * Linux_threads.c now also includes some code to support HPUX and * OSF1 (Compaq Tru64 Unix, really).  The OSF1 support is based on Eric Benson's * patch. * * Eric also suggested an alternate basis for a lock implementation in * his code: * + #elif defined(OSF1) * +    unsigned long GC_allocate_lock = 0; * +    msemaphore GC_allocate_semaphore; * + #  define GC_TRY_LOCK() \ * +    ((msem_lock(&GC_allocate_semaphore, MSEM_IF_NOWAIT) == 0) \ * +     ? (GC_allocate_lock = 1) \ * +     : 0) * + #  define GC_LOCK_TAKEN GC_allocate_lock *//*#define DEBUG_THREADS 1*/# include "private/pthread_support.h"# if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS)# if defined(GC_DGUX386_THREADS) && !defined(_POSIX4A_DRAFT10_SOURCE)#   define _POSIX4A_DRAFT10_SOURCE 1# endif# if defined(GC_DGUX386_THREADS) && !defined(_USING_POSIX4A_DRAFT10)#   define _USING_POSIX4A_DRAFT10 1# endif# include <stdlib.h># include <pthread.h># include <sched.h># include <time.h># include <errno.h># include <unistd.h># include <sys/mman.h># include <sys/time.h># include <sys/types.h># include <sys/stat.h># include <fcntl.h># include <signal.h># include "gc_inline.h"#if defined(GC_DARWIN_THREADS)# include "private/darwin_semaphore.h"#else# include <semaphore.h>#endif /* !GC_DARWIN_THREADS */#if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS)# include <sys/sysctl.h>#endif /* GC_DARWIN_THREADS */#if defined(GC_NETBSD_THREADS)# include <sys/param.h># include <sys/sysctl.h>#endif        /* GC_NETBSD_THREADS *//* Allocator lock definitions.		*/#if !defined(USE_SPIN_LOCK)  pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;#endifunsigned long GC_lock_holder = NO_THREAD;		/* Used only for assertions, and to prevent	 */		/* recursive reentry in the system call wrapper. */#if defined(GC_DGUX386_THREADS)# include <sys/dg_sys_info.h># include <sys/_int_psem.h>  /* sem_t is an uint in DG/UX */  typedef unsigned int  sem_t;#endif /* GC_DGUX386_THREADS */#ifndef __GNUC__#   define __inline__#endif/* Undefine macros used to redirect pthread primitives. */# undef pthread_create# if !defined(GC_DARWIN_THREADS)#   undef pthread_sigmask# endif# undef pthread_join# undef pthread_detach# if defined(GC_OSF1_THREADS) && defined(_PTHREAD_USE_MANGLED_NAMES_) \     && !defined(_PTHREAD_USE_PTDNAM_)  /* Restore the original mangled names on Tru64 UNIX.  */#   define pthread_create __pthread_create#   define pthread_join __pthread_join#   define pthread_detach __pthread_detach# endif#ifdef GC_USE_LD_WRAP#   define WRAP_FUNC(f) __wrap_##f#   define REAL_FUNC(f) __real_##f#else#   ifdef GC_USE_DLOPEN_WRAP#     include <dlfcn.h>#     define WRAP_FUNC(f) f#     define REAL_FUNC(f) GC_real_##f      /* We define both GC_f and plain f to be the wrapped function.	*/      /* In that way plain calls work, as do calls from files that	*/      /* included gc.h, wich redefined f to GC_f.			*/      /* FIXME: Needs work for DARWIN and True64 (OSF1) */      typedef int (* GC_pthread_create_t)(pthread_t *, const pthread_attr_t *,		      		          void * (*)(void *), void *);      static GC_pthread_create_t GC_real_pthread_create;      typedef int (* GC_pthread_sigmask_t)(int, const sigset_t *, sigset_t *);      static GC_pthread_sigmask_t GC_real_pthread_sigmask;      typedef int (* GC_pthread_join_t)(pthread_t, void **);      static GC_pthread_join_t GC_real_pthread_join;      typedef int (* GC_pthread_detach_t)(pthread_t);      static GC_pthread_detach_t GC_real_pthread_detach;#   else#     define WRAP_FUNC(f) GC_##f#     if !defined(GC_DGUX386_THREADS)#       define REAL_FUNC(f) f#     else /* GC_DGUX386_THREADS */#       define REAL_FUNC(f) __d10_##f#     endif /* GC_DGUX386_THREADS */#   endif#endif#if defined(GC_USE_DL_WRAP) || defined(GC_USE_DLOPEN_WRAP)/* Define GC_ functions as aliases for the plain ones, which will	*//* be intercepted.  This allows files which include gc.h, and hence	*//* generate referemces to the GC_ symbols, to see the right symbols.	*/      int GC_pthread_create(pthread_t * t, const pthread_attr_t * a,		         void * (* fn)(void *), void * arg) {	  return pthread_create(t, a, fn, arg);      }      int GC_pthread_sigmask(int how, const sigset_t *mask, sigset_t *old) {	  return pthread_sigmask(how, mask, old);      }      int GC_pthread_join(pthread_t t, void **res) {	  return pthread_join(t, res);      }      int GC_pthread_detach(pthread_t t) {	  return pthread_detach(t);      }#endif /* Linker-based interception. */#ifdef GC_USE_DLOPEN_WRAP  static GC_bool GC_syms_initialized = FALSE;  void GC_init_real_syms(void)  {    void *dl_handle;#   define LIBPTHREAD_NAME "libpthread.so.0"#   define LIBPTHREAD_NAME_LEN 16 /* incl. trailing 0 */    size_t len = LIBPTHREAD_NAME_LEN - 1;    char namebuf[LIBPTHREAD_NAME_LEN];    static char *libpthread_name = LIBPTHREAD_NAME;    if (GC_syms_initialized) return;#   ifdef RTLD_NEXT      dl_handle = RTLD_NEXT;#   else      dl_handle = dlopen(libpthread_name, RTLD_LAZY);      if (NULL == dl_handle) {        while (isdigit(libpthread_name[len-1])) --len;        if (libpthread_name[len-1] == '.') --len;        memcpy(namebuf, libpthread_name, len);        namebuf[len] = '\0';        dl_handle = dlopen(namebuf, RTLD_LAZY);      }      if (NULL == dl_handle) ABORT("Couldn't open libpthread\n");#   endif    GC_real_pthread_create = (GC_pthread_create_t)	    			dlsym(dl_handle, "pthread_create");    GC_real_pthread_sigmask = (GC_pthread_sigmask_t)	    			dlsym(dl_handle, "pthread_sigmask");    GC_real_pthread_join = (GC_pthread_join_t)	    			dlsym(dl_handle, "pthread_join");    GC_real_pthread_detach = (GC_pthread_detach_t)	    			dlsym(dl_handle, "pthread_detach");    GC_syms_initialized = TRUE;  }# define INIT_REAL_SYMS() if (!GC_syms_initialized) GC_init_real_syms();#else# define INIT_REAL_SYMS()#endifvoid GC_thr_init(void);static GC_bool parallel_initialized = FALSE;GC_bool GC_need_to_lock = FALSE;void GC_init_parallel(void);long GC_nprocs = 1;	/* Number of processors.  We may not have	*/			/* access to all of them, but this is as good	*/			/* a guess as any ...				*/#ifdef THREAD_LOCAL_ALLOC/* We must explicitly mark ptrfree and gcj free lists, since the free 	*//* list links wouldn't otherwise be found.  We also set them in the 	*//* normal free lists, since that involves touching less memory than if	*//* we scanned them normally.						*/void GC_mark_thread_local_free_lists(void){    int i;    GC_thread p;        for (i = 0; i < THREAD_TABLE_SZ; ++i) {      for (p = GC_threads[i]; 0 != p; p = p -> next) {	GC_mark_thread_local_fls_for(&(p->tlfs));      }    }}#if defined(GC_ASSERTIONS)    /* Check that all thread-local free-lists are completely marked.	*/    /* also check that thread-specific-data structures are marked.	*/    void GC_check_tls(void) {	int i;	GC_thread p;		for (i = 0; i < THREAD_TABLE_SZ; ++i) {	  for (p = GC_threads[i]; 0 != p; p = p -> next) {	    GC_check_tls_for(&(p->tlfs));	  }	}#       if defined(USE_CUSTOM_SPECIFIC)	  if (GC_thread_key != 0)	    GC_check_tsd_marks(GC_thread_key);#	endif     }#endif /* GC_ASSERTIONS */#endif /* Thread_local_alloc */#ifdef PARALLEL_MARK# ifndef MAX_MARKERS#   define MAX_MARKERS 16# endifstatic ptr_t marker_sp[MAX_MARKERS] = {0};#ifdef IA64  static ptr_t marker_bsp[MAX_MARKERS] = {0};#endifvoid * GC_mark_thread(void * id){  word my_mark_no = 0;  marker_sp[(word)id] = GC_approx_sp();# ifdef IA64    marker_bsp[(word)id] = GC_save_regs_in_stack();# endif  for (;; ++my_mark_no) {    /* GC_mark_no is passed only to allow GC_help_marker to terminate	*/    /* promptly.  This is important if it were called from the signal	*/    /* handler or from the GC lock acquisition code.  Under Linux, it's	*/    /* not safe to call it from a signal handler, since it uses mutexes	*/    /* and condition variables.  Since it is called only here, the 	*/    /* argument is unnecessary.						*/    if (my_mark_no < GC_mark_no || my_mark_no > GC_mark_no + 2) {	/* resynchronize if we get far off, e.g. because GC_mark_no	*/	/* wrapped.							*/	my_mark_no = GC_mark_no;    }#   ifdef DEBUG_THREADS	GC_printf("Starting mark helper for mark number %lu\n", my_mark_no);#   endif    GC_help_marker(my_mark_no);  }}extern long GC_markers;		/* Number of mark threads we would	*/				/* like to have.  Includes the 		*/				/* initiating thread.			*/pthread_t GC_mark_threads[MAX_MARKERS];#define PTHREAD_CREATE REAL_FUNC(pthread_create)static void start_mark_threads(void){    unsigned i;    pthread_attr_t attr;    if (GC_markers > MAX_MARKERS) {	WARN("Limiting number of mark threads\n", 0);	GC_markers = MAX_MARKERS;    }    if (0 != pthread_attr_init(&attr)) ABORT("pthread_attr_init failed");	    if (0 != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))	ABORT("pthread_attr_setdetachstate failed");#   if defined(HPUX) || defined(GC_DGUX386_THREADS)      /* Default stack size is usually too small: fix it. */      /* Otherwise marker threads or GC may run out of	  */      /* space.						  */#     define MIN_STACK_SIZE (8*HBLKSIZE*sizeof(word))      {	size_t old_size;	int code;        if (pthread_attr_getstacksize(&attr, &old_size) != 0)	  ABORT("pthread_attr_getstacksize failed\n");	if (old_size < MIN_STACK_SIZE) {	  if (pthread_attr_setstacksize(&attr, MIN_STACK_SIZE) != 0)		  ABORT("pthread_attr_setstacksize failed\n");	}      }#   endif /* HPUX || GC_DGUX386_THREADS */    if (GC_print_stats) {	GC_log_printf("Starting %ld marker threads\n", GC_markers - 1);    }    for (i = 0; i < GC_markers - 1; ++i) {      if (0 != PTHREAD_CREATE(GC_mark_threads + i, &attr,			      GC_mark_thread, (void *)(word)i)) {	WARN("Marker thread creation failed, errno = %ld.\n", errno);      }    }}#endif /* PARALLEL_MARK */GC_bool GC_thr_initialized = FALSE;volatile GC_thread GC_threads[THREAD_TABLE_SZ];void GC_push_thread_structures(void){    GC_ASSERT(I_HOLD_LOCK());    GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));#   if defined(THREAD_LOCAL_ALLOC)      GC_push_all((ptr_t)(&GC_thread_key),	  (ptr_t)(&GC_thread_key)+sizeof(&GC_thread_key));#   endif}/* It may not be safe to allocate when we register the first thread.	*/static struct GC_Thread_Rep first_thread;/* Add a thread to GC_threads.  We assume it wasn't already there.	*//* Caller holds allocation lock.					*/GC_thread GC_new_thread(pthread_t id){    int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;    GC_thread result;    static GC_bool first_thread_used = FALSE;        GC_ASSERT(I_HOLD_LOCK());    if (!first_thread_used) {    	result = &first_thread;    	first_thread_used = TRUE;    } else {        result = (struct GC_Thread_Rep *)        	 GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);	GC_ASSERT(result -> flags == 0);    }    if (result == 0) return(0);    result -> id = id;    result -> next = GC_threads[hv];    GC_threads[hv] = result;    GC_ASSERT(result -> flags == 0 && result -> thread_blocked == 0);    return(result);}/* Delete a thread from GC_threads.  We assume it is there.	*//* (The code intentionally traps if it wasn't.)			*/void GC_delete_thread(pthread_t id){    int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;    register GC_thread p = GC_threads[hv];    register GC_thread prev = 0;        GC_ASSERT(I_HOLD_LOCK());    while (!THREAD_EQUAL(p -> id, id)) {        prev = p;        p = p -> next;    }    if (prev == 0) {        GC_threads[hv] = p -> next;    } else {        prev -> next = p -> next;    }#   ifdef GC_DARWIN_THREADS	mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread);#   endif    GC_INTERNAL_FREE(p);}/* If a thread has been joined, but we have not yet		*//* been notified, then there may be more than one thread 	*//* in the table with the same pthread id.			*//* This is OK, but we need a way to delete a specific one.	*/void GC_delete_gc_thread(GC_thread gc_id){    pthread_t id = gc_id -> id;    int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;    register GC_thread p = GC_threads[hv];    register GC_thread prev = 0;    GC_ASSERT(I_HOLD_LOCK());    while (p != gc_id) {        prev = p;        p = p -> next;    }    if (prev == 0) {        GC_threads[hv] = p -> next;    } else {        prev -> next = p -> next;    }#   ifdef GC_DARWIN_THREADS	mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread);#   endif    GC_INTERNAL_FREE(p);}/* Return a GC_thread corresponding to a given pthread_t.	*//* Returns 0 if it's not there.					*//* Caller holds  allocation lock or otherwise inhibits 		*//* updates.							*//* If there is more than one thread with the given id we 	*//* return the most recent one.					*/GC_thread GC_lookup_thread(pthread_t id){    int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;    register GC_thread p = GC_threads[hv];        while (p != 0 && !THREAD_EQUAL(p -> id, id)) p = p -> next;    return(p);}#ifdef HANDLE_FORK/* Remove all entries from the GC_threads table, except the	*//* one for the current thread.  We need to do this in the child	*//* process after a fork(), since only the current thread 	*//* survives in the child.					*/void GC_remove_all_threads_but_me(void){    pthread_t self = pthread_self();    int hv;    GC_thread p, next, me;    for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) {      me = 0;      for (p = GC_threads[hv]; 0 != p; p = next) {	next = p -> next;	if (THREAD_EQUAL(p -> id, self)) {	  me = p;	  p -> next = 0;	} else {#	  ifdef THREAD_LOCAL_ALLOC	    if (!(p -> flags & FINISHED)) {	      GC_destroy_thread_local(&(p->tlfs));	    }#	  endif /* THREAD_LOCAL_ALLOC */	  if (p != &first_thread) GC_INTERNAL_FREE(p);	}      }      GC_threads[hv] = me;    }}#endif /* HANDLE_FORK */#ifdef USE_PROC_FOR_LIBRARIESGC_bool GC_segment_is_thread_stack(ptr_t lo, ptr_t hi){    int i;    GC_thread p;    

⌨️ 快捷键说明

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