Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-03-13 09:10:09

0001 //
0002 // MIT License
0003 // Copyright (c) 2020 Jonathan R. Madsen
0004 // Permission is hereby granted, free of charge, to any person obtaining a copy
0005 // of this software and associated documentation files (the "Software"), to deal
0006 // in the Software without restriction, including without limitation the rights
0007 // to use, copy, modify, merge, publish, distribute, sublicense, and
0008 // copies of the Software, and to permit persons to whom the Software is
0009 // furnished to do so, subject to the following conditions:
0010 // The above copyright notice and this permission notice shall be included in
0011 // all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
0012 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
0013 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
0014 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
0015 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
0016 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
0017 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0018 //
0019 
0020 #ifndef G4GMAKE
0021 #include "PTL/Config.hh"  // IWYU pragma: keep
0022 #endif
0023 #include "PTL/Globals.hh"
0024 #include "PTL/VTask.hh"
0025 #if defined(PTL_USE_LOCKS)
0026 #    include "PTL/AutoLock.hh"
0027 #endif
0028 
0029 #include <atomic>
0030 #include <cassert>
0031 #include <list>
0032 #include <memory>
0033 #include <utility>
0034 
0035 namespace PTL
0036 {
0037 class TaskSubQueue
0038 {
0039 public:
0040     template <typename Tp>
0041     using container = std::list<Tp>;
0042 
0043     using task_pointer   = std::shared_ptr<VTask>;
0044     using container_type = container<task_pointer>;
0045     using size_type      = container_type::size_type;
0046 
0047 public:
0048     TaskSubQueue(std::atomic_uintmax_t* _ntasks);
0049     TaskSubQueue(const TaskSubQueue&);
0050     ~TaskSubQueue() = default;
0051 
0052     TaskSubQueue& operator=(const TaskSubQueue&) = delete;
0053 
0054 public:
0055     int GetId() const;
0056 
0057     bool AcquireClaim();
0058     void ReleaseClaim();
0059 
0060     void         PushTask(task_pointer&&) PTL_NO_SANITIZE_THREAD;
0061     task_pointer PopTask(bool front = true) PTL_NO_SANITIZE_THREAD;
0062 
0063     size_type size() const;
0064     bool      empty() const;
0065 
0066 private:
0067     // mutex
0068 #if defined(PTL_USE_LOCKS)
0069     Mutex m_mutex{};
0070 #endif
0071     // used internally to keep number of tasks
0072     std::atomic<size_type> m_ntasks;
0073     // for checking if being modified
0074     std::atomic_bool m_available;
0075     // used my master queue to keep track of number of tasks
0076     std::atomic_uintmax_t* m_all_tasks;
0077     // queue of tasks
0078     container_type m_task_queue;
0079 };
0080 
0081 //======================================================================================//
0082 
0083 inline TaskSubQueue::TaskSubQueue(std::atomic_uintmax_t* _ntasks)
0084 : m_ntasks(0)
0085 , m_available(true)
0086 , m_all_tasks(_ntasks)
0087 {}
0088 
0089 //======================================================================================//
0090 
0091 inline TaskSubQueue::TaskSubQueue(const TaskSubQueue& rhs)
0092 : m_ntasks(0)
0093 , m_available(true)
0094 , m_all_tasks(rhs.m_all_tasks)
0095 {}
0096 
0097 //======================================================================================//
0098 
0099 inline bool
0100 TaskSubQueue::AcquireClaim()
0101 {
0102     bool is_avail = m_available.load(std::memory_order_relaxed);
0103     if(!is_avail)
0104         return false;
0105     return m_available.compare_exchange_strong(is_avail, false,
0106                                                std::memory_order_relaxed);
0107 }
0108 
0109 //======================================================================================//
0110 
0111 inline void
0112 TaskSubQueue::ReleaseClaim()
0113 {
0114     // if(m_available.load(std::memory_order_relaxed))
0115     //    return;
0116     m_available.store(true, std::memory_order_release);
0117 }
0118 
0119 //======================================================================================//
0120 
0121 inline TaskSubQueue::size_type
0122 TaskSubQueue::size() const
0123 {
0124     return m_ntasks.load();
0125 }
0126 
0127 //======================================================================================//
0128 
0129 inline bool
0130 TaskSubQueue::empty() const
0131 {
0132     return (m_ntasks.load() == 0);
0133 }
0134 
0135 //======================================================================================//
0136 
0137 inline void
0138 TaskSubQueue::PushTask(task_pointer&& task)
0139 {
0140     // no need to lock these if claim is acquired via atomic
0141     assert(m_available.load(std::memory_order_relaxed) == false);
0142     ++m_ntasks;
0143 #if defined(PTL_USE_LOCKS)
0144     AutoLock lk{ m_mutex };
0145 #endif
0146     m_task_queue.emplace_front(std::move(task));
0147 }
0148 
0149 //======================================================================================//
0150 
0151 inline TaskSubQueue::task_pointer
0152 TaskSubQueue::PopTask(bool front)
0153 {
0154     // no need to lock -- claim is acquired via atomic
0155     assert(m_available.load(std::memory_order_relaxed) == false);
0156     if(m_ntasks.load() == 0)
0157         return nullptr;
0158 
0159     task_pointer _task{ nullptr };
0160     if(front)
0161     {
0162 #if defined(PTL_USE_LOCKS)
0163         AutoLock lk{ m_mutex };
0164 #endif
0165         _task = std::move(m_task_queue.front());
0166         m_task_queue.pop_front();
0167     }
0168     else
0169     {
0170 #if defined(PTL_USE_LOCKS)
0171         AutoLock lk{ m_mutex };
0172 #endif
0173         _task = std::move(m_task_queue.back());
0174         m_task_queue.pop_back();
0175     }
0176     --m_ntasks;
0177 
0178     return _task;
0179 }
0180 
0181 //======================================================================================//
0182 }  // namespace PTL