Author: Amaury Forgeot d'Arc <amaur...@gmail.com>
Branch: remove-PYPY_NOT_MAIN_FILE
Changeset: r57167:35bed71287ef
Date: 2012-09-06 00:06 +0200
http://bitbucket.org/pypy/pypy/changeset/35bed71287ef/

Log:    Add missing file

diff --git a/pypy/translator/c/src/thread_pthread.c 
b/pypy/translator/c/src/thread_pthread.c
new file mode 100644
--- /dev/null
+++ b/pypy/translator/c/src/thread_pthread.c
@@ -0,0 +1,497 @@
+
+/* Posix threads interface (from CPython) */
+
+#include <unistd.h>   /* for the _POSIX_xxx and _POSIX_THREAD_xxx defines */
+#include <stdlib.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <errno.h>
+#include <assert.h>
+
+/* The following is hopefully equivalent to what CPython does
+   (which is trying to compile a snippet of code using it) */
+#ifdef PTHREAD_SCOPE_SYSTEM
+#  ifndef PTHREAD_SYSTEM_SCHED_SUPPORTED
+#    define PTHREAD_SYSTEM_SCHED_SUPPORTED
+#  endif
+#endif
+
+#if !defined(pthread_attr_default)
+#  define pthread_attr_default ((pthread_attr_t *)NULL)
+#endif
+#if !defined(pthread_mutexattr_default)
+#  define pthread_mutexattr_default ((pthread_mutexattr_t *)NULL)
+#endif
+#if !defined(pthread_condattr_default)
+#  define pthread_condattr_default ((pthread_condattr_t *)NULL)
+#endif
+
+#define CHECK_STATUS(name)  if (status != 0) { perror(name); error = 1; }
+
+/* The POSIX spec requires that use of pthread_attr_setstacksize
+   be conditional on _POSIX_THREAD_ATTR_STACKSIZE being defined. */
+#ifdef _POSIX_THREAD_ATTR_STACKSIZE
+# ifndef THREAD_STACK_SIZE
+#  define THREAD_STACK_SIZE   0   /* use default stack size */
+# endif
+/* for safety, ensure a viable minimum stacksize */
+# define THREAD_STACK_MIN    0x8000  /* 32kB */
+#else  /* !_POSIX_THREAD_ATTR_STACKSIZE */
+# ifdef THREAD_STACK_SIZE
+#  error "THREAD_STACK_SIZE defined but _POSIX_THREAD_ATTR_STACKSIZE undefined"
+# endif
+#endif
+
+/* XXX This implementation is considered (to quote Tim Peters) "inherently
+   hosed" because:
+     - It does not guarantee the promise that a non-zero integer is returned.
+     - The cast to long is inherently unsafe.
+     - It is not clear that the 'volatile' (for AIX?) and ugly casting in the
+       latter return statement (for Alpha OSF/1) are any longer necessary.
+*/
+long RPyThreadGetIdent(void)
+{
+       volatile pthread_t threadid;
+       /* Jump through some hoops for Alpha OSF/1 */
+       threadid = pthread_self();
+
+#ifdef __CYGWIN__
+       /* typedef __uint32_t pthread_t; */
+       return (long) threadid;
+#else
+       if (sizeof(pthread_t) <= sizeof(long))
+               return (long) threadid;
+       else
+               return (long) *(long *) &threadid;
+#endif
+}
+
+static long _pypythread_stacksize = 0;
+
+static void *bootstrap_pthread(void *func)
+{
+  ((void(*)(void))func)();
+  return NULL;
+}
+
+long RPyThreadStart(void (*func)(void))
+{
+       pthread_t th;
+       int status;
+#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
+       pthread_attr_t attrs;
+#endif
+#if defined(THREAD_STACK_SIZE)
+       size_t tss;
+#endif
+
+#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
+       pthread_attr_init(&attrs);
+#endif
+#ifdef THREAD_STACK_SIZE
+       tss = (_pypythread_stacksize != 0) ? _pypythread_stacksize
+               : THREAD_STACK_SIZE;
+       if (tss != 0)
+               pthread_attr_setstacksize(&attrs, tss);
+#endif
+#if defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) && !defined(__FreeBSD__)
+        pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM);
+#endif
+
+       status = pthread_create(&th, 
+#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
+                                &attrs,
+#else
+                                (pthread_attr_t*)NULL,
+#endif
+                                bootstrap_pthread,
+                                (void *)func
+                                );
+
+#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
+       pthread_attr_destroy(&attrs);
+#endif
+       if (status != 0)
+            return -1;
+
+        pthread_detach(th);
+
+#ifdef __CYGWIN__
+       /* typedef __uint32_t pthread_t; */
+       return (long) th;
+#else
+       if (sizeof(pthread_t) <= sizeof(long))
+               return (long) th;
+       else
+               return (long) *(long *) &th;
+#endif
+}
+
+long RPyThreadGetStackSize(void)
+{
+       return _pypythread_stacksize;
+}
+
+long RPyThreadSetStackSize(long newsize)
+{
+#if defined(THREAD_STACK_SIZE)
+       pthread_attr_t attrs;
+       size_t tss_min;
+       int rc;
+#endif
+
+       if (newsize == 0) {    /* set to default */
+               _pypythread_stacksize = 0;
+               return 0;
+       }
+
+#if defined(THREAD_STACK_SIZE)
+# if defined(PTHREAD_STACK_MIN)
+       tss_min = PTHREAD_STACK_MIN > THREAD_STACK_MIN ? PTHREAD_STACK_MIN
+               : THREAD_STACK_MIN;
+# else
+       tss_min = THREAD_STACK_MIN;
+# endif
+       if (newsize >= tss_min) {
+               /* validate stack size by setting thread attribute */
+               if (pthread_attr_init(&attrs) == 0) {
+                       rc = pthread_attr_setstacksize(&attrs, newsize);
+                       pthread_attr_destroy(&attrs);
+                       if (rc == 0) {
+                               _pypythread_stacksize = newsize;
+                               return 0;
+                       }
+               }
+       }
+       return -1;
+#else
+       return -2;
+#endif
+}
+
+/************************************************************/
+#ifdef USE_SEMAPHORES
+/************************************************************/
+
+#include <semaphore.h>
+
+void RPyThreadAfterFork(void)
+{
+}
+
+int RPyThreadLockInit(struct RPyOpaque_ThreadLock *lock)
+{
+       int status, error = 0;
+       lock->initialized = 0;
+       status = sem_init(&lock->sem, 0, 1);
+       CHECK_STATUS("sem_init");
+       if (error)
+               return 0;
+       lock->initialized = 1;
+       return 1;
+}
+
+void RPyOpaqueDealloc_ThreadLock(struct RPyOpaque_ThreadLock *lock)
+{
+       int status, error = 0;
+       if (lock->initialized) {
+               status = sem_destroy(&lock->sem);
+               CHECK_STATUS("sem_destroy");
+               /* 'error' is ignored;
+                  CHECK_STATUS already printed an error message */
+       }
+}
+
+/*
+ * As of February 2002, Cygwin thread implementations mistakenly report error
+ * codes in the return value of the sem_ calls (like the pthread_ functions).
+ * Correct implementations return -1 and put the code in errno. This supports
+ * either.
+ */
+static int
+rpythread_fix_status(int status)
+{
+       return (status == -1) ? errno : status;
+}
+
+int RPyThreadAcquireLock(struct RPyOpaque_ThreadLock *lock, int waitflag)
+{
+       int success;
+       sem_t *thelock = &lock->sem;
+       int status, error = 0;
+
+       do {
+               if (waitflag)
+                       status = rpythread_fix_status(sem_wait(thelock));
+               else
+                       status = rpythread_fix_status(sem_trywait(thelock));
+       } while (status == EINTR); /* Retry if interrupted by a signal */
+
+       if (waitflag) {
+               CHECK_STATUS("sem_wait");
+       } else if (status != EAGAIN) {
+               CHECK_STATUS("sem_trywait");
+       }
+       
+       success = (status == 0) ? 1 : 0;
+       return success;
+}
+
+void RPyThreadReleaseLock(struct RPyOpaque_ThreadLock *lock)
+{
+       sem_t *thelock = &lock->sem;
+       int status, error = 0;
+
+       status = sem_post(thelock);
+       CHECK_STATUS("sem_post");
+}
+
+/************************************************************/
+#else                                      /* no semaphores */
+/************************************************************/
+
+struct RPyOpaque_ThreadLock *alllocks;   /* doubly-linked list */
+
+void RPyThreadAfterFork(void)
+{
+       /* Mess.  We have no clue about how it works on CPython on OSX,
+          but the issue is that the state of mutexes is not really
+          preserved across a fork().  So we need to walk over all lock
+          objects here, and rebuild their mutex and condition variable.
+
+          See e.g. http://hackage.haskell.org/trac/ghc/ticket/1391 for
+          a similar bug about GHC.
+       */
+       struct RPyOpaque_ThreadLock *p = alllocks;
+       alllocks = NULL;
+       while (p) {
+               struct RPyOpaque_ThreadLock *next = p->next;
+               int was_locked = p->locked;
+               RPyThreadLockInit(p);
+               p->locked = was_locked;
+               p = next;
+       }
+}
+
+int RPyThreadLockInit(struct RPyOpaque_ThreadLock *lock)
+{
+       int status, error = 0;
+
+       lock->initialized = 0;
+       lock->locked = 0;
+
+       status = pthread_mutex_init(&lock->mut,
+                                   pthread_mutexattr_default);
+       CHECK_STATUS("pthread_mutex_init");
+
+       status = pthread_cond_init(&lock->lock_released,
+                                  pthread_condattr_default);
+       CHECK_STATUS("pthread_cond_init");
+
+       if (error)
+               return 0;
+       lock->initialized = 1;
+       /* add 'lock' in the doubly-linked list */
+       if (alllocks)
+               alllocks->prev = lock;
+       lock->next = alllocks;
+       lock->prev = NULL;
+       alllocks = lock;
+       return 1;
+}
+
+void RPyOpaqueDealloc_ThreadLock(struct RPyOpaque_ThreadLock *lock)
+{
+       int status, error = 0;
+       if (lock->initialized) {
+               /* remove 'lock' from the doubly-linked list */
+               if (lock->prev)
+                       lock->prev->next = lock->next;
+               else {
+                       assert(alllocks == lock);
+                       alllocks = lock->next;
+               }
+               if (lock->next)
+                       lock->next->prev = lock->prev;
+
+               status = pthread_mutex_destroy(&lock->mut);
+               CHECK_STATUS("pthread_mutex_destroy");
+
+               status = pthread_cond_destroy(&lock->lock_released);
+               CHECK_STATUS("pthread_cond_destroy");
+
+               /* 'error' is ignored;
+                  CHECK_STATUS already printed an error message */
+       }
+}
+
+int RPyThreadAcquireLock(struct RPyOpaque_ThreadLock *lock, int waitflag)
+{
+       int success;
+       int status, error = 0;
+
+       status = pthread_mutex_lock( &lock->mut );
+       CHECK_STATUS("pthread_mutex_lock[1]");
+       success = lock->locked == 0;
+
+       if ( !success && waitflag ) {
+               /* continue trying until we get the lock */
+
+               /* mut must be locked by me -- part of the condition
+                * protocol */
+               while ( lock->locked ) {
+                       status = pthread_cond_wait(&lock->lock_released,
+                                                  &lock->mut);
+                       CHECK_STATUS("pthread_cond_wait");
+               }
+               success = 1;
+       }
+       if (success) lock->locked = 1;
+       status = pthread_mutex_unlock( &lock->mut );
+       CHECK_STATUS("pthread_mutex_unlock[1]");
+
+       if (error) success = 0;
+       return success;
+}
+
+void RPyThreadReleaseLock(struct RPyOpaque_ThreadLock *lock)
+{
+       int status, error = 0;
+
+       status = pthread_mutex_lock( &lock->mut );
+       CHECK_STATUS("pthread_mutex_lock[3]");
+
+       lock->locked = 0;
+
+       status = pthread_mutex_unlock( &lock->mut );
+       CHECK_STATUS("pthread_mutex_unlock[3]");
+
+       /* wake up someone (anyone, if any) waiting on the lock */
+       status = pthread_cond_signal( &lock->lock_released );
+       CHECK_STATUS("pthread_cond_signal");
+}
+
+/************************************************************/
+#endif                                     /* no semaphores */
+/************************************************************/
+
+
+/* Thread-local storage */
+
+char *RPyThreadTLS_Create(RPyThreadTLS *result)
+{
+       if (pthread_key_create(result, NULL) != 0)
+               return "out of thread-local storage keys";
+       else
+               return NULL;
+}
+
+
+/************************************************************/
+/* GIL code                                                 */
+/************************************************************/
+
+#ifdef __llvm__
+#  define HAS_ATOMIC_ADD
+#endif
+
+#ifdef __GNUC__
+#  if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
+#    define HAS_ATOMIC_ADD
+#  endif
+#endif
+
+#ifdef HAS_ATOMIC_ADD
+#  define atomic_add __sync_fetch_and_add
+#else
+#  if defined(__amd64__)
+#    define atomic_add(ptr, value)  asm volatile ("lock addq %0, %1"        \
+                                 : : "ri"(value), "m"(*(ptr)) : "memory")
+#  elif defined(__i386__)
+#    define atomic_add(ptr, value)  asm volatile ("lock addl %0, %1"        \
+                                 : : "ri"(value), "m"(*(ptr)) : "memory")
+#  else
+#    error "Please use gcc >= 4.1 or write a custom 'asm' for your CPU."
+#  endif
+#endif
+
+#define ASSERT_STATUS(call)                             \
+    if (call != 0) {                                    \
+        fprintf(stderr, "Fatal error: " #call "\n");    \
+        abort();                                        \
+    }
+
+static void _debug_print(const char *msg)
+{
+#if 0
+    int col = (int)pthread_self();
+    col = 31 + ((col / 8) % 8);
+    fprintf(stderr, "\033[%dm%s\033[0m", col, msg);
+#endif
+}
+
+static volatile long pending_acquires = -1;
+static pthread_mutex_t mutex_gil = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t cond_gil = PTHREAD_COND_INITIALIZER;
+
+static void assert_has_the_gil(void)
+{
+#ifdef RPY_ASSERT
+    assert(pthread_mutex_trylock(&mutex_gil) != 0);
+    assert(pending_acquires >= 0);
+#endif
+}
+
+long RPyGilAllocate(void)
+{
+    _debug_print("RPyGilAllocate\n");
+    pending_acquires = 0;
+    pthread_mutex_trylock(&mutex_gil);
+    assert_has_the_gil();
+    return 1;
+}
+
+long RPyGilYieldThread(void)
+{
+    /* can be called even before RPyGilAllocate(), but in this case,
+       pending_acquires will be -1 */
+#ifdef RPY_ASSERT
+    if (pending_acquires >= 0)
+        assert_has_the_gil();
+#endif
+    if (pending_acquires <= 0)
+        return 0;
+    atomic_add(&pending_acquires, 1L);
+    _debug_print("{");
+    ASSERT_STATUS(pthread_cond_signal(&cond_gil));
+    ASSERT_STATUS(pthread_cond_wait(&cond_gil, &mutex_gil));
+    _debug_print("}");
+    atomic_add(&pending_acquires, -1L);
+    assert_has_the_gil();
+    return 1;
+}
+
+void RPyGilRelease(void)
+{
+    _debug_print("RPyGilRelease\n");
+#ifdef RPY_ASSERT
+    assert(pending_acquires >= 0);
+#endif
+    assert_has_the_gil();
+    ASSERT_STATUS(pthread_mutex_unlock(&mutex_gil));
+    ASSERT_STATUS(pthread_cond_signal(&cond_gil));
+}
+
+void RPyGilAcquire(void)
+{
+    _debug_print("about to RPyGilAcquire...\n");
+#ifdef RPY_ASSERT
+    assert(pending_acquires >= 0);
+#endif
+    atomic_add(&pending_acquires, 1L);
+    ASSERT_STATUS(pthread_mutex_lock(&mutex_gil));
+    atomic_add(&pending_acquires, -1L);
+    assert_has_the_gil();
+    _debug_print("RPyGilAcquire\n");
+}
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to