text: // Copyright 2016 The Fuchsia Authors
  //
  // Use of this source code is governed by a MIT-style
  // license that can be found in the LICENSE file or at
  // https://opensource.org/licenses/MIT
  
  #pragma once
  
  #include <fbl/canary.h>
  #include <fbl/intrusive_double_list.h>
  #include <fbl/name.h>
  #include <kernel/lockdep.h>
  #include <kernel/mutex.h>
  #include <object/dispatcher.h>
  #include <object/handle.h>
  #include <region-alloc/region-alloc.h>
  #include <sys/types.h>
  
  #include <zircon/compiler.h>
  #include <zircon/rights.h>
  #include <zircon/syscalls/resource.h>
  #include <zircon/thread_annotations.h>
  #include <zircon/types.h>
  
  class ResourceRecord;
  
  class ResourceDispatcher final :
      public SoloDispatcher<ResourceDispatcher, ZX_DEFAULT_RESOURCE_RIGHTS>,
      public fbl::DoublyLinkedListable<ResourceDispatcher*> {
  public:
      static constexpr size_t kMaxRegionPoolSize = 64 << 10;
  
      using ResourceList = fbl::DoublyLinkedList<ResourceDispatcher*>;
      using RefPtr = fbl::RefPtr<ResourceDispatcher>;
  
      // Creates ResourceDispatcher object representing access rights to a
      // given region of address space from a particular address space allocator, or a root resource
      // granted full access permissions. Only one instance of the root resource is created at boot.
      static zx_status_t Create(KernelHandle<ResourceDispatcher>* handle,
                                zx_rights_t* rights,
                                uint32_t kind,
                                uint64_t base,
                                size_t size,
                                uint32_t flags,
                                const char name[ZX_MAX_NAME_LEN],
                                RegionAllocator rallocs[ZX_RSRC_KIND_COUNT] = static_rallocs_,
                                ResourceList* resource_list = &static_resource_list_);
      // Initializes the static mmembers used for bookkeeping and storage.
      static zx_status_t InitializeAllocator(uint32_t kind,
                                             uint64_t base,
                                             size_t size,
                                             RegionAllocator rallocs[ZX_RSRC_KIND_COUNT] =
                                                 static_rallocs_);
      static void Dump();
  
      template <typename T>
      static zx_status_t ForEachResource(T func, ResourceList* resource_list = &static_resource_list_)
          TA_EXCL(ResourcesLock::Get()) {
          Guard<Mutex> guard{ResourcesLock::Get()};
          return ForEachResourceLocked(func, resource_list);
      }
  
      zx_obj_type_t get_type() const final { return ZX_OBJ_TYPE_RESOURCE; }
  
      // Returns a null-terminated name, or the empty string if set_name() has not
      // been called.
      void get_name(char out_name[ZX_MAX_NAME_LEN]) const final {
          name_.get(ZX_MAX_NAME_LEN, out_name);
      }
  
      // Sets the name of the object. May truncate internally. |size| is the size
      // of the buffer pointed to by |name|.
      zx_status_t set_name(const char* name, size_t size) final {
          return name_.set(name, size);
      }
  
      uint64_t get_base() const { return base_; }
      size_t get_size() const { return size_; }
      uint32_t get_kind() const { return kind_; }
      uint32_t get_flags() const { return flags_; }
      ~ResourceDispatcher();
  
  private:
      ResourceDispatcher(uint32_t kind,
                         uint64_t base,
                         size_t size,
                         uint32_t flags,
                         RegionAllocator::Region::UPtr&& region,
                         RegionAllocator rallocs[ZX_RSRC_KIND_COUNT],
                         ResourceList* resource_list);
  
      template <typename T>
      static zx_status_t ForEachResourceLocked(T callback,
                                               ResourceList* resource_list = &static_resource_list_)
          TA_REQ(ResourcesLock::Get()) {
          for (const auto& resource : *resource_list) {
              zx_status_t status = callback(resource);
              if (status != ZX_OK) {
                  return status;
              }
          }
          return ZX_OK;
      }
  
      const uint32_t kind_;
      const uint64_t base_;
      const size_t size_;
      const uint32_t flags_;
      ResourceList* resource_list_;
      fbl::Name<ZX_MAX_NAME_LEN> name_;
      RegionAllocator::Region::UPtr exclusive_region_;
  
      // Static tracking data structures for physical address space allocations.
      // Exclusive allocations are pulled out of the RegionAllocators, and all
      // allocations are added to |static_resource_list_|. Shared allocations will
      // check that no exclusive reservation exists, but then release the region
      // back to the allocator. Likewise, exclusive allocations will check to
      // ensure that the region has not already been allocated as a shared region
      // by checking the static resource list.
      DECLARE_SINGLETON_MUTEX(ResourcesLock);
      static RegionAllocator static_rallocs_[ZX_RSRC_KIND_COUNT] TA_GUARDED(ResourcesLock::Get());
      static RegionAllocator::RegionPool::RefPtr region_pool_;
      // A single global list is used for all resources so that root and hypervisor resources can
      // still be tracked, and filtering can be done via client tools/commands when displaying
      // the list is concerned.
      static ResourceList static_resource_list_ TA_GUARDED(ResourcesLock::Get());
  };
  