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

📄 aix_irix_threads.c

📁 A garbage collector for C and C
💻 C
📖 第 1 页 / 共 2 页
字号:
    pthread_mutex_unlock(&GC_suspend_lock);    pthread_cond_broadcast(&GC_continue_cv);}#endif /* GC_AIX_THREADS *//* We hold allocation lock.  Should do exactly the right thing if the	*//* world is stopped.  Should not fail if it isn't.			*/void GC_push_all_stacks(){    register int i;    register GC_thread p;    register ptr_t hot, cold;    pthread_t me = pthread_self();        /* GC_init() should have been called before GC_push_all_stacks is     * invoked, and GC_init calls GC_thr_init(), which sets     * GC_thr_initialized. */    GC_ASSERT(GC_thr_initialized);    /* GC_printf1("Pushing stacks from thread 0x%x\n", me); */    GC_ASSERT(I_HOLD_LOCK());    for (i = 0; i < THREAD_TABLE_SZ; i++) {      for (p = GC_threads[i]; p != 0; p = p -> next) {        if (p -> flags & FINISHED) continue;	cold = p->stack_cold;	if (!cold) cold=GC_stackbottom; /* 0 indicates 'original stack' */        if (pthread_equal(p -> id, me)) {	    hot = GC_approx_sp();	} else {#        ifdef GC_AIX_THREADS          /* AIX doesn't use signals to suspend, so we need to get an */	  /* accurate hot stack pointer.			      */	  /* See http://publib16.boulder.ibm.com/pseries/en_US/libs/basetrf1/pthread_getthrds_np.htm */          pthread_t id = p -> id;          struct __pthrdsinfo pinfo;          int regbuf[64];          int val = sizeof(regbuf);          int retval = pthread_getthrds_np(&id, PTHRDSINFO_QUERY_ALL, &pinfo,			  		   sizeof(pinfo), regbuf, &val);          if (retval != 0) {	    printf("ERROR: pthread_getthrds_np() failed in GC\n");	    abort();	  }	  /* according to the AIX ABI, 	     "the lowest possible valid stack address is 288 bytes (144 + 144)	     less than the current value of the stack pointer.  Functions may	     use this stack space as volatile storage which is not preserved	     across function calls."	     ftp://ftp.penguinppc64.org/pub/people/amodra/PPC-elf64abi.txt.gz	  */          hot = (ptr_t)(unsigned long)pinfo.__pi_ustk-288;	  cold = (ptr_t)pinfo.__pi_stackend; /* more precise */          /* push the registers too, because they won't be on stack */          GC_push_all_eager((ptr_t)&pinfo.__pi_context,			    (ptr_t)((&pinfo.__pi_context)+1));          GC_push_all_eager((ptr_t)regbuf, ((ptr_t)regbuf)+val);#	 else              hot = p -> stack_hot;#	 endif	}#	ifdef STACK_GROWS_UP          GC_push_all_stack(cold, hot);#	else /* printf("thread 0x%x: hot=0x%08x cold=0x%08x\n", p -> id, hot, cold); */          GC_push_all_stack(hot, cold);#	endif      }    }}/* We hold the allocation lock.	*/void GC_thr_init(){    GC_thread t;    struct sigaction act;    if (GC_thr_initialized) return;    GC_ASSERT(I_HOLD_LOCK());    GC_thr_initialized = TRUE;#ifndef GC_AIX_THREADS    (void) sigaction(SIG_SUSPEND, 0, &act);    if (act.sa_handler != SIG_DFL)    	ABORT("Previously installed SIG_SUSPEND handler");    /* Install handler.	*/	act.sa_handler = GC_suspend_handler;	act.sa_flags = SA_RESTART;	(void) sigemptyset(&act.sa_mask);        if (0 != sigaction(SIG_SUSPEND, &act, 0))	    ABORT("Failed to install SIG_SUSPEND handler");#endif    /* Add the initial thread, so we can stop it.	*/      t = GC_new_thread(pthread_self());      /* use '0' to indicate GC_stackbottom, since GC_init() has not       * completed by the time we are called (from GC_init_inner()) */      t -> stack_cold = 0; /* the original stack. */      t -> stack_hot = (ptr_t)(&t);      t -> flags = DETACHED;}int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset){    sigset_t fudged_set;    #ifdef GC_AIX_THREADS    return(pthread_sigmask(how, set, oset));#endif    if (set != NULL && (how == SIG_BLOCK || how == SIG_SETMASK)) {        fudged_set = *set;        sigdelset(&fudged_set, SIG_SUSPEND);        set = &fudged_set;    }    return(pthread_sigmask(how, set, oset));}struct start_info {    void *(*start_routine)(void *);    void *arg;    word flags;    pthread_mutex_t registeredlock;    pthread_cond_t registered;         int volatile registereddone;};void GC_thread_exit_proc(void *arg){    GC_thread me;    LOCK();    me = GC_lookup_thread(pthread_self());    me -> flags |= FINISHED;    /* reclaim DETACHED thread right away; otherwise wait until join() */    if (me -> flags & DETACHED) {	GC_delete_gc_thread(pthread_self(), me);    }    UNLOCK();}int GC_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();    GC_ASSERT(!(thread_gc_id->flags & DETACHED));    result = pthread_join(thread, retval);    /* Some versions of the Irix pthreads library can erroneously 	*/    /* return EINTR when the call succeeds.				*/	if (EINTR == result) result = 0;    GC_ASSERT(thread_gc_id->flags & FINISHED);    LOCK();    /* Here the pthread thread id may have been recycled. */    GC_delete_gc_thread(thread, thread_gc_id);    UNLOCK();    return result;}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();    /* If a GC occurs before the thread is registered, that GC will	*/    /* ignore this thread.  That's fine, since it will block trying to  */    /* acquire the allocation lock, and won't yet hold interesting 	*/    /* pointers.							*/    LOCK();    /* We register the thread here instead of in the parent, so that	*/    /* we don't need to hold the allocation lock during pthread_create. */    /* Holding the allocation lock there would make REDIRECT_MALLOC	*/    /* impossible.  It probably still doesn't work, but we're a little  */    /* closer ...							*/    /* This unfortunately means that we have to be careful the parent	*/    /* doesn't try to do a pthread_join before we're registered.	*/    me = GC_new_thread(my_pthread);    me -> flags = si -> flags;    me -> stack_cold = (ptr_t) &dummy; /* this now the 'start of stack' */    me -> stack_hot = me->stack_cold;/* this field should always be sensible */    UNLOCK();    start = si -> start_routine;    start_arg = si -> arg;    pthread_mutex_lock(&(si->registeredlock));    si->registereddone = 1;    pthread_cond_signal(&(si->registered));    pthread_mutex_unlock(&(si->registeredlock));    /* si went away as soon as we did this unlock */    pthread_cleanup_push(GC_thread_exit_proc, 0);    result = (*start)(start_arg);    me -> status = result;    pthread_cleanup_pop(1);	/* This involves acquiring the lock, ensuring that we can't exit */	/* while a collection that thinks we're alive is trying to stop  */	/* us.								 */    return(result);}intGC_pthread_create(pthread_t *new_thread,		  const pthread_attr_t *attr,                  void *(*start_routine)(void *), void *arg){    int result;    GC_thread t;    int detachstate;    word my_flags = 0;    struct start_info * si;    	/* This is otherwise saved only in an area mmapped by the thread */    	/* library, which isn't visible to the collector.		 */    LOCK();    /* GC_INTERNAL_MALLOC implicitly calls GC_init() if required */    si = (struct start_info *)GC_INTERNAL_MALLOC(sizeof(struct start_info),						 NORMAL);    GC_ASSERT(GC_thr_initialized); /* initialized by GC_init() */    UNLOCK();    if (0 == si) return(ENOMEM);    pthread_mutex_init(&(si->registeredlock), NULL);    pthread_cond_init(&(si->registered),NULL);    pthread_mutex_lock(&(si->registeredlock));    si -> start_routine = start_routine;    si -> arg = arg;    pthread_attr_getdetachstate(attr, &detachstate);    if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;    si -> flags = my_flags;    result = pthread_create(new_thread, attr, GC_start_routine, si);     /* Wait until child has been added to the thread table.		*/    /* This also ensures that we hold onto si until the child is done	*/    /* with it.  Thus it doesn't matter whether it is otherwise		*/    /* visible to the collector.					*/    if (0 == result) {      si->registereddone = 0;      while (!si->registereddone)         pthread_cond_wait(&(si->registered), &(si->registeredlock));    }    pthread_mutex_unlock(&(si->registeredlock));    pthread_cond_destroy(&(si->registered));    pthread_mutex_destroy(&(si->registeredlock));    LOCK();    GC_INTERNAL_FREE(si);    UNLOCK();    return(result);}/* For now we use the pthreads locking primitives on HP/UX */VOLATILE GC_bool GC_collecting = 0; /* A hint that we're in the collector and       */                        /* holding the allocation lock for an           */                        /* extended period.                             *//* Reasonably fast spin locks.  Basically the same implementation *//* as STL alloc.h.						  */#define SLEEP_THRESHOLD 3volatile unsigned int GC_allocate_lock = 0;#define GC_TRY_LOCK() !GC_test_and_set(&GC_allocate_lock)#define GC_LOCK_TAKEN GC_allocate_lockvoid GC_lock(){#   define low_spin_max 30  /* spin cycles if we suspect uniprocessor */#   define high_spin_max 1000 /* spin cycles for multiprocessor */    static unsigned spin_max = low_spin_max;    unsigned my_spin_max;    static unsigned last_spins = 0;    unsigned my_last_spins;    volatile unsigned junk;#   define PAUSE junk *= junk; junk *= junk; junk *= junk; junk *= junk    int i;    if (GC_TRY_LOCK()) {        return;    }    junk = 0;    my_spin_max = spin_max;    my_last_spins = last_spins;    for (i = 0; i < my_spin_max; i++) {        if (GC_collecting) goto yield;        if (i < my_last_spins/2 || GC_LOCK_TAKEN) {            PAUSE;             continue;        }        if (GC_TRY_LOCK()) {	    /*             * got it!             * Spinning worked.  Thus we're probably not being scheduled             * against the other process with which we were contending.             * Thus it makes sense to spin longer the next time.	     */            last_spins = i;            spin_max = high_spin_max;            return;        }    }    /* We are probably being scheduled against the other process.  Sleep. */    spin_max = low_spin_max;yield:    for (i = 0;; ++i) {        if (GC_TRY_LOCK()) {            return;        }        if (i < SLEEP_THRESHOLD) {            sched_yield();	} else {	    struct timespec ts;		    if (i > 26) i = 26;			/* Don't wait for more than about 60msecs, even	*/			/* under extreme contention.			*/	    ts.tv_sec = 0;	    ts.tv_nsec = 1 << i;	    nanosleep(&ts, 0);	}    }}# else  /* !GC_IRIX_THREADS && !GC_AIX_THREADS */#ifndef LINT  int GC_no_Irix_threads;#endif# endif /* IRIX_THREADS */

⌨️ 快捷键说明

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