Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
Kirill Smelkov
cpython
Commits
91775b95
Commit
91775b95
authored
10 years ago
by
Kirill Smelkov
Browse files
Options
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
);
...
...
This diff is collapsed.
Click to expand it.
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
():
...
...
This diff is collapsed.
Click to expand it.
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
,
...
...
This diff is collapsed.
Click to expand it.
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
Lock
Tests
(
lock_tests
.
Lock
Tests
):
locktype
=
thread
.
allocate_
lock
class
Sem
Tests
(
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__"
:
...
...
This diff is collapsed.
Click to expand it.
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
...
...
This diff is collapsed.
Click to expand it.
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
,
)
...
...
This diff is collapsed.
Click to expand it.
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
):
...
...
This diff is collapsed.
Click to expand it.
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
...
...
This diff is collapsed.
Click to expand it.
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
\
...
...
This diff is collapsed.
Click to expand it.
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
)
...
...
This diff is collapsed.
Click to expand it.
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.
...
...
This diff is collapsed.
Click to expand it.
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
);
...
...
This diff is collapsed.
Click to expand it.
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,
...
...
This diff is collapsed.
Click to expand it.
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