text: // Copyright 2017 The Fuchsia Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef DISPATCHER_POOL_DISPATCHER_THREAD_POOL_H_
  #define DISPATCHER_POOL_DISPATCHER_THREAD_POOL_H_
  
  #include <lib/zx/port.h>
  #include <lib/zx/profile.h>
  #include <threads.h>
  #include <zircon/compiler.h>
  #include <zircon/types.h>
  
  #include <memory>
  
  #include <dispatcher-pool/dispatcher-execution-domain.h>
  #include <fbl/auto_lock.h>
  #include <fbl/intrusive_double_list.h>
  #include <fbl/intrusive_single_list.h>
  #include <fbl/intrusive_wavl_tree.h>
  #include <fbl/mutex.h>
  #include <fbl/ref_counted.h>
  #include <fbl/ref_ptr.h>
  
  namespace dispatcher {
  
  class ThreadPool : public fbl::RefCounted<ThreadPool>,
                     public fbl::WAVLTreeContainable<fbl::RefPtr<ThreadPool>> {
   public:
    static zx_status_t Get(fbl::RefPtr<ThreadPool>* pool_out, zx::profile profile);
    static void ShutdownAll();
  
    void Shutdown();
    zx_status_t AddDomainToPool(fbl::RefPtr<ExecutionDomain> domain);
    void RemoveDomainFromPool(ExecutionDomain* domain);
  
    zx_status_t WaitOnPort(const zx::handle& handle, uint64_t key, zx_signals_t signals,
                           uint32_t options);
    zx_status_t CancelWaitOnPort(const zx::handle& handle, uint64_t key);
    zx_status_t BindIrqToPort(const zx::handle& irq_handle, uint64_t key);
  
    uint64_t GetKey() const;
  
   private:
    friend class fbl::RefPtr<ThreadPool>;
  
    class Thread : public fbl::DoublyLinkedListable<std::unique_ptr<Thread>> {
     public:
      static std::unique_ptr<Thread> Create(fbl::RefPtr<ThreadPool> pool, uint32_t id);
      zx_status_t Start();
      void Join();
  
     private:
      Thread(fbl::RefPtr<ThreadPool> pool, uint32_t id);
  
      void PrintDebugPrefix() const;
      int Main();
  
      // TODO(johngro) : migrate away from C11 threads, use native zircon
      // primitives instead.
      //
      // TODO(johngro) : What is the proper "invalid" value to initialize with
      // here?
      thrd_t thread_handle_;
      fbl::RefPtr<ThreadPool> pool_;
      const uint32_t id_;
    };
  
    explicit ThreadPool(zx::profile profile);
    ~ThreadPool() {}
  
    const zx::profile& profile() const { return profile_; }
    const zx::port& port() const { return port_; }
  
    void PrintDebugPrefix();
    zx_status_t Init();
    void InternalShutdown();
  
    static fbl::Mutex active_pools_lock_;
    static fbl::WAVLTree<zx_koid_t, fbl::RefPtr<ThreadPool>> active_pools_
        __TA_GUARDED(active_pools_lock_);
    static bool system_shutdown_ __TA_GUARDED(active_pools_lock_);
  
    const zx::profile profile_;
    zx_koid_t profile_koid_;
  
    fbl::Mutex pool_lock_ __TA_ACQUIRED_AFTER(active_pools_lock_);
    zx::port port_;
    uint32_t active_domain_count_ __TA_GUARDED(pool_lock_) = 0;
    uint32_t active_thread_count_ __TA_GUARDED(pool_lock_) = 0;
    bool pool_shutting_down_ __TA_GUARDED(pool_lock_) = false;
  
    fbl::DoublyLinkedList<fbl::RefPtr<ExecutionDomain>, ExecutionDomain::ThreadPoolListTraits>
        active_domains_ __TA_GUARDED(pool_lock_);
  
    fbl::DoublyLinkedList<std::unique_ptr<Thread>> active_threads_ __TA_GUARDED(pool_lock_);
  };
  
  }  // namespace dispatcher
  
  #endif  // DISPATCHER_POOL_DISPATCHER_THREAD_POOL_H_
  