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

📄 aix_irix_threads.c

📁 A garbage collector for C and C
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved. * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved. * Copyright (c) 1999-2003 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 for Irix (>=6.2) Pthreads and for AIX pthreads. * This relies on properties * not guaranteed by the Pthread standard.  It may or may not be portable * to other implementations. * * Note that there is a lot of code duplication between this file and * (pthread_support.c, pthread_stop_world.c).  They should be merged. * Pthread_support.c should be directly usable. * * Please avoid adding new ports here; use the generic pthread support * as a base instead. */# include "private/gc_priv.h"# if defined(GC_IRIX_THREADS) || defined(GC_AIX_THREADS)# include <pthread.h># include <assert.h># include <semaphore.h># include <time.h># include <errno.h># include <unistd.h># include <sys/mman.h># include <sys/time.h>#undef pthread_create#undef pthread_sigmask#undef pthread_join#if defined(GC_IRIX_THREADS) && !defined(MUTEX_RECURSIVE_NP)#define MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE#endifvoid GC_thr_init();#if 0void GC_print_sig_mask(){    sigset_t blocked;    int i;    if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)    	ABORT("pthread_sigmask");    GC_printf0("Blocked: ");    for (i = 1; i <= MAXSIG; i++) {        if (sigismember(&blocked, i)) { GC_printf1("%ld ",(long) i); }    }    GC_printf0("\n");}#endif/* We use the allocation lock to protect thread-related data structures. *//* The set of all known threads.  We intercept thread creation and 	*//* joins.  We never actually create detached threads.  We allocate all 	*//* new thread stacks ourselves.  These allow us to maintain this	*//* data structure.							*//* Protected by GC_thr_lock.						*//* Some of this should be declared volatile, but that's incosnsistent	*//* with some library routine declarations.  		 		*/typedef struct GC_Thread_Rep {    struct GC_Thread_Rep * next;  /* More recently allocated threads	*/				  /* with a given pthread id come 	*/				  /* first.  (All but the first are	*/				  /* guaranteed to be dead, but we may  */				  /* not yet have registered the join.) */    pthread_t id;    word stop;#	define NOT_STOPPED 0#	define PLEASE_STOP 1#	define STOPPED 2    word flags;#	define FINISHED 1   	/* Thread has exited.	*/#	define DETACHED 2	/* Thread is intended to be detached.	*/    ptr_t stack_cold;		/* cold end of the stack		*/    ptr_t stack_hot;  		/* Valid only when stopped. */				/* But must be within stack region at	*/				/* all times.				*/    void * status;		/* Used only to avoid premature 	*/				/* reclamation of any data it might 	*/				/* reference.				*/} * GC_thread;GC_thread GC_lookup_thread(pthread_t id);/* * The only way to suspend threads given the pthread interface is to send * signals.  Unfortunately, this means we have to reserve * a signal, and intercept client calls to change the signal mask. */#if 0 /* DOB: 6.1 */# if defined(GC_AIX_THREADS)#   define SIG_SUSPEND SIGUSR1# else#   define SIG_SUSPEND (SIGRTMIN + 6)# endif#endifpthread_mutex_t GC_suspend_lock = PTHREAD_MUTEX_INITIALIZER;				/* Number of threads stopped so far	*/pthread_cond_t GC_suspend_ack_cv = PTHREAD_COND_INITIALIZER;pthread_cond_t GC_continue_cv = PTHREAD_COND_INITIALIZER;void GC_suspend_handler(int sig){    int dummy;    GC_thread me;    sigset_t all_sigs;    sigset_t old_sigs;    int i;    if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");    me = GC_lookup_thread(pthread_self());    /* The lookup here is safe, since I'm doing this on behalf  */    /* of a thread which holds the allocation lock in order	*/    /* to stop the world.  Thus concurrent modification of the	*/    /* data structure is impossible.				*/    if (PLEASE_STOP != me -> stop) {	/* Misdirected signal.	*/	pthread_mutex_unlock(&GC_suspend_lock);	return;    }    pthread_mutex_lock(&GC_suspend_lock);    me -> stack_hot = (ptr_t)(&dummy);    me -> stop = STOPPED;    pthread_cond_signal(&GC_suspend_ack_cv);    pthread_cond_wait(&GC_continue_cv, &GC_suspend_lock);    pthread_mutex_unlock(&GC_suspend_lock);    /* GC_printf1("Continuing 0x%x\n", pthread_self()); */}GC_bool GC_thr_initialized = FALSE;# define THREAD_TABLE_SZ 128	/* Must be power of 2	*/volatile GC_thread GC_threads[THREAD_TABLE_SZ];void GC_push_thread_structures GC_PROTO((void)){    GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));}/* 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 = ((word)id) % THREAD_TABLE_SZ;    GC_thread result;    static struct GC_Thread_Rep first_thread;    static GC_bool first_thread_used = FALSE;        GC_ASSERT(I_HOLD_LOCK());    if (!first_thread_used) {    	result = &first_thread;    	first_thread_used = TRUE;    	/* Dont acquire allocation lock, since we may already hold it. */    } else {        result = (struct GC_Thread_Rep *)        	 GC_generic_malloc_inner(sizeof(struct GC_Thread_Rep), NORMAL);    }    if (result == 0) return(0);    result -> id = id;    result -> next = GC_threads[hv];    GC_threads[hv] = result;    /* result -> flags = 0;     */    /* result -> stop = 0;	*/    return(result);}/* Delete a thread from GC_threads.  We assume it is there.	*//* (The code intentionally traps if it wasn't.)			*//* Caller holds allocation lock.				*//* We explicitly pass in the GC_thread we're looking for, since *//* 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(pthread_t id, GC_thread gc_id){    int hv = ((word)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;    }}/* Return a GC_thread corresponding to a given thread_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 = ((word)id) % THREAD_TABLE_SZ;    register GC_thread p = GC_threads[hv];        /* I either hold the lock, or i'm being called from the stop-the-world     * handler. */#if defined(GC_AIX_THREADS)    GC_ASSERT(I_HOLD_LOCK()); /* no stop-the-world handler needed on AIX */#endif    while (p != 0 && !pthread_equal(p -> id, id)) p = p -> next;    return(p);}#if defined(GC_AIX_THREADS)void GC_stop_world(){    pthread_t my_thread = pthread_self();    register int i;    register GC_thread p;    register int result;    struct timespec timeout;    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 -> id != my_thread) {          pthread_suspend_np(p->id);        }      }    }    /* GC_printf1("World stopped 0x%x\n", pthread_self()); */}void GC_start_world(){    GC_thread p;    unsigned i;    pthread_t my_thread = pthread_self();    /* GC_printf0("World starting\n"); */    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 -> id != my_thread) {          pthread_continue_np(p->id);        }      }    }}#else /* GC_AIX_THREADS *//* Caller holds allocation lock.	*/void GC_stop_world(){    pthread_t my_thread = pthread_self();    register int i;    register GC_thread p;    register int result;    struct timespec timeout;        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 -> id != my_thread) {            if (p -> flags & FINISHED) {		p -> stop = STOPPED;		continue;	    }	    p -> stop = PLEASE_STOP;            result = pthread_kill(p -> id, SIG_SUSPEND);	    /* GC_printf1("Sent signal to 0x%x\n", p -> id); */	    switch(result) {                case ESRCH:                    /* Not really there anymore.  Possible? */                    p -> stop = STOPPED;                    break;                case 0:                    break;                default:                    ABORT("pthread_kill failed");            }        }      }    }    pthread_mutex_lock(&GC_suspend_lock);    for (i = 0; i < THREAD_TABLE_SZ; i++) {      for (p = GC_threads[i]; p != 0; p = p -> next) {        while (p -> id != my_thread && p -> stop != STOPPED) {	    clock_gettime(CLOCK_REALTIME, &timeout);            timeout.tv_nsec += 50000000; /* 50 msecs */            if (timeout.tv_nsec >= 1000000000) {                timeout.tv_nsec -= 1000000000;                ++timeout.tv_sec;            }            result = pthread_cond_timedwait(&GC_suspend_ack_cv,					    &GC_suspend_lock,                                            &timeout);            if (result == ETIMEDOUT) {                /* Signal was lost or misdirected.  Try again.      */                /* Duplicate signals should be benign.              */                result = pthread_kill(p -> id, SIG_SUSPEND);	    }	}      }    }    pthread_mutex_unlock(&GC_suspend_lock);    /* GC_printf1("World stopped 0x%x\n", pthread_self()); */}/* Caller holds allocation lock.	*/void GC_start_world(){    GC_thread p;    unsigned i;    /* GC_printf0("World starting\n"); */    GC_ASSERT(I_HOLD_LOCK());    for (i = 0; i < THREAD_TABLE_SZ; i++) {      for (p = GC_threads[i]; p != 0; p = p -> next) {	p -> stop = NOT_STOPPED;      }    }    pthread_mutex_lock(&GC_suspend_lock);    /* All other threads are at pthread_cond_wait in signal handler.	*/    /* Otherwise we couldn't have acquired the lock.			*/

⌨️ 快捷键说明

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