Make executors shallow-const.
diff --git a/asio/include/asio/executor.hpp b/asio/include/asio/executor.hpp
index 3efbda6..d1d6fd3 100644
--- a/asio/include/asio/executor.hpp
+++ b/asio/include/asio/executor.hpp
@@ -126,19 +126,19 @@
   }
 
   /// Obtain the underlying execution context.
-  execution_context& context() ASIO_NOEXCEPT
+  execution_context& context() const ASIO_NOEXCEPT
   {
     return get_impl()->context();
   }
 
   /// Inform the executor that it has some outstanding work to do.
-  void on_work_started() ASIO_NOEXCEPT
+  void on_work_started() const ASIO_NOEXCEPT
   {
     get_impl()->on_work_started();
   }
 
   /// Inform the executor that some work is no longer outstanding.
-  void on_work_finished() ASIO_NOEXCEPT
+  void on_work_finished() const ASIO_NOEXCEPT
   {
     get_impl()->on_work_finished();
   }
@@ -157,7 +157,7 @@
    * internal storage needed for function invocation.
    */
   template <typename Function, typename Allocator>
-  void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+  void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
 
   /// Request the executor to invoke the given function object.
   /**
@@ -173,7 +173,7 @@
    * internal storage needed for function invocation.
    */
   template <typename Function, typename Allocator>
-  void post(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+  void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
 
   /// Request the executor to invoke the given function object.
   /**
@@ -189,7 +189,7 @@
    * internal storage needed for function invocation.
    */
   template <typename Function, typename Allocator>
-  void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+  void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
 
   struct unspecified_bool_type_t {};
   typedef void (*unspecified_bool_type)(unspecified_bool_type_t);
@@ -301,7 +301,7 @@
   };
 
   // Helper function to check and return the implementation pointer.
-  impl_base* get_impl()
+  impl_base* get_impl() const
   {
     if (!impl_)
     {
diff --git a/asio/include/asio/impl/executor.hpp b/asio/include/asio/impl/executor.hpp
index 8aa9079..7c0766e 100644
--- a/asio/include/asio/impl/executor.hpp
+++ b/asio/include/asio/impl/executor.hpp
@@ -344,7 +344,8 @@
 }
 
 template <typename Function, typename Allocator>
-void executor::dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a)
+void executor::dispatch(ASIO_MOVE_ARG(Function) f,
+    const Allocator& a) const
 {
   impl_base* i = get_impl();
   if (i->fast_dispatch_)
@@ -354,13 +355,15 @@
 }
 
 template <typename Function, typename Allocator>
-void executor::post(ASIO_MOVE_ARG(Function) f, const Allocator& a)
+void executor::post(ASIO_MOVE_ARG(Function) f,
+    const Allocator& a) const
 {
   get_impl()->post(function(ASIO_MOVE_CAST(Function)(f), a));
 }
 
 template <typename Function, typename Allocator>
-void executor::defer(ASIO_MOVE_ARG(Function) f, const Allocator& a)
+void executor::defer(ASIO_MOVE_ARG(Function) f,
+    const Allocator& a) const
 {
   get_impl()->defer(function(ASIO_MOVE_CAST(Function)(f), a));
 }
diff --git a/asio/include/asio/impl/io_context.hpp b/asio/include/asio/impl/io_context.hpp
index 9045440..b10491f 100644
--- a/asio/include/asio/impl/io_context.hpp
+++ b/asio/include/asio/impl/io_context.hpp
@@ -148,24 +148,26 @@
 #endif // !defined(ASIO_NO_DEPRECATED)
 
 inline io_context&
-io_context::executor_type::context() ASIO_NOEXCEPT
+io_context::executor_type::context() const ASIO_NOEXCEPT
 {
   return io_context_;
 }
 
-inline void io_context::executor_type::on_work_started() ASIO_NOEXCEPT
+inline void
+io_context::executor_type::on_work_started() const ASIO_NOEXCEPT
 {
   io_context_.impl_.work_started();
 }
 
