diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index 2841a81..b1d7713 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -575,10 +575,6 @@
     mi->n_clients_delta = 0;
 
     /* prevent dangling pointers */
-    if (m->pending == mi)
-    {
-        multi_set_pending(m, NULL);
-    }
     if (m->earliest_wakeup == mi)
     {
         m->earliest_wakeup = NULL;
@@ -3098,18 +3094,15 @@
             ret = false;
         }
     }
+#ifdef MULTI_DEBUG_EVENT_LOOP
     else
     {
-        /* continue to pend on output? */
-        multi_set_pending(m, ANY_OUT(&mi->context) ? mi : NULL);
-
-#ifdef MULTI_DEBUG_EVENT_LOOP
-        printf("POST %s[%d] to=%d lo=%d/%d w=%" PRIi64 "/%ld\n", id(mi), (int)(mi == m->pending),
+        printf("POST %s[%d] to=%d lo=%d/%d w=%" PRIi64 "/%ld\n", id(mi), (int)ANY_OUT(&mi->context),
                mi->context.c2.to_tun.len, mi->context.c2.to_link.len,
                mi->context.c2.fragment ? mi->context.c2.fragment->outgoing.len : -1,
                (int64_t)mi->context.c2.timeval.tv_sec, (long)mi->context.c2.timeval.tv_usec);
-#endif
     }
+#endif
 
     if ((flags & MPP_RECORD_TOUCH) && m->mpp_touched)
     {
@@ -3400,13 +3393,14 @@
  * data packets.
  */
 static void
-multi_process_incoming_link_data(struct multi_context *m, bool floated, struct link_socket *sock)
+multi_process_incoming_link_data(struct multi_context *m, struct multi_instance *mi, bool floated,
+                                 struct link_socket *sock)
 {
     struct link_socket_info *lsi = &sock->info;
     const uint8_t *orig_buf;
 
     /* decrypt in instance context */
-    struct context *c = &m->pending->context;
+    struct context *c = &mi->context;
 
     orig_buf = c->c2.buf.data;
     if (process_incoming_link_part1(c, lsi, floated))
@@ -3414,7 +3408,7 @@
         /* nonzero length means that we have a valid, decrypted packed */
         if (floated && c->c2.buf.len > 0)
         {
-            multi_process_float(m, m->pending, sock);
+            multi_process_float(m, mi, sock);
         }
 
         process_incoming_link_part2(c, lsi, orig_buf);
@@ -3433,7 +3427,7 @@
             c->c2.to_tun.len = 0;
         }
         /* make sure that source address is associated with this client */
-        else if (multi_get_instance_by_virtual_addr(m, &src, true) != m->pending)
+        else if (multi_get_instance_by_virtual_addr(m, &src, true) != mi)
         {
             /* IPv6 link-local address (fe80::xxx)? */
             if ((src.type & MR_ADDR_MASK) == MR_ADDR_IPV6
@@ -3458,18 +3452,18 @@
             if (mroute_flags & MROUTE_EXTRACT_MCAST)
             {
                 /* for now, treat multicast as broadcast */
-                multi_bcast(m, &c->c2.to_tun, m->pending, 0);
+                multi_bcast(m, &c->c2.to_tun, mi, 0);
             }
             else /* possible client to client routing */
             {
                 ASSERT(!(mroute_flags & MROUTE_EXTRACT_BCAST));
-                struct multi_instance *mi = multi_get_instance_by_virtual_addr(m, &dest, true);
+                struct multi_instance *dest_mi = multi_get_instance_by_virtual_addr(m, &dest, true);
 
                 /* if dest addr is a known client, route to it */
-                if (mi)
+                if (dest_mi)
                 {
                     {
-                        multi_unicast(m, &c->c2.to_tun, mi);
+                        multi_unicast(m, &c->c2.to_tun, dest_mi);
                         register_activity(c, BLEN(&c->c2.to_tun));
                     }
                     c->c2.to_tun.len = 0;
@@ -3502,23 +3496,24 @@
 
         if (mroute_flags & MROUTE_EXTRACT_SUCCEEDED)
         {
-            if (multi_learn_addr(m, m->pending, &src, 0) == m->pending)
+            if (multi_learn_addr(m, mi, &src, 0) == mi)
             {
                 /* check for broadcast */
                 if (m->enable_c2c)
                 {
                     if (mroute_flags & (MROUTE_EXTRACT_BCAST | MROUTE_EXTRACT_MCAST))
                     {
-                        multi_bcast(m, &c->c2.to_tun, m->pending, vid);
+                        multi_bcast(m, &c->c2.to_tun, mi, vid);
                     }
                     else /* try client-to-client routing */
                     {
-                        struct multi_instance *mi = multi_get_instance_by_virtual_addr(m, &dest, false);
+                        struct multi_instance *dest_mi =
+                            multi_get_instance_by_virtual_addr(m, &dest, false);
 
                         /* if dest addr is a known client, route to it */
-                        if (mi)
+                        if (dest_mi)
                         {
-                            multi_unicast(m, &c->c2.to_tun, mi);
+                            multi_unicast(m, &c->c2.to_tun, dest_mi);
                             register_activity(c, BLEN(&c->c2.to_tun));
                             c->c2.to_tun.len = 0;
                         }
@@ -3550,35 +3545,27 @@
 multi_process_incoming_link(struct multi_context *m, struct multi_instance *instance,
                             const unsigned int mpp_flags, struct link_socket *sock)
 {
+    struct multi_instance *mi = instance;
     struct context *c;
     bool ret = true;
     bool floated = false;
 
-    if (m->pending)
-    {
-        return true;
-    }
-
-    if (!instance)
+    if (!mi)
     {
 #ifdef MULTI_DEBUG_EVENT_LOOP
         printf("TCP/UDP -> TUN [%d]\n", BLEN(&m->top.c2.buf));
 #endif
-        multi_set_pending(m, multi_get_create_instance_udp(m, &floated, sock));
-    }
-    else
-    {
-        multi_set_pending(m, instance);
+        mi = multi_get_create_instance_udp(m, &floated, sock);
     }
 
-    if (!m->pending)
+    if (!mi)
     {
         return true;
     }
-    set_prefix(m->pending);
+    set_prefix(mi);
 
     /* get instance context */
-    c = &m->pending->context;
+    c = &mi->context;
 
     if (!instance)
     {
@@ -3594,11 +3581,11 @@
 
     if (BLEN(&c->c2.buf) > 0)
     {
-        multi_process_incoming_link_data(m, floated, sock);
+        multi_process_incoming_link_data(m, mi, floated, sock);
     }
 
     /* postprocess and set wakeup */
-    ret = multi_process_post(m, m->pending, mpp_flags);
+    ret = multi_process_post(m, mi, mpp_flags);
 
     clear_prefix();
 
@@ -3625,11 +3612,6 @@
         printf("TUN -> TCP/UDP [%d]\n", BLEN(&m->top.c2.buf));
 #endif
 
-        if (m->pending)
-        {
-            return true;
-        }
-
         if (dev_type == DEV_TYPE_TAP && m->top.options.vlan_tagging)
         {
             vid = vlan_decapsulate(&m->top, &m->top.c2.buf);
@@ -3657,18 +3639,18 @@
             }
             else
             {
-                multi_set_pending(
-                    m, multi_get_instance_by_virtual_addr(m, &dest, dev_type == DEV_TYPE_TUN));
+                struct multi_instance *mi =
+                    multi_get_instance_by_virtual_addr(m, &dest, dev_type == DEV_TYPE_TUN);
 
-                if (m->pending)
+                if (mi)
                 {
                     /* get instance context */
-                    c = &m->pending->context;
+                    c = &mi->context;
 
-                    set_prefix(m->pending);
+                    set_prefix(mi);
 
                     {
-                        if (multi_output_queue_ready(m, m->pending))
+                        if (multi_output_queue_ready(m, mi))
                         {
                             /* transfer packet pointer from top-level context buffer to instance */
                             c->c2.buf = m->top.c2.buf;
@@ -3686,7 +3668,7 @@
                     process_incoming_tun(c, c->c2.link_sockets[0]);
 
                     /* postprocess and set wakeup */
-                    ret = multi_process_post(m, m->pending, mpp_flags);
+                    ret = multi_process_post(m, mi, mpp_flags);
 
                     clear_prefix();
                 }
diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h
index 31635ba..02841af 100644
--- a/src/openvpn/multi.h
+++ b/src/openvpn/multi.h
@@ -206,8 +206,11 @@
     unsigned long cid_counter;
 #endif
 
-    struct multi_instance *pending;
     struct multi_instance *earliest_wakeup;
+    /* While multi_io_dispatch() runs an action, points to its local where
+     * multi_process_post() with MPP_RECORD_TOUCH stores the instance it
+     * processed.  An action post-processes at most one instance, which
+     * multi_io_action() then closes on signal or writes the output of. */
     struct multi_instance **mpp_touched;
     struct context_buffers *context_buffers;
     time_t per_second_trigger;
@@ -638,11 +641,6 @@
  */
 #define MULTI_CHECK_SIG(m) EVENT_LOOP_CHECK_SIGNAL(&(m)->top, multi_process_signal, (m))
 
-static inline void
-multi_set_pending(struct multi_context *m, struct multi_instance *mi)
-{
-    m->pending = mi;
-}
 /**
  * Assigns a peer-id to a a client and adds the instance to the
  * the instances array of the \c multi_context structure.
diff --git a/src/openvpn/multi_io.c b/src/openvpn/multi_io.c
index 24a6918..a14978b 100644
--- a/src/openvpn/multi_io.c
+++ b/src/openvpn/multi_io.c
@@ -135,36 +135,6 @@
     }
 }
 
-/*
- * Return the io flags appropriate for
- * a point-to-multipoint tunnel.
- */
-static unsigned int
-p2mp_iow_flags(const struct multi_context *m, const struct link_socket *sock)
-{
-    unsigned int flags = IOW_WAIT_SIGNAL;
-
-    if (m->pending)
-    {
-        if (TUN_OUT(&m->pending->context))
-        {
-            flags |= IOW_TO_TUN;
-        }
-
-        /* If the to be processed socket happens to be the same one on the pending
-         * UDP client instance, we set that socket ready for write */
-        if (LINK_OUT(&m->pending->context) && m->pending->context.c2.link_sockets[0] == sock)
-        {
-            flags |= IOW_TO_LINK;
-        }
-    }
-    else
-    {
-        flags |= IOW_READ;
-    }
-    return flags;
-}
-
 int
 multi_io_wait(struct multi_context *m)
 {
@@ -177,7 +147,7 @@
 
         if (proto_is_dgram(sock->info.proto))
         {
-            multi_io_process_flags(&m->top, m->multi_io->es, sock, p2mp_iow_flags(m, sock));
+            multi_io_process_flags(&m->top, m->multi_io->es, sock, IOW_READ | IOW_WAIT_SIGNAL);
         }
         else if (!tuntap_is_dco_win(m->top.c1.tuntap))
         {
@@ -281,6 +251,7 @@
  * perform server-mode postprocessing.
  *
  * @param m            - The single \c multi_context structure.
+ * @param mi           - The \c multi_instance with the packet to send.
  * @param mpp_flags    - Fast I/O optimization flags.
  *
  * @return
@@ -289,12 +260,10 @@
  *  - Falls, if the \c multi_instance was closed.
  */
 static bool
-multi_io_write_tun(struct multi_context *m, const unsigned int mpp_flags)
+multi_io_write_tun(struct multi_context *m, struct multi_instance *mi, const unsigned int mpp_flags)
 {
-    struct multi_instance *mi = m->pending;
     bool ret = true;
 
-    ASSERT(mi);
 #ifdef MULTI_DEBUG_EVENT_LOOP
     printf("%s -> TUN len=%d\n", id(mi), mi->context.c2.to_tun.len);
 #endif
@@ -310,12 +279,8 @@
  * Drop a TUN/TAP outgoing packet..
  */
 static void
-multi_io_drop_tun(struct multi_context *m, const unsigned int mpp_flags)
+multi_io_drop_tun(struct multi_context *m, struct multi_instance *mi, const unsigned int mpp_flags)
 {
-    struct multi_instance *mi = m->pending;
-
-    ASSERT(mi);
-
     set_prefix(mi);
 
     msg(D_MULTI_ERRORS, "MULTI: Outgoing TUN queue full, dropped packet len=%d",
@@ -328,24 +293,22 @@
 }
 
 /*
- * Determine which instance has pending output
- * and prepare the output for sending in
- * the to_link buffer.
+ * Determine which instance has output for the
+ * link: mi itself, or else the next queued
+ * bcast/c2c packet, prepared in its to_link buffer.
  */
 static struct multi_instance *
-multi_io_write_link_pre(struct multi_context *m)
+multi_io_write_link_pre(struct multi_context *m, struct multi_instance *mi)
 {
-    struct multi_instance *mi = NULL;
-
-    if (m->pending)
+    if (mi && LINK_OUT(&mi->context))
     {
-        mi = m->pending;
+        return mi;
     }
-    else if (mbuf_defined(m->mbuf))
+    if (mbuf_defined(m->mbuf))
     {
-        mi = multi_get_queue(m->mbuf);
+        return multi_get_queue(m->mbuf);
     }
-    return mi;
+    return NULL;
 }
 
 static bool
@@ -381,11 +344,12 @@
 }
 
 static bool
-multi_io_write_link(struct multi_context *m, bool defer, const unsigned int mpp_flags)
+multi_io_write_link(struct multi_context *m, struct multi_instance *mi, bool defer,
+                    const unsigned int mpp_flags)
 {
-    struct multi_instance *mi = multi_io_write_link_pre(m);
     bool ret = true;
 
+    mi = multi_io_write_link_pre(m, mi);
     if (mi)
     {
         if ((defer && !proto_is_dgram(mi->context.c2.link_sockets[0]->info.proto))
@@ -406,20 +370,12 @@
                 mbuf_free_buf(mb);
                 buf_reset(buf);
                 ret = multi_process_post(m, mi, mpp_flags);
-                if (!ret)
-                {
-                    mi = NULL;
-                }
                 clear_prefix();
             }
         }
         else
         {
             ret = multi_io_send_link(m, mi, mpp_flags);
-            if (!ret)
-            {
-                mi = NULL;
-            }
         }
     }
     return ret;
@@ -477,11 +433,13 @@
             break;
 
         case TA_TUN_WRITE:
-            multi_io_write_tun(m, mpp_flags);
+            ASSERT(mi);
+            multi_io_write_tun(m, mi, mpp_flags);
             break;
 
         case TA_TUN_WRITE_TIMEOUT:
-            multi_io_drop_tun(m, mpp_flags);
+            ASSERT(mi);
+            multi_io_drop_tun(m, mi, mpp_flags);
             break;
 
         case TA_SOCKET_WRITE_READY:
@@ -490,11 +448,11 @@
             break;
 
         case TA_SOCKET_WRITE:
-            multi_io_write_link(m, false, mpp_flags);
+            multi_io_write_link(m, mi, false, mpp_flags);
             break;
 
         case TA_SOCKET_WRITE_DEFERRED:
-            multi_io_write_link(m, true, mpp_flags);
+            multi_io_write_link(m, mi, true, mpp_flags);
             break;
 
         case TA_INITIAL:
@@ -629,10 +587,6 @@
                             multi_io_action(m, mi, NULL, TA_INITIAL, false);
                         }
                     }
-                    else if (e->rwflags & EVENT_WRITE)
-                    {
-                        multi_io_action(m, NULL, NULL, TA_SOCKET_WRITE, false);
-                    }
                     else if (e->rwflags & EVENT_READ)
                     {
                         multi_io_action(m, NULL, ev_arg->u.sock, TA_SOCKET_READ, false);
@@ -653,11 +607,7 @@
                 /* incoming data on TUN? */
                 if (e->arg == MULTI_IO_TUN)
                 {
-                    if (e->rwflags & EVENT_WRITE)
-                    {
-                        multi_io_action(m, NULL, NULL, TA_TUN_WRITE, false);
-                    }
-                    else if (e->rwflags & EVENT_READ)
+                    if (e->rwflags & EVENT_READ)
                     {
                         multi_io_action(m, NULL, NULL, TA_TUN_READ, false);
                     }
@@ -749,17 +699,17 @@
                 mi = NULL;
             }
             multi_close_instance_on_signal(m, touched);
+            touched = NULL;
         }
 
-
         /*
-         * If dispatch produced any pending output
-         * for a particular instance, point to
-         * that instance.
+         * touched is the only instance this action
+         * post-processed: having closed it above if
+         * it was signalled, write its output if any.
          */
-        if (m->pending)
+        if (touched && ANY_OUT(&touched->context))
         {
-            mi = m->pending;
+            mi = touched;
         }
 
         /*
