about summary refs log tree commit homepage
path: root/ioq.c
diff options
context:
space:
mode:
Diffstat (limited to 'ioq.c')
-rw-r--r--ioq.c56
1 files changed, 46 insertions, 10 deletions
diff --git a/ioq.c b/ioq.c
index e88d7f3..4f62cc5 100644
--- a/ioq.c
+++ b/ioq.c
@@ -3,13 +3,41 @@
  * License: GPLv3 or later (see COPYING for details)
  */
 #include "cmogstored.h"
+#include "trace.h"
 /*
  * This is a semaphore-like API with explicit queueing and activation,
  * so contended scheduling/wakeups happen via epoll/kqueue and there
- * is never blocking of threads (other than the mutex)
+ * is never blocking of threads (other than the mutex which only protects
+ * small memory-only operations)
  *
  * The main operations are mog_ioq_ready and mog_ioq_next
  *
+ * Flow:
+ *
+ *     mog_ioq_ready ---> true --> normal dispatch --> mog_ioq_next
+ *          |    ^                 (mog_ioq_unblock)         |
+ *          |    |                                           |
+ *          |     `-------<--------\                         |
+ *        false                    |                         |
+ *          |                      |                         V
+ *          |                      |                         |
+ *          V                      |                         |
+ *   SIMPLEQ_INSERT_TAIL(push)     ^                         |
+ *          ||                     |                         V
+ *          VV                     |                         /
+ *           \\                    |                        /
+ *            \\                   |                       /
+ *             \\                  |                      V
+ *              `===(wait for)==========>===> SIMPLEQ_{FIRST,REMOVE_HEAD}(pop)
+ *                                 |                   |
+ *                                 |                   V
+ *                                 |                   |
+ *                                 ^       add to kqueue/epoll ready list
+ *                                 |                   |
+ *                                 |                   V
+ *                                 |                   /
+ *                                 `---------<---------'
+ *
  * mog_ioq_next is automatically called when releases a regular file.
  */
 __thread struct mog_ioq *mog_ioq_current;
@@ -53,9 +81,9 @@ static inline void ioq_set_contended(struct mog_ioq *ioq)
  * Adding the mfd to an epoll/kqueue watch list in the same thread/context
  * where this function returns true is a guaranteed bug.
  *
- * client_mfd is the client socket, not the open (regular) file
+ * mfd is the client socket, not the open (regular) file
  */
-bool mog_ioq_ready(struct mog_ioq *ioq, struct mog_fd *client_mfd)
+bool mog_ioq_ready(struct mog_ioq *ioq, struct mog_fd *mfd)
 {
         bool good;
 
@@ -73,8 +101,8 @@ bool mog_ioq_ready(struct mog_ioq *ioq, struct mog_fd *client_mfd)
 
                 mog_ioq_current = ioq;
         } else {
-                client_mfd->ioq_blocked = 1;
-                SIMPLEQ_INSERT_TAIL(&ioq->ioq_head, client_mfd, ioqent);
+                mfd->ioq_blocked = 1;
+                SIMPLEQ_INSERT_TAIL(&ioq->ioq_head, mfd, ioqent);
                 ioq_set_contended(ioq);
         }
 
@@ -89,7 +117,7 @@ bool mog_ioq_ready(struct mog_ioq *ioq, struct mog_fd *client_mfd)
  */
 void mog_ioq_next(struct mog_ioq *check_ioq)
 {
-        struct mog_fd *client_mfd = NULL;
+        struct mog_fd *mfd = NULL;
 
         if (mog_ioq_current == NULL)
                 return;
@@ -102,8 +130,8 @@ void mog_ioq_next(struct mog_ioq *check_ioq)
         mog_ioq_current->cur++;
         if (mog_ioq_current->cur <= mog_ioq_current->max) {
                 /* wake up any waiters */
-                client_mfd = SIMPLEQ_FIRST(&mog_ioq_current->ioq_head);
-                if (client_mfd) {
+                mfd = SIMPLEQ_FIRST(&mog_ioq_current->ioq_head);
+                if (mfd) {
                         SIMPLEQ_REMOVE_HEAD(&mog_ioq_current->ioq_head, ioqent);
 
                         /* if there's another head, we're still contended */
@@ -118,8 +146,10 @@ void mog_ioq_next(struct mog_ioq *check_ioq)
         CHECK(int, 0, pthread_mutex_unlock(&mog_ioq_current->mtx));
 
         /* wake up the next sleeper on this queue */
-        if (client_mfd)
-                mog_activeq_push(mog_ioq_current->svc->queue, client_mfd);
+        if (mfd) {
+                TRACE(CMOGSTORED_IOQ_RESCHEDULE(mfd->fd));
+                mog_activeq_push(mog_ioq_current->svc->queue, mfd);
+        }
         /*
          * We may not touch or use client_mfd here anymore.  Another
          * thread may already have it.  In the worst case, it's been
@@ -173,6 +203,12 @@ void mog_ioq_destroy(struct mog_ioq *ioq)
         CHECK(int, 0, pthread_mutex_destroy(&ioq->mtx));
 }
 
+/*
+ * If this returns true, the caller must continue processing a request
+ * without checking other state associated with the mfd.
+ * If this returns false (the common case), the caller continues as
+ * usual.
+ */
 bool mog_ioq_unblock(struct mog_fd *mfd)
 {
         if (mfd->ioq_blocked == 0)