view Python/thread_sgi.h @ 63509:5fd09e410d36 2.6

Merged revisions 83429,83436 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/release27-maint ................ r83429 | georg.brandl | 2010-08-01 21:14:56 +0200 (So, 01 Aug 2010) | 37 lines Merged revisions 83352,83356-83358,83362,83366,83368-83369 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/py3k ........ r83352 | georg.brandl | 2010-07-31 20:11:07 +0200 (Sa, 31 Jul 2010) | 1 line #9440: Remove borderline test case that fails based on unpredictable conditions such as compiler flags. ........ r83356 | georg.brandl | 2010-07-31 21:29:15 +0200 (Sa, 31 Jul 2010) | 1 line Remove trailing whitespace. ........ r83357 | georg.brandl | 2010-07-31 21:59:55 +0200 (Sa, 31 Jul 2010) | 1 line #5778: document that sys.version can contain a newline. ........ r83358 | georg.brandl | 2010-07-31 22:05:31 +0200 (Sa, 31 Jul 2010) | 1 line #9442: do not document a specific format for sys.version; rather refer to version_info and the platform module. ........ r83362 | georg.brandl | 2010-07-31 23:12:15 +0200 (Sa, 31 Jul 2010) | 1 line #8910: add a file explaining why Lib/test/data is there. ........ r83366 | georg.brandl | 2010-07-31 23:26:40 +0200 (Sa, 31 Jul 2010) | 1 line There always is a False and True now. ........ r83368 | georg.brandl | 2010-07-31 23:40:15 +0200 (Sa, 31 Jul 2010) | 1 line #7909: the prefixes \\.\ and \\?\ indicate special Windows paths, do not try to manipulate them. See http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx for details. ........ r83369 | georg.brandl | 2010-07-31 23:41:42 +0200 (Sa, 31 Jul 2010) | 1 line Fix "Berkeley" name. ........ ................ r83436 | georg.brandl | 2010-08-01 21:33:15 +0200 (So, 01 Aug 2010) | 42 lines Merged revisions 83259,83261,83264-83265,83268-83269,83271-83272,83281 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/py3k ........ r83259 | georg.brandl | 2010-07-30 09:03:39 +0200 (Fr, 30 Jul 2010) | 1 line Clarification. ........ r83261 | georg.brandl | 2010-07-30 09:21:26 +0200 (Fr, 30 Jul 2010) | 1 line #9230: allow Pdb.checkline() to be called without a current frame, for setting breakpoints before starting debugging. ........ r83264 | georg.brandl | 2010-07-30 10:45:26 +0200 (Fr, 30 Jul 2010) | 1 line Document the "jump" command in pdb.__doc__, and add a version tag for "until X". ........ r83265 | georg.brandl | 2010-07-30 10:54:49 +0200 (Fr, 30 Jul 2010) | 1 line #8015: fix crash when entering an empty line for breakpoint commands. Also restore environment properly when an exception occurs during the definition of commands. ........ r83268 | georg.brandl | 2010-07-30 11:23:23 +0200 (Fr, 30 Jul 2010) | 2 lines Issue #8048: Prevent doctests from failing when sys.displayhook has been reassigned. ........ r83269 | georg.brandl | 2010-07-30 11:43:00 +0200 (Fr, 30 Jul 2010) | 1 line #6719: In pdb, do not stop somewhere in the encodings machinery if the source file to be debugged is in a non-builtin encoding. ........ r83271 | georg.brandl | 2010-07-30 11:59:28 +0200 (Fr, 30 Jul 2010) | 1 line #5727: Restore the ability to use readline when calling into pdb in doctests. ........ r83272 | georg.brandl | 2010-07-30 12:29:19 +0200 (Fr, 30 Jul 2010) | 1 line #5294: Fix the behavior of pdb "continue" command when called in the top-level debugged frame. ........ r83281 | georg.brandl | 2010-07-30 15:36:43 +0200 (Fr, 30 Jul 2010) | 1 line Add myself for pdb. ........ ................
author Georg Brandl <georg@python.org>
date Sun, 01 Aug 2010 22:10:15 +0000
parents e38335d4df91
children b36cb4602e21
line wrap: on
line source


#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");
}