[pypy-svn] r64145 - in pypy/trunk/pypy: module/thread module/thread/test translator/c/src translator/c/test
arigo at codespeak.net
arigo at codespeak.net
Thu Apr 16 12:10:11 CEST 2009
Author: arigo
Date: Thu Apr 16 12:10:10 2009
New Revision: 64145
Modified:
pypy/trunk/pypy/module/thread/__init__.py
pypy/trunk/pypy/module/thread/app_thread.py
pypy/trunk/pypy/module/thread/ll_thread.py
pypy/trunk/pypy/module/thread/os_thread.py
pypy/trunk/pypy/module/thread/test/test_thread.py
pypy/trunk/pypy/translator/c/src/thread_nt.h
pypy/trunk/pypy/translator/c/src/thread_pthread.h
pypy/trunk/pypy/translator/c/test/test_standalone.py
Log:
(cfbolz, arigo)
Implement thread.stack_size(). (NT implementation not tested)
Modified: pypy/trunk/pypy/module/thread/__init__.py
==============================================================================
--- pypy/trunk/pypy/module/thread/__init__.py (original)
+++ pypy/trunk/pypy/module/thread/__init__.py Thu Apr 16 12:10:10 2009
@@ -7,13 +7,13 @@
'exit': 'app_thread.exit',
'exit_thread': 'app_thread.exit', # obsolete synonym
'error': 'app_thread.error',
- 'stack_size': 'app_thread.stack_size',
}
interpleveldefs = {
'start_new_thread': 'os_thread.start_new_thread',
'start_new': 'os_thread.start_new_thread', # obsolete syn.
'get_ident': 'os_thread.get_ident',
+ 'stack_size': 'os_thread.stack_size',
'allocate_lock': 'os_lock.allocate_lock',
'allocate': 'os_lock.allocate_lock', # obsolete synonym
'LockType': 'os_lock.getlocktype(space)',
Modified: pypy/trunk/pypy/module/thread/app_thread.py
==============================================================================
--- pypy/trunk/pypy/module/thread/app_thread.py (original)
+++ pypy/trunk/pypy/module/thread/app_thread.py Thu Apr 16 12:10:10 2009
@@ -5,8 +5,3 @@
"""This is synonymous to ``raise SystemExit''. It will cause the current
thread to exit silently unless the exception is caught."""
raise SystemExit
-
-def stack_size(size=0):
- if size == 0:
- return 0
- raise error("not implemented")
Modified: pypy/trunk/pypy/module/thread/ll_thread.py
==============================================================================
--- pypy/trunk/pypy/module/thread/ll_thread.py (original)
+++ pypy/trunk/pypy/module/thread/ll_thread.py Thu Apr 16 12:10:10 2009
@@ -119,6 +119,14 @@
# ____________________________________________________________
#
+# Stack size
+
+get_stacksize = llexternal('RPyThreadGetStackSize', [], lltype.Signed)
+set_stacksize = llexternal('RPyThreadSetStackSize', [lltype.Signed],
+ lltype.Signed)
+
+# ____________________________________________________________
+#
# GIL support wrappers
null_ll_lock = lltype.nullptr(TLOCKP.TO)
Modified: pypy/trunk/pypy/module/thread/os_thread.py
==============================================================================
--- pypy/trunk/pypy/module/thread/os_thread.py (original)
+++ pypy/trunk/pypy/module/thread/os_thread.py Thu Apr 16 12:10:10 2009
@@ -170,3 +170,35 @@
A thread's identity may be reused for another thread after it exits."""
ident = thread.get_ident()
return space.wrap(ident)
+
+def stack_size(space, size=0):
+ """stack_size([size]) -> size
+
+Return the thread stack size used when creating new threads. The
+optional size argument specifies the stack size (in bytes) to be used
+for subsequently created threads, and must be 0 (use platform or
+configured default) or a positive integer value of at least 32,768 (32k).
+If changing the thread stack size is unsupported, a ThreadError
+exception is raised. If the specified size is invalid, a ValueError
+exception is raised, and the stack size is unmodified. 32k bytes
+is currently the minimum supported stack size value to guarantee
+sufficient stack space for the interpreter itself.
+
+Note that some platforms may have particular restrictions on values for
+the stack size, such as requiring a minimum stack size larger than 32kB or
+requiring allocation in multiples of the system memory page size
+- platform documentation should be referred to for more information
+(4kB pages are common; using multiples of 4096 for the stack size is
+the suggested approach in the absence of more specific information)."""
+ if size < 0:
+ raise OperationError(space.w_ValueError,
+ space.wrap("size must be 0 or a positive value"))
+ old_size = thread.get_stacksize()
+ error = thread.set_stacksize(size)
+ if error == -1:
+ raise OperationError(space.w_ValueError,
+ space.wrap("size not valid: %d bytes" % size))
+ if error == -2:
+ raise wrap_thread_error(space, "setting stack size not supported")
+ return space.wrap(old_size)
+stack_size.unwrap_spec = [ObjSpace, int]
Modified: pypy/trunk/pypy/module/thread/test/test_thread.py
==============================================================================
--- pypy/trunk/pypy/module/thread/test/test_thread.py (original)
+++ pypy/trunk/pypy/module/thread/test/test_thread.py Thu Apr 16 12:10:10 2009
@@ -187,3 +187,15 @@
pass
else:
raise Exception("could unexpectedly start 1000 threads")
+
+ def test_stack_size(self):
+ import thread
+ thread.stack_size(0)
+ res = thread.stack_size(0)
+ assert res == 0
+ res = thread.stack_size(1024*1024)
+ assert res == 0
+ res = thread.stack_size(2*1024*1024)
+ assert res == 1024*1024
+ res = thread.stack_size(0)
+ assert res == 2*1024*1024
Modified: pypy/trunk/pypy/translator/c/src/thread_nt.h
==============================================================================
--- pypy/trunk/pypy/translator/c/src/thread_nt.h (original)
+++ pypy/trunk/pypy/translator/c/src/thread_nt.h Thu Apr 16 12:10:10 2009
@@ -48,6 +48,8 @@
#ifndef PYPY_NOT_MAIN_FILE
+static long _pypythread_stacksize = 0;
+
/*
* Return the thread Id instead of an handle. The Id is said to uniquely
identify the thread in the system
@@ -81,7 +83,7 @@
if (obj.done == NULL)
return -1;
- rv = _beginthread(bootstrap, 0, &obj); /* use default stack size */
+ rv = _beginthread(bootstrap, _pypythread_stacksize, &obj);
if (rv == (unsigned long)-1) {
/* I've seen errno == EAGAIN here, which means "there are
* too many threads".
@@ -99,6 +101,32 @@
/************************************************************/
+/* minimum/maximum thread stack sizes supported */
+#define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */
+#define THREAD_MAX_STACKSIZE 0x10000000 /* 256MB */
+
+long RPyThreadGetStackSize(void)
+{
+ return _pypythread_stacksize;
+}
+
+long RPyThreadSetStackSize(long newsize)
+{
+ if (newsize == 0) { /* set to default */
+ _pypythread_stacksize = 0;
+ return 0;
+ }
+
+ /* check the range */
+ if (newsize >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) {
+ _pypythread_stacksize = newsize;
+ return 0;
+ }
+ return -1;
+}
+
+/************************************************************/
+
typedef PVOID WINAPI interlocked_cmp_xchg_t(PVOID *dest, PVOID exc, PVOID comperand) ;
Modified: pypy/trunk/pypy/translator/c/src/thread_pthread.h
==============================================================================
--- pypy/trunk/pypy/translator/c/src/thread_pthread.h (original)
+++ pypy/trunk/pypy/translator/c/src/thread_pthread.h Thu Apr 16 12:10:10 2009
@@ -80,12 +80,28 @@
void RPyOpaqueDealloc_ThreadLock(struct RPyOpaque_ThreadLock *lock);
int RPyThreadAcquireLock(struct RPyOpaque_ThreadLock *lock, int waitflag);
void RPyThreadReleaseLock(struct RPyOpaque_ThreadLock *lock);
+long RPyThreadGetStackSize(void);
+long RPyThreadSetStackSize(long);
/* implementations */
#ifndef PYPY_NOT_MAIN_FILE
+/* 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.
@@ -105,6 +121,8 @@
#endif
}
+static long _pypythread_stacksize = 0;
+
static void *bootstrap_pthread(void *func)
{
((void(*)(void))func)();
@@ -118,12 +136,18 @@
#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
- pthread_attr_setstacksize(&attrs, 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);
@@ -154,6 +178,47 @@
#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
Modified: pypy/trunk/pypy/translator/c/test/test_standalone.py
==============================================================================
--- pypy/trunk/pypy/translator/c/test/test_standalone.py (original)
+++ pypy/trunk/pypy/translator/c/test/test_standalone.py Thu Apr 16 12:10:10 2009
@@ -268,3 +268,54 @@
def test_prof_inline(self):
py.test.skip("Unsupported")
+
+
+class TestThread(object):
+ def test_stack_size(self):
+ from pypy.module.thread import ll_thread
+
+ class State:
+ pass
+ state = State()
+
+ def recurse(n):
+ if n > 0:
+ return recurse(n-1)+1
+ else:
+ return 0
+
+ def bootstrap():
+ # recurse a lot, like 10000 times
+ recurse(10000)
+ state.ll_lock.release()
+
+ def entry_point(argv):
+ os.write(1, "hello world\n")
+ error = ll_thread.set_stacksize(int(argv[1]))
+ assert error == 0
+ # start a new thread
+ state.ll_lock = ll_thread.Lock(ll_thread.allocate_ll_lock())
+ state.ll_lock.acquire(True)
+ ident = ll_thread.start_new_thread(bootstrap, ())
+ # wait for the thread to finish
+ state.ll_lock.acquire(True)
+ os.write(1, "done\n")
+ return 0
+
+ t = TranslationContext()
+ t.buildannotator().build_types(entry_point, [s_list_of_strings])
+ t.buildrtyper().specialize()
+
+ cbuilder = CStandaloneBuilder(t, entry_point, t.config)
+ cbuilder.generate_source()
+ cbuilder.compile()
+
+ # this should work
+ data = cbuilder.cmdexec(str(2*1024*1024)) # 2 MB: should work
+ assert data == 'hello world\ndone\n'
+
+ # this should crash
+ exc_info = py.test.raises(Exception,
+ cbuilder.cmdexec,
+ str(32*1024)) # 32 KB: crash
+ assert exc_info.type is Exception # segfault!
More information about the Pypy-commit
mailing list