-inline void io_context::executor_type::on_work_finished() ASIO_NOEXCEPT
+inline void
+io_context::executor_type::on_work_finished() const ASIO_NOEXCEPT
 {
   io_context_.impl_.work_finished();
 }
 
 template <typename Function, typename Allocator>
 void io_context::executor_type::dispatch(
-    ASIO_MOVE_ARG(Function) f, const Allocator& a)
+    ASIO_MOVE_ARG(Function) f, const Allocator& a) const
 {
   // Make a local, non-const copy of the function.
   typedef typename decay<Function>::type function_type;
@@ -198,7 +200,7 @@
 
 template <typename Function, typename Allocator>
 void io_context::executor_type::post(
-    ASIO_MOVE_ARG(Function) f, const Allocator& a)
+    ASIO_MOVE_ARG(Function) f, const Allocator& a) const
 {
   // Make a local, non-const copy of the function.
   typedef typename decay<Function>::type function_type;
@@ -223,7 +225,7 @@
 
 template <typename Function, typename Allocator>
 void io_context::executor_type::defer(
-    ASIO_MOVE_ARG(Function) f, const Allocator& a)
+    ASIO_MOVE_ARG(Function) f, const Allocator& a) const
 {
   // Make a local, non-const copy of the function.
   typedef typename decay<Function>::type function_type;
diff --git a/asio/include/asio/impl/system_executor.hpp b/asio/include/asio/impl/system_executor.hpp
index bcf429b..29f6a0a 100644
--- a/asio/include/asio/impl/system_executor.hpp
+++ b/asio/include/asio/impl/system_executor.hpp
@@ -25,14 +25,14 @@
 
 namespace asio {
 
-inline execution_context& system_executor::context() ASIO_NOEXCEPT
+inline execution_context& system_executor::context() const ASIO_NOEXCEPT
 {
   return detail::global<context_impl>();
 }
 
 template <typename Function, typename Allocator>
 void system_executor::dispatch(
-    ASIO_MOVE_ARG(Function) f, const Allocator&)
+    ASIO_MOVE_ARG(Function) f, const Allocator&) const
 {
   typename decay<Function>::type tmp(ASIO_MOVE_CAST(Function)(f));
   asio_handler_invoke_helpers::invoke(tmp, tmp);
@@ -40,7 +40,7 @@
 
 template <typename Function, typename Allocator>
 void system_executor::post(
-    ASIO_MOVE_ARG(Function) f, const Allocator& a)
+    ASIO_MOVE_ARG(Function) f, const Allocator& a) const
 {
   context_impl& ctx = detail::global<context_impl>();
 
@@ -66,7 +66,7 @@
 
 template <typename Function, typename Allocator>
 void system_executor::defer(
-    ASIO_MOVE_ARG(Function) f, const Allocator& a)
+    ASIO_MOVE_ARG(Function) f, const Allocator& a) const
 {
   context_impl& ctx = detail::global<context_impl>();
 
diff --git a/asio/include/asio/impl/thread_pool.hpp b/asio/include/asio/impl/thread_pool.hpp
index 7e9b6c4..7aeee4e 100644
--- a/asio/include/asio/impl/thread_pool.hpp
+++ b/asio/include/asio/impl/thread_pool.hpp
@@ -32,24 +32,26 @@
 }
 
 inline thread_pool&
-thread_pool::executor_type::context() ASIO_NOEXCEPT
+thread_pool::executor_type::context() const ASIO_NOEXCEPT
 {
   return pool_;
 }
 
-inline void thread_pool::executor_type::on_work_started() ASIO_NOEXCEPT
+inline void
+thread_pool::executor_type::on_work_started() const ASIO_NOEXCEPT
 {
   pool_.scheduler_.work_started();
 }
 
-inline void thread_pool::executor_type::on_work_finished() ASIO_NOEXCEPT
+inline void thread_pool::executor_type::on_work_finished()
+const ASIO_NOEXCEPT
 {
   pool_.scheduler_.work_finished();
 }
 
 template <typename Function, typename Allocator>
 void thread_pool::executor_type::dispatch(
-    ASIO_MOVE_ARG(Function) f, const Allocator& a)
+    ASIO_MOVE_ARG(Function) f, const Allocator& a) const
 {
   // Make a local, non-const copy of the function.
   typedef typename decay<Function>::type function_type;
@@ -82,7 +84,7 @@
 
 template <typename Function, typename Allocator>
 void thread_pool::executor_type::post(
-    ASIO_MOVE_ARG(Function) f, const Allocator& a)
+    ASIO_MOVE_ARG(Function) f, const Allocator& a) const
 {
   // Make a local, non-const copy of the function.
   typedef typename decay<Function>::type function_type;
@@ -107,7 +109,7 @@
 
 template <typename Function, typename Allocator>
 void thread_pool::executor_type::defer(
-    ASIO_MOVE_ARG(Function) f, const Allocator& a)
+    ASIO_MOVE_ARG(Function) f, const Allocator& a) const
 {
   // Make a local, non-const copy of the function.
   typedef typename decay<Function>::type function_type;
diff --git a/asio/include/asio/io_context.hpp b/asio/include/asio/io_context.hpp
index 7fb49a9..96a0a33 100644
--- a/asio/include/asio/io_context.hpp
+++ b/asio/include/asio/io_context.hpp
@@ -503,7 +503,7 @@
 {
 public:
   /// Obtain the underlying execution context.
-  io_context& context() ASIO_NOEXCEPT;
+  io_context& context() const ASIO_NOEXCEPT;
 
   /// Inform the io_context that it has some outstanding work to do.
   /**
@@ -511,7 +511,7 @@
    * This ensures that the io_context's run() and run_one() functions do not
    * exit while the work is underway.
    */
-  void on_work_started() ASIO_NOEXCEPT;
+  void on_work_started() const ASIO_NOEXCEPT;
 
   /// Inform the io_context that some work is no longer outstanding.
   /**
@@ -519,7 +519,7 @@
    * finished. Once the count of unfinished work reaches zero, the io_context
    * is stopped and the run() and run_one() functions may exit.
    */
-  void on_work_finished() ASIO_NOEXCEPT;
+  void on_work_finished() const ASIO_NOEXCEPT;
 
   /// Request the io_context to invoke the given function object.
   /**
@@ -536,7 +536,7 @@
    * internal storage needed for function invocation.
    */
   template <typename Function, typename Allocator>
-  void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+  void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
 
   /// Request the io_context to invoke the given function object.
   /**
@@ -552,7 +552,7 @@
    * internal storage needed for function invocation.
    */
   template <typename Function, typename Allocator>
-  void post(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+  void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
 
   /// Request the io_context to invoke the given function object.
   /**
@@ -572,7 +572,7 @@
    * internal storage needed for function invocation.
    */
   template <typename Function, typename Allocator>
-  void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+  void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
 
   /// Determine whether the io_context is running in the current thread.
   /**
diff --git a/asio/include/asio/system_executor.hpp b/asio/include/asio/system_executor.hpp
index 07c7874..e227687 100644
--- a/asio/include/asio/system_executor.hpp
+++ b/asio/include/asio/system_executor.hpp
@@ -36,13 +36,13 @@
 {
 public:
   /// Obtain the underlying execution context.
-  execution_context& context() ASIO_NOEXCEPT;
+  execution_context& context() const ASIO_NOEXCEPT;
 
   /// Inform the executor that it has some outstanding work to do.
   /**
    * For the system executor, this is a no-op.
    */
-  void on_work_started() ASIO_NOEXCEPT
+  void on_work_started() const ASIO_NOEXCEPT
   {
   }
 
@@ -50,7 +50,7 @@
   /**
    * For the system executor, this is a no-op.
    */
-  void on_work_finished() ASIO_NOEXCEPT
+  void on_work_finished() const ASIO_NOEXCEPT
   {
   }
 
@@ -67,7 +67,7 @@
    * internal storage needed for function invocation.
    */
   template <typename Function, typename Allocator>
-  void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+  void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
 
   /// Request the system executor to invoke the given function object.
   /**
@@ -83,7 +83,7 @@
    * internal storage needed for function invocation.
    */
   template <typename Function, typename Allocator>
-  void post(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+  void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
 
   /// Request the system executor to invoke the given function object.
   /**
@@ -99,7 +99,7 @@
    * internal storage needed for function invocation.
    */
   template <typename Function, typename Allocator>
-  void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+  void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
 
   /// Compare two executors for equality.
   /**
diff --git a/asio/include/asio/thread_pool.hpp b/asio/include/asio/thread_pool.hpp
index 2a6b460..f3182bf 100644
--- a/asio/include/asio/thread_pool.hpp
+++ b/asio/include/asio/thread_pool.hpp
@@ -83,7 +83,7 @@
 {
 public:
   /// Obtain the underlying execution context.
-  thread_pool& context() ASIO_NOEXCEPT;
+  thread_pool& context() const ASIO_NOEXCEPT;
 
   /// Inform the thread pool that it has some outstanding work to do.
   /**
@@ -91,7 +91,7 @@
    * This ensures that the thread pool's join() function will not return while
    * the work is underway.
    */
-  void on_work_started() ASIO_NOEXCEPT;
+  void on_work_started() const ASIO_NOEXCEPT;
 
   /// Inform the thread pool that some work is no longer outstanding.
   /**
@@ -99,7 +99,7 @@
    * finished. Once the count of unfinished work reaches zero, the thread
    * pool's join() function is permitted to exit.
    */
-  void on_work_finished() ASIO_NOEXCEPT;
+  void on_work_finished() const ASIO_NOEXCEPT;
 
   /// Request the thread pool to invoke the given function object.
   /**
@@ -116,7 +116,7 @@
    * internal storage needed for function invocation.
    */
   template <typename Function, typename Allocator>
-  void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+  void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
 
   /// Request the thread pool to invoke the given function object.
   /**
@@ -132,7 +132,7 @@
    * internal storage needed for function invocation.
    */
   template <typename Function, typename Allocator>
-  void post(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+  void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
 
   /// Request the thread pool to invoke the given function object.
   /**
@@ -152,7 +152,7 @@
    * internal storage needed for function invocation.
    */
   template <typename Function, typename Allocator>
-  void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a);
+  void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
 
   /// Determine whether the thread pool is running in the current thread.
   /**
diff --git a/asio/src/doc/requirements/Executor.qbk b/asio/src/doc/requirements/Executor.qbk
index 9be992b..569410c 100644
--- a/asio/src/doc/requirements/Executor.qbk
+++ b/asio/src/doc/requirements/Executor.qbk
@@ -8,25 +8,33 @@
 [section:Executor1 Executor requirements]
 
 The library describes a standard set of requirements for ['executors]. A type
-meeting Executor requirements shall embody a set of rules for determining how
+meeting the `Executor` requirements embodies a set of rules for determining how
 submitted function objects are to be executed.
 
-An executor type `X` shall satisfy the requirements of `CopyConstructible` (C++
-Std, [copyconstructible]) types. No constructor, comparison operator, copy
-operation, move operation, swap operation, or member functions `context`,
-`on_work_started` and `on_work_finished` on these types shall exit via an
-exception.
+A type `X` meets the `Executor` requirements if it satisfies the requirements of
+`CopyConstructible` (C++Std [copyconstructible]) and `Destructible` (C++Std
+[destructible]), as well as the additional requirements listed below.
 
-The executor copy constructor, comparison operators, and member functions
+No constructor, comparison operator, copy operation, move operation, swap
+operation, or member functions `context`, `on_work_started`, and
+`on_work_finished` on these types shall exit via an exception.
+
+The executor copy constructor, comparison operators, and other member functions
 defined in these requirements shall not introduce data races as a result of
 concurrent calls to those functions from different threads.
 
-In the table below, `X` denotes an executor class, `x` denotes a value of type
-`X&`, `x1` and `x2` denote values of type `const X&`, `x3` denotes a value of
-type `X&&`, `f` denotes a `MoveConstructible` (C++ Std, [moveconstructible])
-function object callable with zero arguments, `a` denotes a value of type `A`
-meeting `Allocator` requirements (C++ Std, [allocator.requirements]), `t`
-denotes an object of type `T`, and `u` denotes an identifier.
+Let `ctx` be the execution context returned by the executor's `context()`
+member function. An executor becomes ['invalid] when the first call to
+`ctx.shutdown()` returns. The effect of calling `on_work_started`,
+`on_work_finished`, `dispatch`, `post`, or `defer` on an invalid executor is
+undefined. [inline_note The copy constructor, comparison operators, and
+`context()` member function continue to remain valid until `ctx` is destroyed.]
+
+In the table below, `x1` and `x2` denote (possibly const) values of type `X`,
+`mx1` denotes an xvalue of type `X`, `f` denotes a `MoveConstructible` (C++Std
+[moveconstructible]) function object callable with zero arguments, `a` denotes
+a (possibly const) value of type `A` meeting the `Allocator` requirements
+(C++Std [allocator.requirements]), and `u` denotes an identifier.
 
 [table Executor requirements
   [[expression] [type] [assertion/note\npre/post-conditions]]
@@ -35,24 +43,25 @@
     []
     [Shall not exit via an exception.\n
      \n
-     post: `u == x1`]
+     post: `u == x1` and
+     `std::addressof(u.context()) == std::addressof(x1.context()).`]
   ]
   [
-    [`X u(x3);`]
+    [`X u(mx1);`]
     []
     [Shall not exit via an exception.\n
      \n
-     post: `u` equals the prior value of `x3`.]
+     post: `u` equals the prior value of `mx1` and
+     `std::addressof(u.context())` equals the prior value of
+     `std::addressof(mx1.context())`.]
   ]
   [
     [`x1 == x2`]
     [`bool`]
-    [Shall not exit via an exception.\n
-     \n
-     Returns `true` only if `x1` and `x2` can be interchanged with identical
+    [ Returns `true` only if `x1` and `x2` can be interchanged with identical
      effects in any of the expressions defined in these type requirements.
-     Note: `false` does not necessarily imply that the effects are not
-     identical.\n
+     [inline_note Returning `false` does not necessarily imply that the effects
+     are not identical.]\n
      \n
      `operator==` shall be reflexive, symmetric, and transitive, and shall not
      exit via an exception.]
@@ -60,71 +69,72 @@
   [
     [`x1 != x2`]
     [`bool`]
+    [Same as `!(x1 == x2)`.]
+  ]
+  [
+    [`x1.context()`]
+    [`execution_context&`, or `E&` where `E` is a type that satifisfies the
+     [link requirements.execution_context `ExecutionContext`] requirements.]
     [Shall not exit via an exception.\n
      \n
-     Same as `!(x1 == x2)`.]
+     The comparison operators and member functions defined in these
+     requirements shall not alter the reference returned by this function.]
   ]
   [
-    [`x.context()`]
-    [`execution_context&`, or a type that is convertible to `execution_context&`.]
-    [Shall not exit via an exception.]
-  ]
-  [
-    [`x.on_work_started()`]
+    [`x1.on_work_started()`]
     []
     [Shall not exit via an exception.]
   ]
   [
-    [`x.on_work_finished()`]
+    [`x1.on_work_finished()`]
     []
     [Shall not exit via an exception.\n
      \n
-     Requires: A preceding call `x1.on_work_started()` where `x == x1`.]
+     Precondition: A preceding call `x2.on_work_started()` where `x1 == x2`.]
   ]
   [
-    [`x.dispatch(std::move(f),a)`]
+    [`x1.dispatch(std::move(f),a)`]
     []
-    [Effects: Calls [^['DECAY_COPY]]`(forward<Func>(f))()` at most once. The
-     executor may invoke `f` in the current thread, prior to returning from
-     `dispatch`. The call to `DECAY_COPY()` is evaluated in the thread that
-     called `dispatch`.\n
+    [Effects: Creates an object `f1` initialized with
+     [^['DECAY_COPY]]`(forward<Func>(f))` (C++Std \[thread.decaycopy\]) in the
+     current thread of execution . Calls `f1()` at most once. The executor may
+     block forward progress of the caller until `f1()` finishes execution.\n
      \n
-     Executor implementations are encouraged to use the supplied allocator to
-     allocate any memory required to store the function object. The executor
-     shall deallocate all memory prior to invoking the function object.\n
+     Executor implementations should use the supplied allocator to allocate any
+     memory required to store the function object. Prior to invoking the
+     function object, the executor shall deallocate any memory allocated.
+     [inline_note Executors defined in this Technical Specification always use
+     the supplied allocator unless otherwise specified.]\n
      \n
-     Synchronization: The invocation of `dispatch` synchronizes with (C++ Std,
-     \[intro.multithread\]) the invocation of `f`.]
+     Synchronization: The invocation of `dispatch` synchronizes with (C++Std
+     \[intro.multithread\]) the invocation of `f1`.]
   ]
   [
-    [`x.post(std::move(f),a)`]
+    [`x1.post(std::move(f),a)`\n
+     `x1.defer(std::move(f),a)`]
     []
-    [Effects: Calls [^['DECAY_COPY]]`(forward<Func>(f))()` at most once. The
-     executor may not invoke `f` in the current thread, prior to returning from
-     `post`. The call to `DECAY_COPY()` is evaluated in the thread that called
-     `post`.\n
+    [Effects: Creates an object `f1` initialized with
+     [^['DECAY_COPY]]`(forward<Func>(f))` in the current thread of execution.
+     Calls `f1()` at most once. The executor shall not block forward progress
+     of the caller pending completion of `f1()`.\n
      \n
-     Executor implementations are encouraged to use the supplied allocator to
-     allocate any memory required to store the function object. The executor
-     shall deallocate all memory prior to invoking the function object.\n
+     Executor implementations should use the supplied allocator to allocate any
+     memory required to store the function object. Prior to invoking the
+     function object, the executor shall deallocate any memory allocated.
+     [inline_note Executors defined in this Technical Specification always use
+     the supplied allocator unless otherwise specified.]\n
      \n
-     Synchronization: The invocation of `post` synchronizes with (C++ Std,
-     \[intro.multithread\]) the invocation of `f`.]
-  ]
-  [
-    [`x.defer(std::move(f),a)`]
-    []
-    [Effects: Calls [^['DECAY_COPY]]`(forward<Func>(f))()` at most once. The
-     executor may not invoke `f` in the current thread, prior to returning from
-     `defer`. The call to `DECAY_COPY()` is evaluated in the thread that called
-     `defer`.\n
+     Synchronization: The invocation of `post` or `defer` synchronizes with
+     (C++Std \[intro.multithread\]) the invocation of `f1`.\n
      \n
-     Executor implementations are encouraged to use the supplied allocator to
-     allocate any memory required to store the function object. The executor
-     shall deallocate all memory prior to invoking the function object.\n
-     \n
-     Synchronization: The invocation of `defer` synchronizes with (C++ Std,
-     \[intro.multithread\]) the invocation of `f`.]
+     [inline_note Although the requirements placed on `defer` are identical to
+     `post`, the use of `post` conveys a preference that the caller ['does not]
+     block the first step of [^f1]'s progress, whereas `defer` conveys a
+     preference that the caller ['does] block the first step of [^f1]. One use
+     of `defer` is to convey the intention of the caller that [^f1] is a
+     continuation of the current call context. The executor may use this
+     information to optimize or otherwise adjust the way in which `f1` is
+     invoked.]]
   ]
 ]