mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 11:49:12 +00:00 
			
		
		
		
	svn+ssh://pythondev@svn.python.org/python/branches/py3k
................
  r81032 | antoine.pitrou | 2010-05-09 17:52:27 +0200 (dim., 09 mai 2010) | 9 lines
  Recorded merge of revisions 81029 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk
  ........
    r81029 | antoine.pitrou | 2010-05-09 16:46:46 +0200 (dim., 09 mai 2010) | 3 lines
    Untabify C files. Will watch buildbots.
  ........
................
		
	
			
		
			
				
	
	
		
			375 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			375 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
 | 
						|
#include <stdlib.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <signal.h>
 | 
						|
#include <sys/types.h>
 | 
						|
#include <sys/wait.h>
 | 
						|
#include <sys/prctl.h>
 | 
						|
#include <ulocks.h>
 | 
						|
#include <errno.h>
 | 
						|
 | 
						|
#define HDR_SIZE        2680    /* sizeof(ushdr_t) */
 | 
						|
#define MAXPROC         100     /* max # of threads that can be started */
 | 
						|
 | 
						|
static usptr_t *shared_arena;
 | 
						|
static ulock_t count_lock;      /* protection for some variables */
 | 
						|
static ulock_t wait_lock;       /* lock used to wait for other threads */
 | 
						|
static int waiting_for_threads; /* protected by count_lock */
 | 
						|
static int nthreads;            /* protected by count_lock */
 | 
						|
static int exit_status;
 | 
						|
#ifndef NO_EXIT_PROG
 | 
						|
static int do_exit;             /* indicates that the program is to exit */
 | 
						|
#endif
 | 
						|
static int exiting;             /* we're already exiting (for maybe_exit) */
 | 
						|
static pid_t my_pid;            /* PID of main thread */
 | 
						|
static struct pidlist {
 | 
						|
    pid_t parent;
 | 
						|
    pid_t child;
 | 
						|
} pidlist[MAXPROC];     /* PIDs of other threads; protected by count_lock */
 | 
						|
static int maxpidindex;         /* # of PIDs in pidlist */
 | 
						|
 | 
						|
#ifndef NO_EXIT_PROG
 | 
						|
/*
 | 
						|
 * This routine is called as a signal handler when another thread
 | 
						|
 * exits.  When that happens, we must see whether we have to exit as
 | 
						|
 * well (because of an PyThread_exit_prog()) or whether we should continue on.
 | 
						|
 */
 | 
						|
