This is an automated email from the ASF dual-hosted git repository.

oknet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 8ae5611  Optimize: Do not signal EThreads which are not blocked on 
cond_timedwait.
8ae5611 is described below

commit 8ae5611ae1c555198a4ddeda68055ac4ff20afd5
Author: Oknet Xu <xuc...@skyguard.com.cn>
AuthorDate: Wed Dec 19 20:40:24 2018 +0800

    Optimize: Do not signal EThreads which are not blocked on cond_timedwait.
    
    From the man page of `pthread_cond_timedwait()`:
    
    ```
    The pthread_cond_timedwait() function atomically blocks the current
    thread waiting on the condition variable specified by cond, and releases
    the mutex specified by mutex.  The waiting thread unblocks only after
    another thread calls pthread_cond_signal(3), or
    pthread_cond_broadcast(3) with the same condition variable, or if the
    system time reaches the time specified in abstime, and the current
    thread reacquires the lock on mutex.
    ```
    
    Refer to the code of `ProtectedQueue::wait()`,
    
    ```
        ink_mutex_acquire(&lock);
        if (INK_ATOMICLIST_EMPTY(al)) {
          timespec ts = ink_hrtime_to_timespec(timeout);
          ink_cond_timedwait(&might_have_data, &lock, &ts);
        }
        ink_mutex_release(&lock);
    ```
    
    The `EThread::lock` is acquired and then released immediatelly by
    `ink_cond_timedwait()`.
    When the thread unblocks, the thread reacquires the lock on
    `EThread::lock`, and then released immediatelly.
    
    Refer to the code of `ProtectedQueue::signal()`,
    
    ```
    TS_INLINE void
    ProtectedQueue::signal()
    {
      // Need to get the lock before you can signal the thread
      ink_mutex_acquire(&lock);
      ink_cond_signal(&might_have_data);
      ink_mutex_release(&lock);
    }
    ```
    
    The threads that try to send signal to the same target Event Thread are
    blocked on the mutex and send meaningless wakeup signals one by one.
    
    It is not necessory,
    
    - To acquire and release the `EThread::lock` again and again in the
    event loop,
    - To send wakeup signal to an Event Thread that does not blocked on
    `pthread_cond_timedwait()`.
    
    Changes of the commit:
    
    The Event Thread has two status: busy and sleep,
    
    - Keep `EThread::lock` locked while Event Thread is busy,
    - The `EThread::lock` is released while Event Thread is sleep.
    
    When other threads try to acquire the `EThread::lock` of the target
    Event Thread,
    
    - Acquired, indicating that the target Event Thread is sleep, must send
    a wakeup signal to the Event Thread.
    - Failed, indicating that the target Event Thread is busy, do nothing.
    
    Backports:
    
    If you backport the commit to the branch without PR#2541,
    
    - It is safe to remove `flush_signals()` from the event loop.
    - Also safe to remove any code related with `ethreads_to_be_signalled[]`
    and `n_ethreads_to_be_signalled`.
    - Always do `try_signal()` within `ProtectedQueue::enqueue()`.
    - Suggest to remove `ProtectedQueue::signal()`.
---
 iocore/eventsystem/I_EThread.h       |  7 ++++++-
 iocore/eventsystem/ProtectedQueue.cc | 17 ++++++++---------
 iocore/eventsystem/UnixEThread.cc    |  9 +++++++++
 3 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/iocore/eventsystem/I_EThread.h b/iocore/eventsystem/I_EThread.h
index 7f62545..8ce926a 100644
--- a/iocore/eventsystem/I_EThread.h
+++ b/iocore/eventsystem/I_EThread.h
@@ -371,7 +371,12 @@ public:
     void
     signalActivity() override
     {
-      _q.signal();
+      /* Try to acquire the `EThread::lock` of the Event Thread:
+       *   - Acquired, indicating that the Event Thread is sleep,
+       *               must send a wakeup signal to the Event Thread.
+       *   - Failed, indicating that the Event Thread is busy, do nothing.
+       */
+      (void)_q.try_signal();
     }
 
     ProtectedQueue &_q;
diff --git a/iocore/eventsystem/ProtectedQueue.cc 
b/iocore/eventsystem/ProtectedQueue.cc
index c4b5377..bd434e7 100644
--- a/iocore/eventsystem/ProtectedQueue.cc
+++ b/iocore/eventsystem/ProtectedQueue.cc
@@ -114,15 +114,14 @@ ProtectedQueue::dequeue_external()
 void
 ProtectedQueue::wait(ink_hrtime timeout)
 {
-  // If there are no external events available, don't do a cond_timedwait.
+  /* If there are no external events available, will do a cond_timedwait.
+   *
+   *   - The `EThread::lock` will be released,
+   *   - And then the Event Thread goes to sleep and waits for the wakeup 
signal of `EThread::might_have_data`,
+   *   - The `EThread::lock` will be locked again when the Event Thread wakes 
up.
+   */
   if (INK_ATOMICLIST_EMPTY(al)) {
-    ink_mutex_acquire(&lock);
-    // The "al" may have new events while waiting for the mutex become 
available.
-    // We have to recheck the external queue again.
-    if (INK_ATOMICLIST_EMPTY(al)) {
-      timespec ts = ink_hrtime_to_timespec(timeout);
-      ink_cond_timedwait(&might_have_data, &lock, &ts);
-    }
-    ink_mutex_release(&lock);
+    timespec ts = ink_hrtime_to_timespec(timeout);
+    ink_cond_timedwait(&might_have_data, &lock, &ts);
   }
 }
diff --git a/iocore/eventsystem/UnixEThread.cc 
b/iocore/eventsystem/UnixEThread.cc
index a5c72c5..06920db 100644
--- a/iocore/eventsystem/UnixEThread.cc
+++ b/iocore/eventsystem/UnixEThread.cc
@@ -323,7 +323,16 @@ EThread::execute()
 
   switch (tt) {
   case REGULAR: {
+    /* The Event Thread has two status: busy and sleep:
+     *   - Keep `EThread::lock` locked while Event Thread is busy,
+     *   - The `EThread::lock` is released while Event Thread is sleep.
+     * When other threads try to acquire the `EThread::lock` of the target 
Event Thread:
+     *   - Acquired, indicating that the target Event Thread is sleep,
+     *   - Failed, indicating that the target Event Thread is busy.
+     */
+    ink_mutex_acquire(&EventQueueExternal.lock);
     this->execute_regular();
+    ink_mutex_release(&EventQueueExternal.lock);
     break;
   }
   case DEDICATED: {

Reply via email to