Coverage for /Syzygy/agent/common/thread_state.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%86860.C++source

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  //
  15    :  // Defines the members of the ThreadStateBase and ThreadStateManager classes
  16    :  
  17    :  #include "syzygy/agent/common/thread_state.h"
  18    :  
  19    :  namespace agent {
  20    :  namespace common {
  21    :  
  22    :  ThreadStateBase::ThreadStateBase()
  23    :      : thread_handle_(
  24  E :          ::OpenThread(SYNCHRONIZE, FALSE, ::GetCurrentThreadId())) {
  25  E :    DCHECK(thread_handle_.IsValid());
  26  E :    InitializeListHead(&entry_);
  27  E :  }
  28    :  
  29  E :  ThreadStateBase::~ThreadStateBase() {
  30  E :    DCHECK(IsListEmpty(&entry_));
  31  E :  }
  32    :  
  33  E :  ThreadStateManager::ThreadStateManager() {
  34  E :    InitializeListHead(&active_items_);
  35  E :    InitializeListHead(&death_row_items_);
  36  E :  }
  37    :  
  38  E :  ThreadStateManager::~ThreadStateManager() {
  39    :    // Destroy all active and death row thread states here. Note that this is
  40    :    // racy as hell if other threads are active, but it's the caller's
  41    :    // responsibility to ensure that's not the case.
  42    :  
  43    :    // Attempt an orderly deletion of items of the death row.
  44  E :    Scavenge();
  45    :  
  46    :    // Note that we don't hold lock_ for these operations, as the destructor
  47    :    // has to be the only member of the party at this point.
  48  E :    if (!IsListEmpty(&death_row_items_)) {
  49    :      // This will happen if the items have been marked for death, but their
  50    :      // threads are still active.
  51  E :      LOG(WARNING) << "Active death row items at manager destruction.";
  52    :  
  53  E :      DeleteItems(&death_row_items_);
  54    :    }
  55    :  
  56  E :    if (!IsListEmpty(&active_items_)) {
  57    :      // This can and will happen if other threads in the process have been
  58    :      // terminated, as that'll orphan their thread states.
  59  E :      LOG(WARNING) << "Active thread states at manager destruction.";
  60    :  
  61  E :      DeleteItems(&active_items_);
  62    :    }
  63    :  
  64    :    // If either of these asserts fire, then there are active threads in the
  65    :    // process that are still interacting with the manager. This is obviously
  66    :    // very bad, as the manager is about to wink out of existence.
  67  E :    DCHECK(IsListEmpty(&active_items_));
  68  E :    DCHECK(IsListEmpty(&death_row_items_));
  69  E :  }
  70    :  
  71  E :  void ThreadStateManager::Register(ThreadStateBase* item) {
  72  E :    DCHECK(item != NULL);
  73  E :    DCHECK(IsListEmpty(&item->entry_));
  74  E :    base::AutoLock auto_lock(lock_);
  75  E :    InsertTailList(&active_items_, &item->entry_);
  76  E :  }
  77    :  
  78  E :  void ThreadStateManager::Unregister(ThreadStateBase* item) {
  79  E :    DCHECK(item != NULL);
  80  E :    base::AutoLock auto_lock(lock_);
  81  E :    RemoveEntryList(&item->entry_);
  82  E :    InitializeListHead(&item->entry_);
  83  E :  }
  84    :  
  85  E :  void ThreadStateManager::MarkForDeath(ThreadStateBase* item) {
  86  E :    DCHECK(item != NULL);
  87    :  
  88    :    {
  89  E :      base::AutoLock auto_lock(lock_);
  90    :  
  91    :      // Make sure the item we're marking is on the active or death row lists.
  92    :      DCHECK(IsNodeOnList(&active_items_, &item->entry_) ||
  93  E :             IsNodeOnList(&death_row_items_, &item->entry_));
  94    :  
  95    :      // Pull it out of the list it's on, this'll preserve it over the scavenge
  96    :      // below, in the unlikely case that the item is being marked from another
  97    :      // thread than it's own.
  98  E :      RemoveEntryList(&item->entry_);
  99  E :    }
 100    :  
 101    :    // Use this opportunity to scavenge existing thread states on death row.
 102  E :    Scavenge();
 103    :  
 104    :    // Mark item for death, for later scavenging.
 105    :    {
 106  E :      base::AutoLock auto_lock(lock_);
 107    :  
 108  E :      InsertHeadList(&death_row_items_, &item->entry_);
 109  E :    }
 110  E :  }
 111    :  
 112  E :  bool ThreadStateManager::Scavenge() {
 113    :    // We'll store the list of scavenged items here.
 114    :    LIST_ENTRY dead_items;
 115  E :    InitializeListHead(&dead_items);
 116  E :    bool has_more_items = false;
 117    :  
 118    :    // Acquire the lock when interacting with the internal data.
 119    :    {
 120  E :      base::AutoLock auto_lock(lock_);
 121    :  
 122    :      // Put all of the death row items belonging
 123    :      // to dead threads into dead_items.
 124  E :      GatherDeadItemsUnlocked(&dead_items);
 125    :  
 126    :      // Return whether or not the thread state manager is no longer holding
 127    :      // any items.
 128    :      has_more_items =
 129  E :          !IsListEmpty(&active_items_) || !IsListEmpty(&death_row_items_);
 130  E :    }
 131    :  
 132    :    // We can delete any dead items we found outside of the lock.
 133  E :    DeleteItems(&dead_items);
 134  E :    DCHECK(IsListEmpty(&dead_items));
 135    :  
 136  E :    return has_more_items;
 137  E :  }
 138    :  
 139  E :  void ThreadStateManager::GatherDeadItemsUnlocked(LIST_ENTRY* dead_items) {
 140  E :    DCHECK(dead_items != NULL);
 141  E :    DCHECK(IsListEmpty(dead_items));
 142  E :    lock_.AssertAcquired();
 143    :  
 144    :    // Return if the death row items list is empty.
 145  E :    if (IsListEmpty(&death_row_items_))
 146  E :      return;
 147    :  
 148    :    // Walk the death row items list, looking for items owned by dead threads.
 149    :    ThreadStateBase* item =
 150  E :        CONTAINING_RECORD(death_row_items_.Flink, ThreadStateBase, entry_);
 151  E :    while (item != NULL) {
 152  E :      ThreadStateBase* next_item = NULL;
 153  E :      if (item->entry_.Flink != &death_row_items_) {
 154    :        next_item =
 155  E :            CONTAINING_RECORD(item->entry_.Flink, ThreadStateBase, entry_);
 156    :      }
 157    :  
 158    :      // Move the item to the dead_items list if the associated thread is dead.
 159  E :      if (IsThreadDead(item)) {
 160  E :        RemoveEntryList(&item->entry_);
 161  E :        InsertTailList(dead_items, &item->entry_);
 162    :      }
 163    :  
 164  E :      item = next_item;
 165  E :    }
 166  E :  }
 167    :  
 168  E :  bool ThreadStateManager::IsThreadDead(ThreadStateBase* item) {
 169  E :    DCHECK(item != NULL);
 170  E :    return ::WaitForSingleObject(item->thread_handle_.Get(), 0) == WAIT_OBJECT_0;
 171  E :  }
 172    :  
 173  E :  void ThreadStateManager::DeleteItems(LIST_ENTRY* items) {
 174  E :    DCHECK(items != NULL);
 175    :    // Let's delete all entries in items.
 176  E :    while (!IsListEmpty(items)) {
 177    :      ThreadStateBase* item =
 178  E :          CONTAINING_RECORD(items->Flink, ThreadStateBase, entry_);
 179  E :      RemoveHeadList(items);
 180  E :      InitializeListHead(&item->entry_);
 181  E :      delete item;
 182  E :    }
 183  E :  }
 184    :  
 185    :  }  // namespace common
 186    :  }  // namespace agent

Coverage information generated Thu Jan 14 17:40:38 2016.