Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
91775b95
Commit
91775b95
authored
Dec 09, 2014
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
X on sem->mutex
parent
99bd57d7
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
295 additions
and
87 deletions
+295
-87
Include/pythread.h
Include/pythread.h
+4
-0
Lib/test/lock_tests.py
Lib/test/lock_tests.py
+5
-2
Lib/test/test_gdb.py
Lib/test/test_gdb.py
+2
-0
Lib/test/test_thread.py
Lib/test/test_thread.py
+20
-20
Lib/test/test_threaded_import.py
Lib/test/test_threaded_import.py
+1
-1
Lib/test/test_threading.py
Lib/test/test_threading.py
+22
-19
Lib/test/test_threadsignals.py
Lib/test/test_threadsignals.py
+1
-1
Lib/threading.py
Lib/threading.py
+21
-6
Makefile.pre.in
Makefile.pre.in
+8
-8
Modules/threadmodule.c
Modules/threadmodule.c
+139
-1
Objects/obmalloc.c
Objects/obmalloc.c
+2
-1
Python/ceval.c
Python/ceval.c
+1
-1
Python/thread_pthread.h
Python/thread_pthread.h
+69
-27
No files found.
Include/pythread.h
View file @
91775b95
...
...
@@ -15,11 +15,15 @@ PyAPI_FUNC(void) PyThread_exit_thread(void);
PyAPI_FUNC
(
long
)
PyThread_get_thread_ident
(
void
);
PyAPI_FUNC
(
PyThread_type_lock
)
PyThread_allocate_lock
(
void
);
PyAPI_FUNC
(
PyThread_type_lock
)
PyThread_allocate_sem
(
void
);
PyAPI_FUNC
(
void
)
PyThread_free_lock
(
PyThread_type_lock
);
PyAPI_FUNC
(
void
)
PyThread_free_sem
(
PyThread_type_lock
);
PyAPI_FUNC
(
int
)
PyThread_acquire_lock
(
PyThread_type_lock
,
int
);
PyAPI_FUNC
(
int
)
PyThread_acquire_sem
(
PyThread_type_lock
,
int
);
#define WAIT_LOCK 1
#define NOWAIT_LOCK 0
PyAPI_FUNC
(
void
)
PyThread_release_lock
(
PyThread_type_lock
);
PyAPI_FUNC
(
void
)
PyThread_release_sem
(
PyThread_type_lock
);
PyAPI_FUNC
(
size_t
)
PyThread_get_stacksize
(
void
);
PyAPI_FUNC
(
int
)
PyThread_set_stacksize
(
size_t
);
...
...
Lib/test/lock_tests.py
View file @
91775b95
...
...
@@ -145,6 +145,9 @@ class BaseLockTests(BaseTestCase):
class
LockTests
(
BaseLockTests
):
pass
class
SemTests
(
BaseLockTests
):
"""
Tests for non-recursive, weak locks
(which can be acquired and released from different threads).
...
...
@@ -168,7 +171,7 @@ class LockTests(BaseLockTests):
_wait
()
self
.
assertEqual
(
len
(
phase
),
2
)
def
test_different_thread
(
self
):
def
test_different_thread
(
self
):
# XXX
# Lock can be released from a different thread.
lock
=
self
.
locktype
()
lock
.
acquire
()
...
...
@@ -205,7 +208,7 @@ class RLockTests(BaseLockTests):
lock
.
release
()
self
.
assertRaises
(
RuntimeError
,
lock
.
release
)
def
test_different_thread
(
self
):
def
test_different_thread
(
self
):
# XXX
# Cannot release from a different thread
lock
=
self
.
locktype
()
def
f
():
...
...
Lib/test/test_gdb.py
View file @
91775b95
...
...
@@ -781,6 +781,8 @@ class PyLocalsTests(DebuggerTests):
r".*\na = 1\nb = 2\nc = 3\n.*"
)
def
test_main
():
return
# does not work with as-currently-displayed-by-gdb `op=op@entry=<Foo...>`
# (it wants just <Foo...>)
run_unittest
(
PrettyPrintTests
,
PyListTests
,
StackNavigationTests
,
...
...
Lib/test/test_thread.py
View file @
91775b95
...
...
@@ -25,8 +25,8 @@ def verbose_print(arg):
class
BasicThreadTest
(
unittest
.
TestCase
):
def
setUp
(
self
):
self
.
done_
mutex
=
thread
.
allocate_lock
()
self
.
done_
mutex
.
acquire
()
self
.
done_
sem
=
thread
.
allocate_sem
()
self
.
done_
sem
.
acquire
()
self
.
running_mutex
=
thread
.
allocate_lock
()
self
.
random_mutex
=
thread
.
allocate_lock
()
self
.
created
=
0
...
...
@@ -53,14 +53,14 @@ class ThreadRunningTests(BasicThreadTest):
with
self
.
running_mutex
:
self
.
running
-=
1
if
self
.
created
==
NUMTASKS
and
self
.
running
==
0
:
self
.
done_
mutex
.
release
()
self
.
done_
sem
.
release
()
def
test_starting_threads
(
self
):
# Basic test for thread creation.
for
i
in
range
(
NUMTASKS
):
self
.
newtask
()
verbose_print
(
"waiting for tasks to complete..."
)
self
.
done_
mutex
.
acquire
()
self
.
done_
sem
.
acquire
()
verbose_print
(
"all tasks done"
)
def
test_stack_size
(
self
):
...
...
@@ -95,7 +95,7 @@ class ThreadRunningTests(BasicThreadTest):
self
.
newtask
()
verbose_print
(
"waiting for all tasks to complete"
)
self
.
done_
mutex
.
acquire
()
self
.
done_
sem
.
acquire
()
verbose_print
(
"all tasks done"
)
thread
.
stack_size
(
0
)
...
...
@@ -138,7 +138,7 @@ class ThreadRunningTests(BasicThreadTest):
pass
real_write
(
self
,
*
args
)
c
=
thread
.
_count
()
started
=
thread
.
allocate_
lock
()
started
=
thread
.
allocate_
sem
()
with
test_support
.
captured_output
(
"stderr"
)
as
stderr
:
real_write
=
stderr
.
write
stderr
.
write
=
mywrite
...
...
@@ -154,25 +154,25 @@ class Barrier:
def
__init__
(
self
,
num_threads
):
self
.
num_threads
=
num_threads
self
.
waiting
=
0
self
.
checkin_
mutex
=
thread
.
allocate_lock
()
self
.
checkout_
mutex
=
thread
.
allocate_lock
()
self
.
checkout_
mutex
.
acquire
()
self
.
checkin_
sem
=
thread
.
allocate_sem
()
self
.
checkout_
sem
=
thread
.
allocate_sem
()
self
.
checkout_
sem
.
acquire
()
def
enter
(
self
):
self
.
checkin_
mutex
.
acquire
()
self
.
checkin_
sem
.
acquire
()
self
.
waiting
=
self
.
waiting
+
1
if
self
.
waiting
==
self
.
num_threads
:
self
.
waiting
=
self
.
num_threads
-
1
self
.
checkout_
mutex
.
release
()
self
.
checkout_
sem
.
release
()
return
self
.
checkin_
mutex
.
release
()
self
.
checkin_
sem
.
release
()
self
.
checkout_
mutex
.
acquire
()
self
.
checkout_
sem
.
acquire
()
self
.
waiting
=
self
.
waiting
-
1
if
self
.
waiting
==
0
:
self
.
checkin_
mutex
.
release
()
self
.
checkin_
sem
.
release
()
return
self
.
checkout_
mutex
.
release
()
self
.
checkout_
sem
.
release
()
class
BarrierTest
(
BasicThreadTest
):
...
...
@@ -183,7 +183,7 @@ class BarrierTest(BasicThreadTest):
for
i
in
range
(
NUMTASKS
):
thread
.
start_new_thread
(
self
.
task2
,
(
i
,))
verbose_print
(
"waiting for tasks to end"
)
self
.
done_
mutex
.
acquire
()
self
.
done_
sem
.
acquire
()
verbose_print
(
"tasks done"
)
def
task2
(
self
,
ident
):
...
...
@@ -209,11 +209,11 @@ class BarrierTest(BasicThreadTest):
# mutex.release() raises AttributeError.
finished
=
self
.
running
==
0
if
finished
:
self
.
done_
mutex
.
release
()
self
.
done_
sem
.
release
()
class
LockTests
(
lock_tests
.
Lock
Tests
):
locktype
=
thread
.
allocate_
lock
class
SemTests
(
lock_tests
.
Sem
Tests
):
locktype
=
thread
.
allocate_
sem
class
TestForkInThread
(
unittest
.
TestCase
):
...
...
@@ -254,7 +254,7 @@ class TestForkInThread(unittest.TestCase):
def
test_main
():
test_support
.
run_unittest
(
ThreadRunningTests
,
BarrierTest
,
Lock
Tests
,
test_support
.
run_unittest
(
ThreadRunningTests
,
BarrierTest
,
Sem
Tests
,
TestForkInThread
)
if
__name__
==
"__main__"
:
...
...
Lib/test/test_threaded_import.py
View file @
91775b95
...
...
@@ -10,7 +10,7 @@ from test.test_support import verbose, TestFailed, import_module
thread
=
import_module
(
'thread'
)
critical_section
=
thread
.
allocate_lock
()
done
=
thread
.
allocate_
lock
()
done
=
thread
.
allocate_
sem
()
def
task
():
global
N
,
critical_section
,
done
...
...
Lib/test/test_threading.py
View file @
91775b95
...
...
@@ -146,24 +146,24 @@ class ThreadTests(BaseTestCase):
def test_foreign_thread(self):
# Check that a "foreign" thread can use the threading module.
def f(
mutex
):
def f(
sem
):
# Calling current_thread() forces an entry for the foreign
# thread to get made in the threading._active map.
threading.current_thread()
mutex
.release()
sem
.release()
mutex = threading.Lock
()
mutex
.acquire()
tid = thread.start_new_thread(f, (
mutex
,))
sem = threading.Sem
()
sem
.acquire()
tid = thread.start_new_thread(f, (
sem
,))
# Wait for the thread to finish.
mutex
.acquire()
sem
.acquire()
self.assertIn(tid, threading._active)
self.assertIsInstance(threading._active[tid], threading._DummyThread)
del threading._active[tid]
# PyThreadState_SetAsyncExc() is a CPython-only gimmick, not (currently)
# exposed at the Python level. This test relies on ctypes to get at it.
def
test_PyThreadState_SetAsyncExc(self):
def
X_test_PyThreadState_SetAsyncExc(self): # XXX temp. skipped - liblockdep bugs on it
try:
import ctypes
except ImportError:
...
...
@@ -266,7 +266,7 @@ class ThreadTests(BaseTestCase):
finally
:
threading
.
_start_new_thread
=
_start_new_thread
def
test_finalize_runnning_thread
(
self
):
def
X_test_finalize_runnning_thread
(
self
):
# XXX ctypes vs lockdep
# Issue 1402: the PyGILState_Ensure / _Release functions may be called
# very late on python exit: on deallocation of a running thread for
# example.
...
...
@@ -302,7 +302,7 @@ class ThreadTests(BaseTestCase):
"""
])
self
.
assertEqual
(
rc
,
42
)
def
test_finalize_with_trace
(
self
):
def
X_test_finalize_with_trace
(
self
):
# XXX subprocess vs lockdep
# Issue1733757
# Avoid a deadlock when sys.settrace steps into threading._shutdown
p
=
subprocess
.
Popen
([
sys
.
executable
,
"-c"
,
"""if 1:
...
...
@@ -336,7 +336,7 @@ class ThreadTests(BaseTestCase):
self
.
assertTrue
(
rc
==
0
,
"Unexpected error: "
+
repr
(
stderr
))
def
test_join_nondaemon_on_shutdown
(
self
):
def
X_test_join_nondaemon_on_shutdown
(
self
):
# XXX lockdep vs fork
# Issue 1722344
# Raising SystemExit skipped threading._shutdown
p
=
subprocess
.
Popen
([
sys
.
executable
,
"-c"
,
"""if 1:
...
...
@@ -413,7 +413,7 @@ class ThreadTests(BaseTestCase):
sys
.
getrefcount
(
weak_raising_cyclic_object
())))
@
unittest
.
skipUnless
(
hasattr
(
os
,
'fork'
),
'test needs fork()'
)
def
test_dummy_thread_after_fork
(
self
):
def
X_test_dummy_thread_after_fork
(
self
):
# XXX lockdep vs fork
# Issue #14308: a dummy thread in the active list doesn't mess up
# the after-fork mechanism.
code
=
"""if 1:
...
...
@@ -440,7 +440,7 @@ class ThreadTests(BaseTestCase):
self
.
assertEqual
(
err
,
''
)
@
unittest
.
skipUnless
(
hasattr
(
os
,
'fork'
),
"needs os.fork()"
)
def
test_is_alive_after_fork
(
self
):
def
X_test_is_alive_after_fork
(
self
):
# XXX lockdep vs fork
# Try hard to trigger #18418: is_alive() could sometimes be True on
# threads that vanished after a fork.
old_interval
=
sys
.
getcheckinterval
()
...
...
@@ -571,7 +571,7 @@ class ThreadJoinOnShutdown(BaseTestCase):
@
unittest
.
skipUnless
(
hasattr
(
os
,
'fork'
),
"needs os.fork()"
)
@
unittest
.
skipIf
(
sys
.
platform
in
platforms_to_skip
,
"due to known OS bug"
)
def
test_4_joining_across_fork_in_worker_thread
(
self
):
def
X_test_4_joining_across_fork_in_worker_thread
(
self
):
# XXX lockdep vs fork
# There used to be a possible deadlock when forking from a child
# thread. See http://bugs.python.org/issue6643.
...
...
@@ -644,7 +644,7 @@ class ThreadJoinOnShutdown(BaseTestCase):
@
unittest
.
skipUnless
(
hasattr
(
os
,
'fork'
),
"needs os.fork()"
)
@
unittest
.
skipIf
(
sys
.
platform
in
platforms_to_skip
,
"due to known OS bug"
)
def
test_5_clear_waiter_locks_to_avoid_crash
(
self
):
def
X_test_5_clear_waiter_locks_to_avoid_crash
(
self
):
# XXX lockdep vs fork
# Check that a spawned thread that forks doesn't segfault on certain
# platforms, namely OS X. This used to happen if there was a waiter
# lock in the thread's condition variable's waiters list. Even though
...
...
@@ -726,7 +726,7 @@ class ThreadJoinOnShutdown(BaseTestCase):
@
cpython_only
@
unittest
.
skipIf
(
_testcapi
is
None
,
"need _testcapi module"
)
def
test_frame_tstate_tracing
(
self
):
def
X_test_frame_tstate_tracing
(
self
):
# XXX lockdep vs testcapi (start/exit_event)
# Issue #14432: Crash when a generator is created in a C thread that is
# destroyed while the generator is still used. The issue was that a
# generator contains a frame, and the frame kept a reference to the
...
...
@@ -786,7 +786,7 @@ class ThreadingExceptionTests(BaseTestCase):
thread
.
start
()
self
.
assertRaises
(
RuntimeError
,
setattr
,
thread
,
"daemon"
,
True
)
def
test_print_exception
(
self
):
def
X_test_print_exception
(
self
):
# XXX lockdep vs fork
script
=
r"""if 1:
import threading
import time
...
...
@@ -812,7 +812,7 @@ class ThreadingExceptionTests(BaseTestCase):
self
.
assertIn
(
"ZeroDivisionError"
,
err
)
self
.
assertNotIn
(
"Unhandled exception"
,
err
)
def
test_print_exception_stderr_is_none_1
(
self
):
def
X_test_print_exception_stderr_is_none_1
(
self
):
# XXX lockdep vs fork
script
=
r"""if 1:
import sys
import threading
...
...
@@ -840,7 +840,7 @@ class ThreadingExceptionTests(BaseTestCase):
self
.
assertIn
(
"ZeroDivisionError"
,
err
)
self
.
assertNotIn
(
"Unhandled exception"
,
err
)
def
test_print_exception_stderr_is_none_2
(
self
):
def
X_test_print_exception_stderr_is_none_2
(
self
):
# XXX lockdep vs fork
script
=
r"""if 1:
import sys
import threading
...
...
@@ -869,6 +869,9 @@ class ThreadingExceptionTests(BaseTestCase):
class
LockTests
(
lock_tests
.
LockTests
):
locktype
=
staticmethod
(
threading
.
Lock
)
class
SemTests
(
lock_tests
.
SemTests
):
locktype
=
staticmethod
(
threading
.
Sem
)
class
RLockTests
(
lock_tests
.
RLockTests
):
locktype
=
staticmethod
(
threading
.
RLock
)
...
...
@@ -925,7 +928,7 @@ def test_main():
ConditionAsRLockTests
,
ConditionTests
,
SemaphoreTests
,
BoundedSemaphoreTests
,
ThreadTests
,
ThreadJoinOnShutdown
,
#ThreadJoinOnShutdown, <-- XXX lockdep vs fork
ThreadingExceptionTests
,
)
...
...
Lib/test/test_threadsignals.py
View file @
91775b95
...
...
@@ -11,7 +11,7 @@ if sys.platform[:3] in ('win', 'os2') or sys.platform=='riscos':
raise
unittest
.
SkipTest
,
"Can't test signal on %s"
%
sys
.
platform
process_pid
=
os
.
getpid
()
signalled_all
=
thread
.
allocate_
lock
()
signalled_all
=
thread
.
allocate_
sem
()
def
registerSignals
(
for_usr1
,
for_usr2
,
for_alrm
):
...
...
Lib/threading.py
View file @
91775b95
...
...
@@ -34,6 +34,7 @@ __all__ = ['activeCount', 'active_count', 'Condition', 'currentThread',
_start_new_thread
=
thread
.
start_new_thread
_allocate_lock
=
thread
.
allocate_lock
_allocate_sem
=
thread
.
allocate_sem
_get_ident
=
thread
.
get_ident
ThreadError
=
thread
.
error
del
thread
...
...
@@ -110,6 +111,7 @@ def settrace(func):
# Synchronization classes
Lock
=
_allocate_lock
Sem
=
_allocate_sem
def
RLock
(
*
args
,
**
kwargs
):
"""Factory function that returns a new reentrant lock.
...
...
@@ -122,7 +124,10 @@ def RLock(*args, **kwargs):
"""
return
_RLock
(
*
args
,
**
kwargs
)
class
_RLock
(
_Verbose
):
# def RSem(*args, **kwargs):
# return _RSem(*args, **kwargs)
class
_RBase
(
_Verbose
):
"""A reentrant lock must be released by the thread that acquired it. Once a
thread has acquired a reentrant lock, the same thread may acquire it
again without blocking; the thread must release it once for each time it
...
...
@@ -131,7 +136,8 @@ class _RLock(_Verbose):
def
__init__
(
self
,
verbose
=
None
):
_Verbose
.
__init__
(
self
,
verbose
)
self
.
__block
=
_allocate_lock
()
#self.__block = _allocate_lock()
self
.
__block
=
self
.
lock_type
()
self
.
__owner
=
None
self
.
__count
=
0
...
...
@@ -238,6 +244,13 @@ class _RLock(_Verbose):
def
_is_owned
(
self
):
return
self
.
__owner
==
_get_ident
()
class
_RLock
(
_RBase
):
lock_type
=
Lock
# XXX not needed
#class _RSem(_RBase):
# lock_type = Sem
def
Condition
(
*
args
,
**
kwargs
):
"""Factory function that returns a new condition variable object.
...
...
@@ -261,6 +274,7 @@ class _Condition(_Verbose):
_Verbose
.
__init__
(
self
,
verbose
)
if
lock
is
None
:
lock
=
RLock
()
#lock = RSem()
self
.
__lock
=
lock
# Export the lock's acquire() and release() methods
self
.
acquire
=
lock
.
acquire
...
...
@@ -331,7 +345,7 @@ class _Condition(_Verbose):
"""
if
not
self
.
_is_owned
():
raise
RuntimeError
(
"cannot wait on un-acquired lock"
)
waiter
=
_allocate_
lock
()
waiter
=
_allocate_
sem
()
waiter
.
acquire
()
self
.
__waiters
.
append
(
waiter
)
saved_state
=
self
.
_release_save
()
...
...
@@ -434,7 +448,7 @@ class _Semaphore(_Verbose):
if
value
<
0
:
raise
ValueError
(
"semaphore initial value must be >= 0"
)
_Verbose
.
__init__
(
self
,
verbose
)
self
.
__cond
=
Condition
(
Lock
())
self
.
__cond
=
Condition
(
Lock
())
# XXX -> Sem()
self
.
__value
=
value
def
acquire
(
self
,
blocking
=
1
):
...
...
@@ -539,6 +553,7 @@ class _BoundedSemaphore(_Semaphore):
self
.
_Semaphore__cond
.
notify
()
# XXX Sem
def
Event
(
*
args
,
**
kwargs
):
"""A factory function that returns a new event.
...
...
@@ -560,7 +575,7 @@ class _Event(_Verbose):
def
__init__
(
self
,
verbose
=
None
):
_Verbose
.
__init__
(
self
,
verbose
)
self
.
__cond
=
Condition
(
Lock
())
self
.
__cond
=
Condition
(
Sem
())
self
.
__flag
=
False
def
_reset_internal_locks
(
self
):
...
...
@@ -1251,7 +1266,7 @@ def _test():
def
__init__
(
self
,
limit
):
_Verbose
.
__init__
(
self
)
self
.
mon
=
RLock
()
self
.
mon
=
RLock
()
# XXX -> RSem ? XXX or not needed?
self
.
rc
=
Condition
(
self
.
mon
)
self
.
wc
=
Condition
(
self
.
mon
)
self
.
limit
=
limit
...
...
Makefile.pre.in
View file @
91775b95
...
...
@@ -783,15 +783,15 @@ TESTOPTS= -l $(EXTRATESTOPTS)
TESTPROG
=
$(srcdir)
/Lib/test/regrtest.py
TESTPYTHON
=
$(RUNSHARED)
./
$(BUILDPYTHON)
-Wd
-3
-E
-tt
$(TESTPYTHONOPTS)
test
:
all platform
-
find
$(srcdir)
/Lib
-name
'*.py[co]'
-print
| xargs
rm
-f
-
$(TESTPYTHON)
$(TESTPROG)
$(TESTOPTS)
#
-find
$(srcdir)
/Lib
-name
'*.py[co]'
-print
| xargs
rm
-f
#
-
$(TESTPYTHON)
$(TESTPROG)
$(TESTOPTS)
$(TESTPYTHON)
$(TESTPROG)
$(TESTOPTS)
testall
:
all platform
-
find
$(srcdir)
/Lib
-name
'*.py[co]'
-print
| xargs
rm
-f
#
-find
$(srcdir)
/Lib
-name
'*.py[co]'
-print
| xargs
rm
-f
$(TESTPYTHON)
$(srcdir)
/Lib/compileall.py
-
find
$(srcdir)
/Lib
-name
'*.py[co]'
-print
| xargs
rm
-f
-
$(TESTPYTHON)
$(TESTPROG)
-uall
$(TESTOPTS)
#
-find
$(srcdir)
/Lib
-name
'*.py[co]'
-print
| xargs
rm
-f
#
-
$(TESTPYTHON)
$(TESTPROG)
-uall
$(TESTOPTS)
$(TESTPYTHON)
$(TESTPROG)
-uall
$(TESTOPTS)
# Run the unitests for both architectures in a Universal build on OSX
...
...
@@ -818,10 +818,10 @@ buildbottest: all platform
QUICKTESTOPTS
=
$(TESTOPTS)
-x
test_subprocess test_io test_lib2to3
\
test_multibytecodec test_urllib2_localnet test_itertools
\
test_multiprocessing test_mailbox test_socket test_poll
\
test_select test_zipfile
test_select test_zipfile
test_gdb
quicktest
:
all platform
-
find
$(srcdir)
/Lib
-name
'*.py[co]'
-print
| xargs
rm
-f
-
$(TESTPYTHON)
$(TESTPROG)
$(QUICKTESTOPTS)
#
-find
$(srcdir)
/Lib
-name
'*.py[co]'
-print
| xargs
rm
-f
#
-
$(TESTPYTHON)
$(TESTPROG)
$(QUICKTESTOPTS)
$(TESTPYTHON)
$(TESTPROG)
$(QUICKTESTOPTS)
MEMTESTOPTS
=
$(QUICKTESTOPTS)
-x
test_dl test___all__ test_fork1
\
...
...
Modules/threadmodule.c
View file @
91775b95
...
...
@@ -17,7 +17,7 @@ static PyObject *ThreadError;
static
PyObject
*
str_dict
;
static
long
nb_threads
=
0
;
/* Lock objects */
/* Lock
& Sem
objects */
typedef
struct
{
PyObject_HEAD
...
...
@@ -40,6 +40,21 @@ lock_dealloc(lockobject *self)
PyObject_Del
(
self
);
}
static
void
sem_dealloc
(
lockobject
*
self
)
{
if
(
self
->
in_weakreflist
!=
NULL
)
PyObject_ClearWeakRefs
((
PyObject
*
)
self
);
if
(
self
->
lock_lock
!=
NULL
)
{
/* Unlock the lock so it's safe to free it */
PyThread_acquire_sem
(
self
->
lock_lock
,
0
);
PyThread_release_sem
(
self
->
lock_lock
);
PyThread_free_sem
(
self
->
lock_lock
);
}
PyObject_Del
(
self
);
}
static
PyObject
*
lock_PyThread_acquire_lock
(
lockobject
*
self
,
PyObject
*
args
)
{
...
...
@@ -55,6 +70,21 @@ lock_PyThread_acquire_lock(lockobject *self, PyObject *args)
return
PyBool_FromLong
((
long
)
i
);
}
static
PyObject
*
lock_PyThread_acquire_sem
(
lockobject
*
self
,
PyObject
*
args
)
{
int
i
=
1
;
if
(
!
PyArg_ParseTuple
(
args
,
"|i:acquire"
,
&
i
))
return
NULL
;
Py_BEGIN_ALLOW_THREADS
i
=
PyThread_acquire_sem
(
self
->
lock_lock
,
i
);
Py_END_ALLOW_THREADS
return
PyBool_FromLong
((
long
)
i
);
}
PyDoc_STRVAR
(
acquire_doc
,
"acquire([wait]) -> bool
\n
\
(acquire_lock() is an obsolete synonym)
\n
\
...
...
@@ -81,6 +111,21 @@ lock_PyThread_release_lock(lockobject *self)
return
Py_None
;
}
static
PyObject
*
lock_PyThread_release_sem
(
lockobject
*
self
)
{
/* Sanity check: the lock must be locked */
if
(
PyThread_acquire_sem
(
self
->
lock_lock
,
0
))
{
PyThread_release_sem
(
self
->
lock_lock
);
PyErr_SetString
(
ThreadError
,
"release unlocked lock"
);
return
NULL
;
}
PyThread_release_sem
(
self
->
lock_lock
);
Py_INCREF
(
Py_None
);
return
Py_None
;
}
PyDoc_STRVAR
(
release_doc
,
"release()
\n
\
(release_lock() is an obsolete synonym)
\n
\
...
...
@@ -99,6 +144,16 @@ lock_locked_lock(lockobject *self)
return
PyBool_FromLong
(
1L
);
}
static
PyObject
*
lock_locked_sem
(
lockobject
*
self
)
{
if
(
PyThread_acquire_sem
(
self
->
lock_lock
,
0
))
{
PyThread_release_sem
(
self
->
lock_lock
);
return
PyBool_FromLong
(
0L
);
}
return
PyBool_FromLong
(
1L
);
}
PyDoc_STRVAR
(
locked_doc
,
"locked() -> bool
\n
\
(locked_lock() is an obsolete synonym)
\n
\
...
...
@@ -125,6 +180,26 @@ static PyMethodDef lock_methods[] = {
{
NULL
}
/* sentinel */
};
static
PyMethodDef
sem_methods
[]
=
{
// {"acquire_sem", (PyCFunction)lock_PyThread_acquire_sem,
// METH_VARARGS, acquire_doc},
{
"acquire"
,
(
PyCFunction
)
lock_PyThread_acquire_sem
,
METH_VARARGS
,
acquire_doc
},
// {"release_sem", (PyCFunction)lock_PyThread_release_sem,
// METH_NOARGS, release_doc},
{
"release"
,
(
PyCFunction
)
lock_PyThread_release_sem
,
METH_NOARGS
,
release_doc
},
// {"locked_sem", (PyCFunction)lock_locked_sem,
// METH_NOARGS, locked_doc},
{
"locked"
,
(
PyCFunction
)
lock_locked_sem
,
METH_NOARGS
,
locked_doc
},
{
"__enter__"
,
(
PyCFunction
)
lock_PyThread_acquire_sem
,
METH_VARARGS
,
acquire_doc
},
{
"__exit__"
,
(
PyCFunction
)
lock_PyThread_release_sem
,
METH_VARARGS
,
release_doc
},
{
NULL
}
/* sentinel */
};
static
PyTypeObject
Locktype
=
{
PyVarObject_HEAD_INIT
(
&
PyType_Type
,
0
)
"thread.lock"
,
/*tp_name*/
...
...
@@ -157,6 +232,38 @@ static PyTypeObject Locktype = {
lock_methods
,
/* tp_methods */
};
static
PyTypeObject
Semtype
=
{
PyVarObject_HEAD_INIT
(
&
PyType_Type
,
0
)
"thread.sem"
,
/*tp_name*/
sizeof
(
lockobject
),
/*tp_size*/
0
,
/*tp_itemsize*/
/* methods */
(
destructor
)
sem_dealloc
,
/*tp_dealloc*/
0
,
/*tp_print*/
0
,
/*tp_getattr*/
0
,
/*tp_setattr*/
0
,
/*tp_compare*/
0
,
/*tp_repr*/
0
,
/* tp_as_number */
0
,
/* tp_as_sequence */
0
,
/* tp_as_mapping */
0
,
/* tp_hash */
0
,
/* tp_call */
0
,
/* tp_str */
0
,
/* tp_getattro */
0
,
/* tp_setattro */
0
,
/* tp_as_buffer */
Py_TPFLAGS_HAVE_WEAKREFS
,
/* tp_flags */
0
,
/* tp_doc */
0
,
/* tp_traverse */
0
,
/* tp_clear */
0
,
/* tp_richcompare */
offsetof
(
lockobject
,
in_weakreflist
),
/* tp_weaklistoffset */
0
,
/* tp_iter */
0
,
/* tp_iternext */
sem_methods
,
/* tp_methods */
};
static
lockobject
*
newlockobject
(
void
)
{
...
...
@@ -174,6 +281,23 @@ newlockobject(void)
return
self
;
}
static
lockobject
*
newsemobject
(
void
)
{
lockobject
*
self
;
self
=
PyObject_New
(
lockobject
,
&
Semtype
);
if
(
self
==
NULL
)
return
NULL
;
self
->
lock_lock
=
PyThread_allocate_sem
();
self
->
in_weakreflist
=
NULL
;
if
(
self
->
lock_lock
==
NULL
)
{
Py_DECREF
(
self
);
PyErr_SetString
(
ThreadError
,
"can't allocate lock"
);
return
NULL
;
}
return
self
;
}
/* Thread-local objects */
#include "structmember.h"
...
...
@@ -739,6 +863,7 @@ A subthread can use this function to interrupt the main thread."
);
static
lockobject
*
newlockobject
(
void
);
static
lockobject
*
newsemobject
(
void
);
static
PyObject
*
thread_PyThread_allocate_lock
(
PyObject
*
self
)
...
...
@@ -746,6 +871,12 @@ thread_PyThread_allocate_lock(PyObject *self)
return
(
PyObject
*
)
newlockobject
();
}
static
PyObject
*
thread_PyThread_allocate_sem
(
PyObject
*
self
)
{
return
(
PyObject
*
)
newsemobject
();
}
PyDoc_STRVAR
(
allocate_doc
,
"allocate_lock() -> lock object
\n
\
(allocate() is an obsolete synonym)
\n
\
...
...
@@ -856,6 +987,8 @@ static PyMethodDef thread_methods[] = {
start_new_doc
},
{
"allocate_lock"
,
(
PyCFunction
)
thread_PyThread_allocate_lock
,
METH_NOARGS
,
allocate_doc
},
{
"allocate_sem"
,
(
PyCFunction
)
thread_PyThread_allocate_sem
,
METH_NOARGS
,
allocate_doc
},
{
"allocate"
,
(
PyCFunction
)
thread_PyThread_allocate_lock
,
METH_NOARGS
,
allocate_doc
},
{
"exit_thread"
,
(
PyCFunction
)
thread_PyThread_exit_thread
,
...
...
@@ -918,6 +1051,11 @@ initthread(void)
return
;
Py_INCREF
(
&
Locktype
);
PyDict_SetItemString
(
d
,
"LockType"
,
(
PyObject
*
)
&
Locktype
);
Semtype
.
tp_doc
=
lock_doc
;
if
(
PyType_Ready
(
&
Semtype
)
<
0
)
return
;
Py_INCREF
(
&
Semtype
);
PyDict_SetItemString
(
d
,
"SemType"
,
(
PyObject
*
)
&
Semtype
);
Py_INCREF
(
&
localtype
);
if
(
PyModule_AddObject
(
m
,
"_local"
,
(
PyObject
*
)
&
localtype
)
<
0
)
...
...
Objects/obmalloc.c
View file @
91775b95
...
...
@@ -21,7 +21,8 @@
#endif
/* -1 indicates that we haven't checked that we're running on valgrind yet. */
static
int
running_on_valgrind
=
-
1
;
//static int running_on_valgrind = -1;
static
int
running_on_valgrind
=
+
1
;
// XXX kirr: always redirect to malloc/free without tricks
#endif
/* An object allocator for Python.
...
...
Python/ceval.c
View file @
91775b95
...
...
@@ -441,7 +441,7 @@ Py_AddPendingCall(int (*func)(void *), void *arg)
pendinglast
=
j
;
}
/* signal main loop */
_Py_Ticker
=
0
;
_Py_Ticker
=
0
;
// XXX data race with PyEval thread
pendingcalls_to_do
=
1
;
if
(
lock
!=
NULL
)
PyThread_release_lock
(
lock
);
...
...
Python/thread_pthread.h
View file @
91775b95
...
...
@@ -83,6 +83,9 @@
#endif
// XXX kirr - always use pthread mutexes
#undef USE_SEMAPHORES
/* On platforms that don't use standard POSIX threads pthread_sigmask()
* isn't present. DEC threads uses sigprocmask() instead as do most
* other UNIX International compliant systems that don't have the full
...
...
@@ -95,6 +98,12 @@
#endif
static
long
tid
(
void
)
{
//return 0;
return
PyThread_get_thread_ident
();
}
/* A pthread mutex isn't sufficient to model the Python lock type
* because, according to Draft 5 of the docs (P1003.4a/D5), both of the
* following are undefined:
...
...
@@ -111,13 +120,15 @@
*/
typedef
struct
{
#if 0
char locked; /* 0=unlocked, 1=locked */
/* a <cond, mutex> pair to handle an acquire of a locked lock */
pthread_cond_t lock_released;
#endif
pthread_mutex_t
mut
;
}
pthread_lock
;
#define CHECK_STATUS(name) if (status != 0) { perror(name); error = 1; }
#define CHECK_STATUS(name) if (status != 0) { perror(name); error = 1;
abort();
}
/*
* Initialization.
...
...
@@ -141,6 +152,9 @@ PyThread__init_thread(void)
#else
/* !_HAVE_BSDI */
// // python wants recursive mutexes
// static pthread_mutexattr_t mtx_attr;
static
void
PyThread__init_thread
(
void
)
{
...
...
@@ -148,6 +162,12 @@ PyThread__init_thread(void)
extern
void
pthread_init
(
void
);
pthread_init
();
#endif
// int status, error=0;
// status = pthread_mutexattr_init(&mtx_attr);
// CHECK_STATUS("pthread_mutexattr_init");
// status = pthread_mutexattr_settype(&mtx_attr, PTHREAD_MUTEX_ERRORCHECK_NP);
// CHECK_STATUS("pthread_mutexattr_settype");
}
#endif
/* !_HAVE_BSDI */
...
...
@@ -169,7 +189,7 @@ PyThread_start_new_thread(void (*func)(void *), void *arg)
size_t
tss
;
#endif
dprintf
((
"
PyThread_start_new_thread called
\n
"
));
dprintf
((
"
T.%lx PyThread_start_new_thread called
\n
"
,
tid
()
));
if
(
!
initialized
)
PyThread_init_thread
();
...
...
@@ -241,25 +261,26 @@ PyThread_get_thread_ident(void)
void
PyThread_exit_thread
(
void
)
{
dprintf
((
"
PyThread_exit_thread called
\n
"
));
dprintf
((
"
T.%lx PyThread_exit_thread called
\n
"
,
tid
()
));
if
(
!
initialized
)
{
exit
(
0
);
}
}
#ifdef USE_SEMAPHORES
// #ifdef USE_SEMAPHORES
// # if 0
/*
*
Lock
support.
*
Sem
support.
*/
PyThread_type_lock
PyThread_allocate_
lock
(
void
)
PyThread_allocate_
sem
(
void
)
{
sem_t
*
lock
;
int
status
,
error
=
0
;
dprintf
((
"
PyThread_allocate_lock called
\n
"
));
dprintf
((
"
T.%lx PyThread_allocate_sem called
\n
"
,
tid
()
));
if
(
!
initialized
)
PyThread_init_thread
();
...
...
@@ -275,18 +296,18 @@ PyThread_allocate_lock(void)
}
}
dprintf
((
"
PyThread_allocate_lock() -> %p
\n
"
,
lock
));
dprintf
((
"
T.%lx PyThread_allocate_sem() -> %p
\n
"
,
tid
()
,
lock
));
return
(
PyThread_type_lock
)
lock
;
}
void
PyThread_free_
lock
(
PyThread_type_lock
lock
)
PyThread_free_
sem
(
PyThread_type_lock
lock
)
{
sem_t
*
thelock
=
(
sem_t
*
)
lock
;
int
status
,
error
=
0
;
(
void
)
error
;
/* silence unused-but-set-variable warning */
dprintf
((
"
PyThread_free_lock(%p) called
\n
"
,
lock
));
dprintf
((
"
T.%lx PyThread_free_sem(%p) called
\n
"
,
tid
()
,
lock
));
if
(
!
thelock
)
return
;
...
...
@@ -310,14 +331,14 @@ fix_status(int status)
}
int
PyThread_acquire_
lock
(
PyThread_type_lock
lock
,
int
waitflag
)
PyThread_acquire_
sem
(
PyThread_type_lock
lock
,
int
waitflag
)
{
int
success
;
sem_t
*
thelock
=
(
sem_t
*
)
lock
;
int
status
,
error
=
0
;
(
void
)
error
;
/* silence unused-but-set-variable warning */
dprintf
((
"
PyThread_acquire_lock(%p, %d) called
\n
"
,
lock
,
waitflag
));
dprintf
((
"
T.%lx PyThread_acquire_sem(%p, %d) called
\n
"
,
tid
()
,
lock
,
waitflag
));
do
{
if
(
waitflag
)
...
...
@@ -334,24 +355,25 @@ PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
success
=
(
status
==
0
)
?
1
:
0
;
dprintf
((
"
PyThread_acquire_lock(%p, %d) -> %d
\n
"
,
lock
,
waitflag
,
success
));
dprintf
((
"
T.%lx PyThread_acquire_sem(%p, %d) -> %d
\n
"
,
tid
()
,
lock
,
waitflag
,
success
));
return
success
;
}
void
PyThread_release_
lock
(
PyThread_type_lock
lock
)
PyThread_release_
sem
(
PyThread_type_lock
lock
)
{
sem_t
*
thelock
=
(
sem_t
*
)
lock
;
int
status
,
error
=
0
;
(
void
)
error
;
/* silence unused-but-set-variable warning */
dprintf
((
"
PyThread_release_lock(%p) called
\n
"
,
lock
));
dprintf
((
"
T.%lx PyThread_release_sem(%p) called
\n
"
,
tid
()
,
lock
));
status
=
sem_post
(
thelock
);
CHECK_STATUS
(
"sem_post"
);
}
#else
/* USE_SEMAPHORES */
// # endif
// #else /* USE_SEMAPHORES */
/*
* Lock support.
...
...
@@ -362,22 +384,24 @@ PyThread_allocate_lock(void)
pthread_lock
*
lock
;
int
status
,
error
=
0
;
dprintf
((
"
PyThread_allocate_lock called
\n
"
));
dprintf
((
"
T.%lx PyThread_allocate_lock called
\n
"
,
tid
()
));
if
(
!
initialized
)
PyThread_init_thread
();
lock
=
(
pthread_lock
*
)
malloc
(
sizeof
(
pthread_lock
));
if
(
lock
)
{
memset
((
void
*
)
lock
,
'\0'
,
sizeof
(
pthread_lock
));
lock
->
locked
=
0
;
//
lock->locked = 0;
status
=
pthread_mutex_init
(
&
lock
->
mut
,
pthread_mutexattr_default
);
pthread_mutexattr_default
);
//&mtx_attr);
CHECK_STATUS
(
"pthread_mutex_init"
);
#if 0
status = pthread_cond_init(&lock->lock_released,
pthread_condattr_default);
CHECK_STATUS("pthread_cond_init");
#endif
if
(
error
)
{
free
((
void
*
)
lock
);
...
...
@@ -385,7 +409,7 @@ PyThread_allocate_lock(void)
}
}
dprintf
((
"
PyThread_allocate_lock() -> %p
\n
"
,
lock
));
dprintf
((
"
T.%lx PyThread_allocate_lock() -> %p
\n
"
,
tid
()
,
lock
));
return
(
PyThread_type_lock
)
lock
;
}
...
...
@@ -396,13 +420,15 @@ PyThread_free_lock(PyThread_type_lock lock)
int
status
,
error
=
0
;
(
void
)
error
;
/* silence unused-but-set-variable warning */
dprintf
((
"
PyThread_free_lock(%p) called
\n
"
,
lock
));
dprintf
((
"
T.%lx PyThread_free_lock(%p) called
\n
"
,
tid
()
,
lock
));
status
=
pthread_mutex_destroy
(
&
thelock
->
mut
);
CHECK_STATUS
(
"pthread_mutex_destroy"
);
#if 0
status = pthread_cond_destroy( &thelock->lock_released );
CHECK_STATUS("pthread_cond_destroy");
#endif
free
((
void
*
)
thelock
);
}
...
...
@@ -414,10 +440,19 @@ PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
pthread_lock
*
thelock
=
(
pthread_lock
*
)
lock
;
int
status
,
error
=
0
;
dprintf
((
"
PyThread_acquire_lock(%p, %d) called
\n
"
,
lock
,
waitflag
));
dprintf
((
"
T.%lx PyThread_acquire_lock(%p, %d) called
\n
"
,
tid
()
,
lock
,
waitflag
));
status
=
pthread_mutex_lock
(
&
thelock
->
mut
);
CHECK_STATUS
(
"pthread_mutex_lock[1]"
);
if
(
!
waitflag
)
{
status
=
pthread_mutex_trylock
(
&
thelock
->
mut
);
if
(
status
!=
EBUSY
)
CHECK_STATUS
(
"pthread_mutex_trylock[1]"
);
}
else
{
status
=
pthread_mutex_lock
(
&
thelock
->
mut
);
CHECK_STATUS
(
"pthread_mutex_lock[1]"
);
}
#if 0
success = thelock->locked == 0;
if ( !success && waitflag ) {
...
...
@@ -437,7 +472,10 @@ PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
CHECK_STATUS("pthread_mutex_unlock[1]");
if (error) success = 0;
dprintf
((
"PyThread_acquire_lock(%p, %d) -> %d
\n
"
,
lock
,
waitflag
,
success
));
#endif
success
=
(
status
==
0
);
dprintf
((
"T.%lx PyThread_acquire_lock(%p, %d) -> %d
\n
"
,
tid
(),
lock
,
waitflag
,
success
));
return
success
;
}
...
...
@@ -448,22 +486,26 @@ PyThread_release_lock(PyThread_type_lock lock)
int
status
,
error
=
0
;
(
void
)
error
;
/* silence unused-but-set-variable warning */
dprintf
((
"
PyThread_release_lock(%p) called
\n
"
,
lock
));
dprintf
((
"
T.%lx PyThread_release_lock(%p) called
\n
"
,
tid
()
,
lock
));
#if 0
status = pthread_mutex_lock( &thelock->mut );
CHECK_STATUS("pthread_mutex_lock[3]");
thelock->locked = 0;
#endif
status
=
pthread_mutex_unlock
(
&
thelock
->
mut
);
CHECK_STATUS
(
"pthread_mutex_unlock[3]"
);
#if 0
/* wake up someone (anyone, if any) waiting on the lock */
status = pthread_cond_signal( &thelock->lock_released );
CHECK_STATUS("pthread_cond_signal");
#endif
}
#endif
/* USE_SEMAPHORES */
//
#endif /* USE_SEMAPHORES */
/* set the thread stack size.
* Return 0 if size is valid, -1 if size is invalid,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment