Revert "[graphite] Add multiple work lists to SkExecutor"

This reverts commit 3b83fd3eba3f29d2b0e8b27067f43ba781642a22.

Reason for revert: ASAN complaint

Original change's description:
> [graphite] Add multiple work lists to SkExecutor
>
> Bug: b/434712686
> Change-Id: I5266e19b8da90ea18ee31ea80550875d97498f01
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1050616
> Reviewed-by: Michael Ludwig <michaelludwig@google.com>
> Reviewed-by: Thomas Smith <thomsmit@google.com>
> Commit-Queue: Robert Phillips <robertphillips@google.com>

Bug: b/434712686
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Change-Id: I8741a527445ea0f4186d74e4747e0c460108d0f7
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1056436
Auto-Submit: Robert Phillips <robertphillips@google.com>
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index b25ec09..4872c58 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -503,7 +503,7 @@
     (r'std::mutex', 'SkMutex'),
     (r'std::shared_mutex', 'SkSharedMutex'),
     (r'std::stop_token', ''),
-    (r'std::thread', '', ['^tests/', 'SkExecutor']),
+    (r'std::thread', '', ['^tests/']),
 
     # We used to have separate symbols for this, but coalesced them to make the
     # Bazel build easier.
diff --git a/gn/tests.gni b/gn/tests.gni
index a01097b..819e5dd 100644
--- a/gn/tests.gni
+++ b/gn/tests.gni
@@ -74,7 +74,6 @@
   "$_tests/EmptyPathTest.cpp",
   "$_tests/EncodeTest.cpp",
   "$_tests/EncodedInfoTest.cpp",
-  "$_tests/ExecutorTest.cpp",
   "$_tests/ExifTest.cpp",
   "$_tests/ExtendedSkColorTypeTests.cpp",
   "$_tests/F16DrawTest.cpp",
diff --git a/include/core/SkExecutor.h b/include/core/SkExecutor.h
index eb62c15..88e2ca6 100644
--- a/include/core/SkExecutor.h
+++ b/include/core/SkExecutor.h
@@ -22,27 +22,12 @@
     static std::unique_ptr<SkExecutor> MakeLIFOThreadPool(int threads = 0,
                                                           bool allowBorrowing = true);
 
-    // A work list is the queue or stack to which work is added and removed. The above two
-    // factory functions create an executor with only one list while the following two factories
-    // can create executors with multiple work lists. Having multiple work lists allows for
-    // prioritization with work being pulled from the lower indexed work lists first - with
-    // work list '0' being the highest priority.
-    static std::unique_ptr<SkExecutor> MakeMultiListFIFOThreadPool(int numWorkLists,
-                                                                   int threads = 0,
-                                                                   bool allowBorrowing = true);
-    static std::unique_ptr<SkExecutor> MakeMultiListLIFOThreadPool(int numWorkLists,
-                                                                   int threads = 0,
-                                                                   bool allowBorrowing = true);
-
     // There is always a default SkExecutor available by calling SkExecutor::GetDefault().
     static SkExecutor& GetDefault();
     static void SetDefault(SkExecutor*);  // Does not take ownership.  Not thread safe.
 
     // Add work to execute.
-    virtual void add(std::function<void(void)>);
-    virtual void add(std::function<void(void)>, int workList) = 0;
-
-    virtual void discardAllPendingWork() = 0;
+    virtual void add(std::function<void(void)>) = 0;
 
     // If it makes sense for this executor, use this thread to execute work for a little while.
     virtual void borrow() {}
diff --git a/src/core/SkExecutor.cpp b/src/core/SkExecutor.cpp
index 484aaa5..4c97f7f 100644
--- a/src/core/SkExecutor.cpp
+++ b/src/core/SkExecutor.cpp
@@ -9,7 +9,6 @@
 #include "include/private/base/SkMutex.h"
 #include "include/private/base/SkSemaphore.h"
 #include "include/private/base/SkTArray.h"
-#include "include/private/base/SkTPin.h"
 #include "src/base/SkNoDestructor.h"
 
 #include <deque>
@@ -34,16 +33,11 @@
 
 SkExecutor::~SkExecutor() {}
 
