hunk.code_window: iOS worker VMs run on Mac Mini 8.1 hosts in an isolated environment. Every build gets its own fresh macOS VM:
   - Hardware:
     - Intel: Intel(R) Core(TM) i7-8700B CPU (6 cores/12 threads), 64 GB RAM
     - M1: 3.2GHz 8-Core M1 (4 performance and 4 efficiency cores), 16 GB RAM [2020]
   - Build resources:
     - [`intel-medium`](eas-json/#resourceclass-2): 3 cores, 12 GB RAM, 2 builder VMs per host
  
hunk.labels: keep keep keep keep replace keep keep
hunk.after_edit:   - M1: 3.2GHz 8-Core M1 (4 performance and 4 efficiency cores), 16 GB RAM
     - M2: 3.4GHz 12-Core M2 (8 performance and 4 efficiency cores), 24 GB RAM
  
hunk.file_path: docs/pages/build-reference/infrastructure.mdx
hunk.type: replace
file: /*
   * Copyright 2020 Google LLC
   *
   * Use of this source code is governed by a BSD-style license that can be
   * found in the LICENSE file.
   */
  
  #ifndef SkIDChangeListener_DEFINED
  #define SkIDChangeListener_DEFINED
  
  #include "include/core/SkRefCnt.h"
  #include "include/private/SkMutex.h"
  #include "include/private/SkTDArray.h"
  
  #include <atomic>
  
  /**
   * Used to be notified when a gen/unique ID is invalidated, typically to preemptively purge
   * associated items from a cache that are no longer reachable. The listener can
   * be marked for deregistration if the cached item is remove before the listener is
   * triggered. This prevents unbounded listener growth when cache items are routinely
   * removed before the gen ID/unique ID is invalidated.
   */
  class SkIDChangeListener : public SkRefCnt {
  public:
      SkIDChangeListener();
  
      ~SkIDChangeListener() override;
  
      virtual void changed() = 0;
  
      /**
       * Mark the listener is no longer needed. It should be removed and changed() should not be
       * called.
       */
      void markShouldDeregister() { fShouldDeregister.store(true, std::memory_order_relaxed); }
  
      /** Indicates whether markShouldDeregister was called. */
      bool shouldDeregister() { return fShouldDeregister.load(std::memory_order_acquire); }
  
      /** Manages a list of SkIDChangeListeners. */
      class List {
      public:
          List();
  
          ~List();
  
          /**
           * Add a new listener to the list. It must not already be deregistered. Also clears out
           * previously deregistered listeners.
           */
          void add(sk_sp<SkIDChangeListener> listener) SK_EXCLUDES(fMutex);
  
          /**
           * The number of registered listeners (including deregisterd listeners that are yet-to-be
           * removed.
           */
          int count() const SK_EXCLUDES(fMutex);
  
          /** Calls changed() on all listeners that haven't been deregistered and resets the list. */
          void changed() SK_EXCLUDES(fMutex);
  
          /** Resets without calling changed() on the listeners. */
          void reset() SK_EXCLUDES(fMutex);
  
      private:
          mutable SkMutex fMutex;
          SkTDArray<SkIDChangeListener*> fListeners SK_GUARDED_BY(fMutex);  // pointers are reffed
      };
  
  private:
      std::atomic<bool> fShouldDeregister;
  };
  
  #endif
  