Fix potential data race due to reading the reactor pointer outside the lock.
diff --git a/asio/include/asio/detail/impl/epoll_reactor.ipp b/asio/include/asio/detail/impl/epoll_reactor.ipp
index 7e092bd..5502144 100644
--- a/asio/include/asio/detail/impl/epoll_reactor.ipp
+++ b/asio/include/asio/detail/impl/epoll_reactor.ipp
@@ -606,8 +606,9 @@
 
 operation* epoll_reactor::descriptor_state::perform_io(uint32_t events)
 {
+  mutex_.lock();
   perform_io_cleanup_on_block_exit io_cleanup(reactor_);
-  mutex::scoped_lock descriptor_lock(mutex_);
+  mutex::scoped_lock descriptor_lock(mutex_, mutex::scoped_lock::adopt_lock);
 
   // Exception operations must be processed first to ensure that any
   // out-of-band data is read before normal data.
diff --git a/asio/include/asio/detail/scoped_lock.hpp b/asio/include/asio/detail/scoped_lock.hpp
index cc225f2..5529818 100644
--- a/asio/include/asio/detail/scoped_lock.hpp
+++ b/asio/include/asio/detail/scoped_lock.hpp
@@ -28,8 +28,18 @@
   : private noncopyable
 {
 public:
+  // Tag type used to distinguish constructors.
+  enum adopt_lock_t { adopt_lock };
+
+  // Constructor adopts a lock that is already held.
+  scoped_lock(Mutex& m, adopt_lock_t)
+    : mutex_(m),
+      locked_(true)
+  {
+  }
+
   // Constructor acquires the lock.
-  scoped_lock(Mutex& m)
+  explicit scoped_lock(Mutex& m)
     : mutex_(m)
   {
     mutex_.lock();