-void SkExecutor::add(std::function<void(void)> work) {
-    this->add(std::move(work), /* workList= */ 0);
-}
-
 // The default default SkExecutor is an SkTrivialExecutor, which just runs the work right away.
 class SkTrivialExecutor final : public SkExecutor {
-    void add(std::function<void(void)> work, int /* workList */) override {
+    void add(std::function<void(void)> work) override {
         work();
     }
-    void discardAllPendingWork() override {}
 };
 
 static SkExecutor& trivial_executor() {
@@ -80,12 +74,7 @@
 template <typename WorkList>
 class SkThreadPool final : public SkExecutor {
 public:
-    explicit SkThreadPool(int numWorkLists, int threads, bool allowBorrowing)
-            : fNumWorkLists(numWorkLists < 1 ? 1 : numWorkLists)
-            , fAllowBorrowing(allowBorrowing) {
-
-        fWorkLists = std::make_unique<WorkList[]>(fNumWorkLists);
-
+    explicit SkThreadPool(int threads, bool allowBorrowing) : fAllowBorrowing(allowBorrowing) {
         for (int i = 0; i < threads; i++) {
             fThreads.emplace_back(&Loop, this);
         }
@@ -94,8 +83,7 @@
     ~SkThreadPool() override {
         // Signal each thread that it's time to shut down.
         for (int i = 0; i < fThreads.size(); i++) {
-            // Add the notification to the highest priority list
-            this->add(nullptr, /* workList= */ 0);
+            this->add(nullptr);
         }
         // Wait for each thread to shut down.
         for (int i = 0; i < fThreads.size(); i++) {
@@ -103,27 +91,16 @@
         }
     }
 
-    void add(std::function<void(void)> work, int workList) override {
-        workList = SkTPin(workList, 0, fNumWorkLists-1);
-
+    void add(std::function<void(void)> work) override {
         // Add some work to our pile of work to do.
         {
             SkAutoMutexExclusive lock(fWorkLock);
-
-            fWorkLists[workList].emplace_back(std::move(work));
+            fWork.emplace_back(std::move(work));
         }
         // Tell the Loop() threads to pick it up.
         fWorkAvailable.signal(1);
     }
 
-    void discardAllPendingWork() override {
-        SkAutoMutexExclusive lock(fWorkLock);
-
-        for (int i = 0; i < fNumWorkLists; ++i) {
-            fWorkLists[i].clear();
-        }
-    }
-
     void borrow() override {
         // If there is work waiting and we're allowed to borrow work, do it.
         if (fAllowBorrowing && fWorkAvailable.try_wait()) {
@@ -132,26 +109,13 @@
     }
 
 private:
-    // This method should usually be called only when fWorkAvailable indicates there's work to do.
+    // This method should be called only when fWorkAvailable indicates there's work to do.
     bool do_work() {
         std::function<void(void)> work;
-        bool workAvailable = false;
         {
             SkAutoMutexExclusive lock(fWorkLock);
-
-            for (int i = 0; i < fNumWorkLists; ++i) {
-                if (!fWorkLists[i].empty()) {
-                    workAvailable = true;
-                    work = pop(&fWorkLists[i]);
-                    break;
-                }
-            }
-        }
-
-        if (!workAvailable) {
-            // Because we can discard work asynchronous to Loop() we can sometimes get in this
-            // method with no work to do
-            return true;
+            SkASSERT(!fWork.empty());        // TODO: if (fWork.empty()) { return true; } ?
+            work = pop(&fWork);
         }
 
         if (!work) {
@@ -172,40 +136,20 @@
     // Both SkMutex and SkSpinlock can work here.
     using Lock = SkMutex;
 
-    TArray<std::thread>         fThreads;
-    const int                   fNumWorkLists; // guaranteed >= 1
-    std::unique_ptr<WorkList[]> fWorkLists SK_GUARDED_BY(fWorkLock);
-    Lock                        fWorkLock;
-    SkSemaphore                 fWorkAvailable;
-    const bool                  fAllowBorrowing;
+    TArray<std::thread> fThreads;
+    WorkList              fWork;
+    Lock                  fWorkLock;
+    SkSemaphore           fWorkAvailable;
+    bool                  fAllowBorrowing;
 };
 
 std::unique_ptr<SkExecutor> SkExecutor::MakeFIFOThreadPool(int threads, bool allowBorrowing) {
     using WorkList = std::deque<std::function<void(void)>>;
-    return std::make_unique<SkThreadPool<WorkList>>(/* numWorkLists= */ 1,
-                                                    threads > 0 ? threads : num_cores(),
+    return std::make_unique<SkThreadPool<WorkList>>(threads > 0 ? threads : num_cores(),
                                                     allowBorrowing);
 }
 std::unique_ptr<SkExecutor> SkExecutor::MakeLIFOThreadPool(int threads, bool allowBorrowing) {
     using WorkList = TArray<std::function<void(void)>>;
-    return std::make_unique<SkThreadPool<WorkList>>(/* numWorkLists= */ 1,
-                                                    threads > 0 ? threads : num_cores(),
-                                                    allowBorrowing);
-}
-
-std::unique_ptr<SkExecutor> SkExecutor::MakeMultiListFIFOThreadPool(int numWorkLists,
-                                                                    int threads,
-                                                                    bool allowBorrowing) {
-    using WorkList = std::deque<std::function<void(void)>>;
-    return std::make_unique<SkThreadPool<WorkList>>(numWorkLists,
-                                                    threads > 0 ? threads : num_cores(),
-                                                    allowBorrowing);
-}
-std::unique_ptr<SkExecutor> SkExecutor::MakeMultiListLIFOThreadPool(int numWorkLists,
-                                                                    int threads,
-                                                                    bool allowBorrowing) {
-    using WorkList = TArray<std::function<void(void)>>;
-    return std::make_unique<SkThreadPool<WorkList>>(numWorkLists,
-                                                    threads > 0 ? threads : num_cores(),
+    return std::make_unique<SkThreadPool<WorkList>>(threads > 0 ? threads : num_cores(),
                                                     allowBorrowing);
 }
diff --git a/src/core/SkTaskGroup.cpp b/src/core/SkTaskGroup.cpp
index 3303c3a..cd5c50f 100644
--- a/src/core/SkTaskGroup.cpp
+++ b/src/core/SkTaskGroup.cpp
@@ -14,20 +14,11 @@
 SkTaskGroup::SkTaskGroup(SkExecutor& executor) : fPending(0), fExecutor(executor) {}
 
 void SkTaskGroup::add(std::function<void(void)> fn) {
-    this->add(std::move(fn), /* workList= */ 0);
-}
-
-void SkTaskGroup::add(std::function<void(void)> fn, int workList) {
     fPending.fetch_add(+1, std::memory_order_relaxed);
     fExecutor.add([this, fn{std::move(fn)}] {
-                      fn();
-                      fPending.fetch_add(-1, std::memory_order_release);
-                  },
-                  workList);
-}
-
-void SkTaskGroup::discardAllPendingWork() {
-    fExecutor.discardAllPendingWork();
+        fn();
+        fPending.fetch_add(-1, std::memory_order_release);
+    });
 }
 
 void SkTaskGroup::batch(int N, std::function<void(int)> fn) {
diff --git a/src/core/SkTaskGroup.h b/src/core/SkTaskGroup.h
index 5f1b910..7e9d2ba 100644
--- a/src/core/SkTaskGroup.h
+++ b/src/core/SkTaskGroup.h
@@ -25,9 +25,6 @@
 
     // Add a task to this SkTaskGroup.
     void add(std::function<void(void)> fn);
-    void add(std::function<void(void)> fn, int workList);
-
-    void discardAllPendingWork();
 
     // Add a batch of N tasks, all calling fn with different arguments.
     void batch(int N, std::function<void(int)> fn);
diff --git a/tests/ExecutorTest.cpp b/tests/ExecutorTest.cpp
deleted file mode 100644
index 8ffe433..0000000
--- a/tests/ExecutorTest.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright 2025 Google LLC
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "include/core/SkExecutor.h"
-#include "src/base/SkSpinlock.h"
-#include "src/core/SkTaskGroup.h"
-#include "tests/Test.h"
-
-#include <thread>
-
-namespace {
-
-constexpr int kNumWorkLists = 2;
-constexpr int kNumThreads = 4;
-constexpr int kHighPriority = 0;
-constexpr int kLowPriority = 1;
-
-// This utility just collects a set kMaxCount ints in a thread-safe manner. It has a
-// predicate to check if the results match expectations.
-class Collector {
-public:
-    static constexpr int kMaxCount = 200;
-
-    void insert(int i) SK_EXCLUDES(fSpinLock) {
-        SkAutoSpinlock lock{fSpinLock};
-
-        if (fCount >= kMaxCount) {
-            return;
-        }
-
-        fData[fCount++] = i;
-    }
-
-    int count() const SK_EXCLUDES(fSpinLock) {
-        SkAutoSpinlock lock{fSpinLock};
-        return fCount;
-    }
-
-#if defined(SK_DEBUG)
-    void dump() const SK_EXCLUDES(fSpinLock) {
-        SkAutoSpinlock lock{fSpinLock};
-
-        for (int i = 0; i < fCount; ++i) {
-            SkDebugf("%d ", fData[i]);
-        }
-        SkDebugf("\n");
-    }
-#endif
-
-    // For this following tests we expect that all the high priority work is completed
-    // before the low priority work. The length of the two task types is set up so,
-    // even if low priority work is picked up while the high priority tasks are finishing,
-    // all the high priority task should still finish before the low priority ones.
-    bool dataIsInOrder() const SK_EXCLUDES(fSpinLock) {
-        SkAutoSpinlock lock{fSpinLock};
-
-        for (int i = 0; i < fCount; ++i) {
-            if (i < 100) {
-                if (fData[i] >= 100) { return false; }
-            } else {
-                if (fData[i] < 100) { return false; }
-            }
-        }
-        return true;
-    }
-
-private:
-    mutable SkSpinlock fSpinLock;
-
-    int fCount SK_GUARDED_BY(fSpinLock) = 0;
-    int fData[kMaxCount] SK_GUARDED_BY(fSpinLock);
-};
-
-// Make sure all high priority work is started before the low priority work is begun
-void priority_test(skiatest::Reporter* reporter, std::unique_ptr<SkExecutor> executor) {
-    SkTaskGroup taskGroup(*executor);
-    Collector collector;
-
-    for (int i = 0; i < 100; ++i) {
-        taskGroup.add([&collector, i]() {
-            collector.insert(i);
-            std::this_thread::sleep_for(std::chrono::microseconds(50));
-        }, kHighPriority);
-    }
-    for (int i = 100; i < 200; ++i) {
-        taskGroup.add([&collector, i]() {
-            std::this_thread::sleep_for(std::chrono::milliseconds(1));
-            collector.insert(i);
-        }, kLowPriority);
-    }
-
-    taskGroup.wait();
-
-    REPORTER_ASSERT(reporter, collector.count() == Collector::kMaxCount);
-    REPORTER_ASSERT(reporter, collector.dataIsInOrder());
-}
-
-// Test out discarding
-void discard_test(skiatest::Reporter* reporter, std::unique_ptr<SkExecutor> executor) {
-    SkTaskGroup taskGroup(*executor);
-    Collector collector;
-
-    for (int i = 0; i < 100; ++i) {
-        executor->add([&collector, i]() {
-            collector.insert(i);
-            std::this_thread::sleep_for(std::chrono::microseconds(50));
-        }, kHighPriority);
-    }
-    for (int i = 100; i < 200; ++i) {
-        executor->add([&collector, i]() {
-            std::this_thread::sleep_for(std::chrono::milliseconds(1));
-            collector.insert(i);
-        }, kLowPriority);
-    }
-    std::this_thread::sleep_for(std::chrono::milliseconds(3));
-    executor->discardAllPendingWork();
-
-    taskGroup.wait();
-
-    // We should've shaved off some work
-    REPORTER_ASSERT(reporter, collector.count() < Collector::kMaxCount);
-    // But, the work that got done should still be in order
-    REPORTER_ASSERT(reporter, collector.dataIsInOrder());
-}
-
-std::unique_ptr<SkExecutor> make_2x_FIFO() {
-    return SkExecutor::MakeMultiListFIFOThreadPool(
-        kNumWorkLists, kNumThreads, /* allowBorrowing= */ false);
-}
-
-std::unique_ptr<SkExecutor> make_2x_LIFO() {
-    return SkExecutor::MakeMultiListLIFOThreadPool(
-        kNumWorkLists, kNumThreads, /* allowBorrowing= */ false);
-}
-
-std::unique_ptr<SkExecutor> make_1x_FIFO() {
-    return SkExecutor::MakeFIFOThreadPool(kNumThreads, /* allowBorrowing= */ false);
-}
-
-} // anonymous namespace
-
-DEF_TEST(Executor, reporter) {
-    // 1x_LIFO is incompatible w/ how this test is structured
-    for (auto makeExecutor : { make_2x_FIFO, make_2x_LIFO, make_1x_FIFO }) {
-        priority_test(reporter, makeExecutor());
-        discard_test(reporter, makeExecutor());
-    }
-}
diff --git a/tests/testgroups.bzl b/tests/testgroups.bzl
index 2289f10..72d28bd 100644
--- a/tests/testgroups.bzl
+++ b/tests/testgroups.bzl
@@ -40,7 +40,6 @@
     "DrawBitmapRectTest.cpp",
     "DrawPathTest.cpp",
     "EmptyPathTest.cpp",
-    "ExecutorTest.cpp",
     "F16StagesTest.cpp",
     "FillPathTest.cpp",
     "FitsInTest.cpp",