Merge "Upgrade bionic to tzdata2014g."
diff --git a/linker/linked_list.h b/linker/linked_list.h
index 14fe1e5..5fbdc8f 100644
--- a/linker/linked_list.h
+++ b/linker/linked_list.h
@@ -86,10 +86,21 @@
   }
 
   template<typename F>
-  void for_each(F&& action) {
+  void for_each(F action) {
+    visit([&] (T* si) {
+      action(si);
+      return true;
+    });
+  }
+
+  template<typename F>
+  bool visit(F action) {
     for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) {
-      action(e->element);
+      if (!action(e->element)) {
+        return false;
+      }
     }
+    return true;
   }
 
   template<typename F>
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 919f8c0..16730d6 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -627,10 +627,42 @@
     return nullptr;
 }
 
+// Each size has it's own allocator.
+template<size_t size>
+class SizeBasedAllocator {
+ public:
+  static void* alloc() {
+    return allocator_.alloc();
+  }
 
+  static void free(void* ptr) {
+    allocator_.free(ptr);
+  }
 
-// Another soinfo list allocator to use in dlsym. We don't reuse
-// SoinfoListAllocator because it is write-protected most of the time.
+ private:
+  static LinkerBlockAllocator allocator_;
+};
+
+template<size_t size>
+LinkerBlockAllocator SizeBasedAllocator<size>::allocator_(size);
+
+template<typename T>
+class TypeBasedAllocator {
+ public:
+  static T* alloc() {
+    return reinterpret_cast<T*>(SizeBasedAllocator<sizeof(T)>::alloc());
+  }
+
+  static void free(T* ptr) {
+    SizeBasedAllocator<sizeof(T)>::free(ptr);
+  }
+};
+
+template <typename T>
+using linked_list_t = LinkedList<T, TypeBasedAllocator<LinkedListEntry<T>>>;
+
+typedef linked_list_t<soinfo> SoinfoLinkedList;
+
 static LinkerAllocator<LinkedListEntry<soinfo>> g_soinfo_list_allocator_rw;
 class SoinfoListAllocatorRW {
  public:
@@ -646,8 +678,9 @@
 // This is used by dlsym(3).  It performs symbol lookup only within the
 // specified soinfo object and its dependencies in breadth first order.
 ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) {
-  LinkedList<soinfo, SoinfoListAllocatorRW> visit_list;
-  LinkedList<soinfo, SoinfoListAllocatorRW> visited;
+  SoinfoLinkedList visit_list;
+  SoinfoLinkedList visited;
+
   visit_list.push_back(si);
   soinfo* current_soinfo;
   while ((current_soinfo = visit_list.pop_front()) != nullptr) {
diff --git a/linker/tests/linked_list_test.cpp b/linker/tests/linked_list_test.cpp
index 0483b84..a555edb 100644
--- a/linker/tests/linked_list_test.cpp
+++ b/linker/tests/linked_list_test.cpp
@@ -151,15 +151,15 @@
   memset(buf, 0, sizeof(buf));
   ASSERT_EQ(4U, list.size());
   ASSERT_EQ(2U, list.copy_to_array(buf, 2));
-  ASSERT_EQ('a', *buf[0]);
-  ASSERT_EQ('b', *buf[1]);
+  ASSERT_STREQ("a", buf[0]);
+  ASSERT_STREQ("b", buf[1]);
   ASSERT_EQ(nullptr, buf[2]);
 
   ASSERT_EQ(4U, list.copy_to_array(buf, max_size));
-  ASSERT_EQ('a', *buf[0]);
-  ASSERT_EQ('b', *buf[1]);
-  ASSERT_EQ('c', *buf[2]);
-  ASSERT_EQ('d', *buf[3]);
+  ASSERT_STREQ("a", buf[0]);
+  ASSERT_STREQ("b", buf[1]);
+  ASSERT_STREQ("c", buf[2]);
+  ASSERT_STREQ("d", buf[3]);
   ASSERT_EQ(nullptr, buf[4]);
 
   memset(buf, 0, sizeof(buf));
@@ -168,7 +168,7 @@
   });
   ASSERT_EQ(1U, list.size());
   ASSERT_EQ(1U, list.copy_to_array(buf, max_size));
-  ASSERT_EQ('c', *buf[0]);
+  ASSERT_STREQ("c", buf[0]);
   ASSERT_EQ(nullptr, buf[1]);
 
   memset(buf, 0, sizeof(buf));
@@ -182,3 +182,39 @@
   ASSERT_EQ(nullptr, buf[0]);
 }
 
+TEST(linked_list, test_visit) {
+  test_list_t list;
+  list.push_back("a");
+  list.push_back("b");
+  list.push_back("c");
+  list.push_back("d");
+
+  int visits = 0;
+  std::stringstream ss;
+  bool result = list.visit([&](const char* c) {
+    ++visits;
+    ss << c;
+    return true;
+  });
+
+  ASSERT_TRUE(result);
+  ASSERT_EQ(4, visits);
+  ASSERT_EQ("abcd", ss.str());
+
+  visits = 0;
+  ss.str(std::string());
+
+  result = list.visit([&](const char* c) {
+    if (++visits == 3) {
+      return false;
+    }
+
+    ss << c;
+    return true;
+  });
+
+  ASSERT_TRUE(!result);
+  ASSERT_EQ(3, visits);
+  ASSERT_EQ("ab", ss.str());
+}
+