static void exit_sig(void)
 | 
						|
{
 | 
						|
    d2printf(("exit_sig called\n"));
 | 
						|
    if (exiting && getpid() == my_pid) {
 | 
						|
        d2printf(("already exiting\n"));
 | 
						|
        return;
 | 
						|
    }
 | 
						|
    if (do_exit) {
 | 
						|
        d2printf(("exiting in exit_sig\n"));
 | 
						|
#ifdef Py_DEBUG
 | 
						|
        if ((thread_debug & 8) == 0)
 | 
						|
            thread_debug &= ~1; /* don't produce debug messages */
 | 
						|
#endif
 | 
						|
        PyThread_exit_thread();
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * This routine is called when a process calls exit().  If that wasn't
 | 
						|
 * done from the library, we do as if an PyThread_exit_prog() was intended.
 | 
						|
 */
 | 
						|
static void maybe_exit(void)
 | 
						|
{
 | 
						|
    dprintf(("maybe_exit called\n"));
 | 
						|
    if (exiting) {
 | 
						|
        dprintf(("already exiting\n"));
 | 
						|
        return;
 | 
						|
    }
 | 
						|
    PyThread_exit_prog(0);
 | 
						|
}
 | 
						|
#endif /* NO_EXIT_PROG */
 | 
						|
 | 
						|
/*
 | 
						|
 * Initialization.
 | 
						|
 */
 | 
						|
static void PyThread__init_thread(void)
 | 
						|
{
 | 
						|
#ifndef NO_EXIT_PROG
 | 
						|
    struct sigaction s;
 | 
						|
#endif /* NO_EXIT_PROG */
 | 
						|
#ifdef USE_DL
 | 
						|
    long addr, size;
 | 
						|
#endif /* USE_DL */
 | 
						|
 | 
						|
 | 
						|
#ifdef USE_DL
 | 
						|
    if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
 | 
						|
        perror("usconfig - CONF_INITSIZE (check)");
 | 
						|
    if (usconfig(CONF_INITSIZE, size) < 0)
 | 
						|
        perror("usconfig - CONF_INITSIZE (reset)");
 | 
						|
    addr = (long) dl_getrange(size + HDR_SIZE);
 | 
						|
    dprintf(("trying to use addr %p-%p for shared arena\n", addr, addr+size));
 | 
						|
    errno = 0;
 | 
						|
    if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0)
 | 
						|
        perror("usconfig - CONF_ATTACHADDR (set)");
 | 
						|
#endif /* USE_DL */
 | 
						|
    if (usconfig(CONF_INITUSERS, 16) < 0)
 | 
						|
        perror("usconfig - CONF_INITUSERS");
 | 
						|
    my_pid = getpid();          /* so that we know which is the main thread */
 | 
						|
#ifndef NO_EXIT_PROG
 | 
						|
    atexit(maybe_exit);
 | 
						|
    s.sa_handler = exit_sig;
 | 
						|
    sigemptyset(&s.sa_mask);
 | 
						|
    /*sigaddset(&s.sa_mask, SIGUSR1);*/
 | 
						|
    s.sa_flags = 0;
 | 
						|
    sigaction(SIGUSR1, &s, 0);
 | 
						|
    if (prctl(PR_SETEXITSIG, SIGUSR1) < 0)
 | 
						|
        perror("prctl - PR_SETEXITSIG");
 | 
						|
#endif /* NO_EXIT_PROG */
 | 
						|
    if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0)
 | 
						|
        perror("usconfig - CONF_ARENATYPE");
 | 
						|
    usconfig(CONF_LOCKTYPE, US_DEBUG); /* XXX */
 | 
						|
#ifdef Py_DEBUG
 | 
						|
    if (thread_debug & 4)
 | 
						|
        usconfig(CONF_LOCKTYPE, US_DEBUGPLUS);
 | 
						|
    else if (thread_debug & 2)
 | 
						|
        usconfig(CONF_LOCKTYPE, US_DEBUG);
 | 
						|
#endif /* Py_DEBUG */
 | 
						|
    if ((shared_arena = usinit(tmpnam(0))) == 0)
 | 
						|
        perror("usinit");
 | 
						|
#ifdef USE_DL
 | 
						|
    if (usconfig(CONF_ATTACHADDR, addr) < 0) /* reset address */
 | 
						|
        perror("usconfig - CONF_ATTACHADDR (reset)");
 | 
						|
#endif /* USE_DL */
 | 
						|
    if ((count_lock = usnewlock(shared_arena)) == NULL)
 | 
						|
        perror("usnewlock (count_lock)");
 | 
						|
    (void) usinitlock(count_lock);
 | 
						|
    if ((wait_lock = usnewlock(shared_arena)) == NULL)
 | 
						|
        perror("usnewlock (wait_lock)");
 | 
						|
    dprintf(("arena start: %p, arena size: %ld\n",  shared_arena, (long) usconfig(CONF_GETSIZE, shared_arena)));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Thread support.
 | 
						|
 */
 | 
						|
 | 
						|
static void clean_threads(void)
 | 
						|
{
 | 
						|
    int i, j;
 | 
						|
    pid_t mypid, pid;
 | 
						|
 | 
						|
    /* clean up any exited threads */
 | 
						|
    mypid = getpid();
 | 
						|
    i = 0;
 | 
						|
    while (i < maxpidindex) {
 | 
						|
        if (pidlist[i].parent == mypid && (pid = pidlist[i].child) > 0) {
 | 
						|
            pid = waitpid(pid, 0, WNOHANG);
 | 
						|
            if (pid > 0) {
 | 
						|
                /* a thread has exited */
 | 
						|
                pidlist[i] = pidlist[--maxpidindex];
 | 
						|
                /* remove references to children of dead proc */
 | 
						|
                for (j = 0; j < maxpidindex; j++)
 | 
						|
                    if (pidlist[j].parent == pid)
 | 
						|
                        pidlist[j].child = -1;
 | 
						|
                continue; /* don't increment i */
 | 
						|
            }
 | 
						|
        }
 | 
						|
        i++;
 | 
						|
    }
 | 
						|
    /* clean up the list */
 | 
						|
    i = 0;
 | 
						|
    while (i < maxpidindex) {
 | 
						|
        if (pidlist[i].child == -1) {
 | 
						|
            pidlist[i] = pidlist[--maxpidindex];
 | 
						|
            continue; /* don't increment i */
 | 
						|
        }
 | 
						|
        i++;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
long PyThread_start_new_thread(void (*func)(void *), void *arg)
 | 
						|
{
 | 
						|
#ifdef USE_DL
 | 
						|
    long addr, size;
 | 
						|
    static int local_initialized = 0;
 | 
						|
#endif /* USE_DL */
 | 
						|
    int success = 0;            /* init not needed when SOLARIS_THREADS and */
 | 
						|
                /* C_THREADS implemented properly */
 | 
						|
 | 
						|
    dprintf(("PyThread_start_new_thread called\n"));
 | 
						|
    if (!initialized)
 | 
						|
        PyThread_init_thread();
 | 
						|
    switch (ussetlock(count_lock)) {
 | 
						|
    case 0: return 0;
 | 
						|
    case -1: perror("ussetlock (count_lock)");
 | 
						|
    }
 | 
						|
    if (maxpidindex >= MAXPROC)
 | 
						|
        success = -1;
 | 
						|
    else {
 | 
						|
#ifdef USE_DL
 | 
						|
        if (!local_initialized) {
 | 
						|
            if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
 | 
						|
                perror("usconfig - CONF_INITSIZE (check)");
 | 
						|
            if (usconfig(CONF_INITSIZE, size) < 0)
 | 
						|
                perror("usconfig - CONF_INITSIZE (reset)");
 | 
						|
            addr = (long) dl_getrange(size + HDR_SIZE);
 | 
						|
            dprintf(("trying to use addr %p-%p for sproc\n",
 | 
						|
                     addr, addr+size));
 | 
						|
            errno = 0;
 | 
						|
            if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 &&
 | 
						|
                errno != 0)
 | 
						|
                perror("usconfig - CONF_ATTACHADDR (set)");
 | 
						|
        }
 | 
						|
#endif /* USE_DL */
 | 
						|
        clean_threads();
 | 
						|
        if ((success = sproc(func, PR_SALL, arg)) < 0)
 | 
						|
            perror("sproc");
 | 
						|
#ifdef USE_DL
 | 
						|
        if (!local_initialized) {
 | 
						|
            if (usconfig(CONF_ATTACHADDR, addr) < 0)
 | 
						|
                /* reset address */
 | 
						|
                perror("usconfig - CONF_ATTACHADDR (reset)");
 | 
						|
            local_initialized = 1;
 | 
						|
        }
 | 
						|
#endif /* USE_DL */
 | 
						|
        if (success >= 0) {
 | 
						|
            nthreads++;
 | 
						|
            pidlist[maxpidindex].parent = getpid();
 | 
						|
            pidlist[maxpidindex++].child = success;
 | 
						|
            dprintf(("pidlist[%d] = %d\n",
 | 
						|
                     maxpidindex-1, success));
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (usunsetlock(count_lock) < 0)
 | 
						|
        perror("usunsetlock (count_lock)");
 | 
						|
    return success;
 | 
						|
}
 | 
						|
 | 
						|
long PyThread_get_thread_ident(void)
 | 
						|
{
 | 
						|
    return getpid();
 | 
						|
}
 | 
						|
 | 
						|
static void do_PyThread_exit_thread(int no_cleanup)
 | 
						|
{
 | 
						|
    dprintf(("PyThread_exit_thread called\n"));
 | 
						|
    if (!initialized)
 | 
						|
        if (no_cleanup)
 | 
						|
            _exit(0);
 | 
						|
        else
 | 
						|
            exit(0);
 | 
						|
    if (ussetlock(count_lock) < 0)
 | 
						|
        perror("ussetlock (count_lock)");
 | 
						|
    nthreads--;
 | 
						|
    if (getpid() == my_pid) {
 | 
						|
        /* main thread; wait for other threads to exit */
 | 
						|
        exiting = 1;
 | 
						|
#ifndef NO_EXIT_PROG
 | 
						|
        if (do_exit) {
 | 
						|
            int i;
 | 
						|
 | 
						|
            /* notify other threads */
 | 
						|
            clean_threads();
 | 
						|
            if (nthreads >= 0) {
 | 
						|
                dprintf(("kill other threads\n"));
 | 
						|
                for (i = 0; i < maxpidindex; i++)
 | 
						|
                    if (pidlist[i].child > 0)
 | 
						|
                        (void) kill(pidlist[i].child,
 | 
						|
                                    SIGKILL);
 | 
						|
                _exit(exit_status);
 | 
						|
            }
 | 
						|
        }
 | 
						|
#endif /* NO_EXIT_PROG */
 | 
						|
        waiting_for_threads = 1;
 | 
						|
        if (ussetlock(wait_lock) < 0)
 | 
						|
            perror("ussetlock (wait_lock)");
 | 
						|
        for (;;) {
 | 
						|
            if (nthreads < 0) {
 | 
						|
                dprintf(("really exit (%d)\n", exit_status));
 | 
						|
                if (no_cleanup)
 | 
						|
                    _exit(exit_status);
 | 
						|
                else
 | 
						|
                    exit(exit_status);
 | 
						|
            }
 | 
						|
            if (usunsetlock(count_lock) < 0)
 | 
						|
                perror("usunsetlock (count_lock)");
 | 
						|
            dprintf(("waiting for other threads (%d)\n", nthreads));
 | 
						|
            if (ussetlock(wait_lock) < 0)
 | 
						|
                perror("ussetlock (wait_lock)");
 | 
						|
            if (ussetlock(count_lock) < 0)
 | 
						|
                perror("ussetlock (count_lock)");
 | 
						|
        }
 | 
						|
    }
 | 
						|
    /* not the main thread */
 | 
						|
    if (waiting_for_threads) {
 | 
						|
        dprintf(("main thread is waiting\n"));
 | 
						|
        if (usunsetlock(wait_lock) < 0)
 | 
						|
            perror("usunsetlock (wait_lock)");
 | 
						|
    }
 | 
						|
#ifndef NO_EXIT_PROG
 | 
						|
    else if (do_exit)
 | 
						|
        (void) kill(my_pid, SIGUSR1);
 | 
						|
#endif /* NO_EXIT_PROG */
 | 
						|
    if (usunsetlock(count_lock) < 0)
 | 
						|
        perror("usunsetlock (count_lock)");
 | 
						|
    _exit(0);
 | 
						|
}
 | 
						|
 | 
						|
void PyThread_exit_thread(void)
 | 
						|
{
 | 
						|
    do_PyThread_exit_thread(0);
 | 
						|
}
 | 
						|
 | 
						|
void PyThread__exit_thread(void)
 | 
						|
{
 | 
						|
    do_PyThread_exit_thread(1);
 | 
						|
}
 | 
						|
 | 
						|
#ifndef NO_EXIT_PROG
 | 
						|
static void do_PyThread_exit_prog(int status, int no_cleanup)
 | 
						|
{
 | 
						|
    dprintf(("PyThread_exit_prog(%d) called\n", status));
 | 
						|
    if (!initialized)
 | 
						|
        if (no_cleanup)
 | 
						|
            _exit(status);
 | 
						|
        else
 | 
						|
            exit(status);
 | 
						|
    do_exit = 1;
 | 
						|
    exit_status = status;
 | 
						|
    do_PyThread_exit_thread(no_cleanup);
 | 
						|
}
 | 
						|
 | 
						|
void PyThread_exit_prog(int status)
 | 
						|
{
 | 
						|
    do_PyThread_exit_prog(status, 0);
 | 
						|
}
 | 
						|
 | 
						|
void PyThread__exit_prog(int status)
 | 
						|
{
 | 
						|
    do_PyThread_exit_prog(status, 1);
 | 
						|
}
 | 
						|
#endif /* NO_EXIT_PROG */
 | 
						|
 | 
						|
/*
 | 
						|
 * Lock support.
 | 
						|
 */
 | 
						|
PyThread_type_lock PyThread_allocate_lock(void)
 | 
						|
{
 | 
						|
    ulock_t lock;
 | 
						|
 | 
						|
    dprintf(("PyThread_allocate_lock called\n"));
 | 
						|
    if (!initialized)
 | 
						|
        PyThread_init_thread();
 | 
						|
 | 
						|
    if ((lock = usnewlock(shared_arena)) == NULL)
 | 
						|
        perror("usnewlock");
 | 
						|
    (void) usinitlock(lock);
 | 
						|
    dprintf(("PyThread_allocate_lock() -> %p\n", lock));
 | 
						|
    return (PyThread_type_lock) lock;
 | 
						|
}
 | 
						|
 | 
						|
void PyThread_free_lock(PyThread_type_lock lock)
 | 
						|
{
 | 
						|
    dprintf(("PyThread_free_lock(%p) called\n", lock));
 | 
						|
    usfreelock((ulock_t) lock, shared_arena);
 | 
						|
}
 | 
						|
 | 
						|
int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
 | 
						|
{
 | 
						|
    int success;
 | 
						|
 | 
						|
    dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));
 | 
						|
    errno = 0;                  /* clear it just in case */
 | 
						|
    if (waitflag)
 | 
						|
        success = ussetlock((ulock_t) lock);
 | 
						|
    else
 | 
						|
        success = uscsetlock((ulock_t) lock, 1); /* Try it once */
 | 
						|
    if (success < 0)
 | 
						|
        perror(waitflag ? "ussetlock" : "uscsetlock");
 | 
						|
    dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));
 | 
						|
    return success;
 | 
						|
}
 | 
						|
 | 
						|
void PyThread_release_lock(PyThread_type_lock lock)
 | 
						|
{
 | 
						|
    dprintf(("PyThread_release_lock(%p) called\n", lock));
 | 
						|
    if (usunsetlock((ulock_t) lock) < 0)
 | 
						|
        perror("usunsetlock");
 | 
						|
}
 |