[pypy-commit] pypy stm-gc: Add 'transaction.remove_epoll()'.
arigo
noreply at buildbot.pypy.org
Sat Mar 31 17:58:44 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch: stm-gc
Changeset: r54111:22ab9f05fb91
Date: 2012-03-31 17:58 +0200
http://bitbucket.org/pypy/pypy/changeset/22ab9f05fb91/
Log: Add 'transaction.remove_epoll()'.
diff --git a/lib_pypy/transaction.py b/lib_pypy/transaction.py
--- a/lib_pypy/transaction.py
+++ b/lib_pypy/transaction.py
@@ -15,6 +15,9 @@
_pending[r] = (f, args)
def add_epoll(ep, callback):
+ for key, (f, args) in _pending.items():
+ if getattr(f, '_reads_from_epoll_', None) is ep:
+ raise ValueError("add_epoll(ep): ep is already registered")
def poll_reader():
# assume only one epoll is added. If the _pending list is
# now empty, wait. If not, then just poll non-blockingly.
@@ -26,8 +29,17 @@
for fd, events in got:
add(callback, fd, events)
add(poll_reader)
+ poll_reader._reads_from_epoll_ = ep
add(poll_reader)
+def remove_epoll(ep):
+ for key, (f, args) in _pending.items():
+ if getattr(f, '_reads_from_epoll_', None) is ep:
+ del _pending[key]
+ break
+ else:
+ raise ValueError("remove_epoll(ep): ep is not registered")
+
def run():
pending = _pending
try:
diff --git a/pypy/module/transaction/__init__.py b/pypy/module/transaction/__init__.py
--- a/pypy/module/transaction/__init__.py
+++ b/pypy/module/transaction/__init__.py
@@ -9,7 +9,8 @@
'set_num_threads': 'interp_transaction.set_num_threads',
'add': 'interp_transaction.add',
'run': 'interp_transaction.run',
- 'add_epoll': 'interp_epoll.add_epoll', # xxx linux only
+ 'add_epoll': 'interp_epoll.add_epoll', # xxx linux only
+ 'remove_epoll': 'interp_epoll.remove_epoll', # xxx linux only
}
appleveldefs = {
diff --git a/pypy/module/transaction/interp_epoll.py b/pypy/module/transaction/interp_epoll.py
--- a/pypy/module/transaction/interp_epoll.py
+++ b/pypy/module/transaction/interp_epoll.py
@@ -35,6 +35,7 @@
self.evs = lltype.malloc(rffi.CArray(epoll_event), self.maxevents,
flavor='raw', add_memory_pressure=True,
track_allocation=False)
+ self.force_quit = False
def __del__(self):
evs = self.evs
@@ -45,7 +46,7 @@
def run(self):
# This code is run non-transactionally. Careful, no GC available.
state = interp_transaction.state
- if state.has_exception():
+ if state.has_exception() or self.force_quit:
return
fd = rffi.cast(rffi.INT, self.epoller.epfd)
maxevents = rffi.cast(rffi.INT, self.maxevents)
@@ -107,4 +108,25 @@
@unwrap_spec(epoller=W_Epoll)
def add_epoll(space, epoller, w_callback):
- EPollPending(space, epoller, w_callback).register()
+ state = interp_transaction.state
+ if state.epolls is None:
+ state.epolls = {}
+ elif epoller in state.epolls:
+ raise OperationError(space.w_ValueError,
+ space.wrap("add_epoll(ep): ep is already registered"))
+ pending = EPollPending(space, epoller, w_callback)
+ state.epolls[epoller] = pending
+ pending.register()
+
+ at unwrap_spec(epoller=W_Epoll)
+def remove_epoll(space, epoller):
+ state = interp_transaction.state
+ if state.epolls is None:
+ pending = None
+ else:
+ pending = state.epolls.get(epoller, None)
+ if pending is None:
+ raise OperationError(space.w_ValueError,
+ space.wrap("remove_epoll(ep): ep is not registered"))
+ pending.force_quit = True
+ del state.epolls[epoller]
diff --git a/pypy/module/transaction/interp_transaction.py b/pypy/module/transaction/interp_transaction.py
--- a/pypy/module/transaction/interp_transaction.py
+++ b/pypy/module/transaction/interp_transaction.py
@@ -23,6 +23,7 @@
self.ll_no_tasks_pending_lock = threadintf.null_ll_lock
self.ll_unfinished_lock = threadintf.null_ll_lock
self.threadobjs = {} # empty during translation
+ self.epolls = None
self.pending = Fifo()
def _freeze_(self):
@@ -305,6 +306,7 @@
assert not state.is_locked_no_tasks_pending()
state.clear_all_values_apart_from_main()
state.running = False
+ state.epolls = None
#
# now re-raise the exception that we got in a transaction
state.close_exceptions()
diff --git a/pypy/module/transaction/test/test_epoll.py b/pypy/module/transaction/test/test_epoll.py
--- a/pypy/module/transaction/test/test_epoll.py
+++ b/pypy/module/transaction/test/test_epoll.py
@@ -50,6 +50,26 @@
raises(Done, transaction.run)
assert steps == ['write_stuff', 'callback']
+ def test_remove_closed_epoll(self):
+ import transaction, select, posix as os
+
+ fd_read, fd_write = os.pipe()
+
+ epoller = select.epoll()
+ epoller.register(fd_read)
+
+ # we run it 10 times in order to get both possible orders in
+ # the emulator
+ for i in range(10):
+ transaction.add_epoll(epoller, lambda *args: not_actually_callable)
+ transaction.add(transaction.remove_epoll, epoller)
+ transaction.run()
+ # assert didn't deadlock
+ transaction.add(transaction.remove_epoll, epoller)
+ transaction.add_epoll(epoller, lambda *args: not_actually_callable)
+ transaction.run()
+ # assert didn't deadlock
+
class AppTestEpollEmulator(AppTestEpoll):
def setup_class(cls):
More information about the pypy-commit
mailing list