medfall

A super great game engine
Log | Files | Refs

waitset.hpp (5582B)


      1 /*  Relacy Race Detector
      2  *  Copyright (c) 2008-2013, Dmitry S. Vyukov
      3  *  All rights reserved.
      4  *  This software is provided AS-IS with no warranty, either express or implied.
      5  *  This software is distributed under a license and may not be copied,
      6  *  modified or distributed except as expressly authorized under the
      7  *  terms of the license contained in the file LICENSE in this distribution.
      8  */
      9 
     10 #ifndef RL_WAITSET_HPP
     11 #define RL_WAITSET_HPP
     12 #ifdef _MSC_VER
     13 #   pragma once
     14 #endif
     15 
     16 #include "base.hpp"
     17 #include "thread_base.hpp"
     18 #include "context_base.hpp"
     19 
     20 
     21 namespace rl
     22 {
     23 
     24 
     25 template<thread_id_t thread_count>
     26 class waitset
     27 {
     28 public:
     29     waitset()
     30     {
     31         size_ = 0;
     32     }
     33 
     34     unpark_reason park_current(context& c,
     35                                bool is_timed,
     36                                bool allow_spurious_wakeup,
     37                                bool do_switch,
     38                                debug_info_param info)
     39     {
     40         RL_VERIFY(size_ < thread_count);
     41         thread_info_base* th = c.threadx_;
     42         thread_desc desc = {th, 0, 0, 0, false, do_switch};
     43         set_[size_] = desc;
     44         size_ += 1;
     45         unpark_reason reason = c.park_current_thread(is_timed, allow_spurious_wakeup, do_switch, info);
     46         if (reason == unpark_reason_normal)
     47         {
     48             if (do_switch)
     49                 RL_VERIFY(c.threadx_->temp_switch_from_ != -1);
     50             else
     51                 RL_VERIFY(c.threadx_->temp_switch_from_ == -1);
     52         }
     53         else
     54         {
     55             remove(th);
     56         }
     57         return reason;
     58     }
     59 
     60     static unpark_reason park_current(context& c,
     61                                       waitset** ws,
     62                                       win_waitable_object** wo,
     63                                       size_t count,
     64                                       bool wait_all,
     65                                       bool is_timed,
     66                                       bool do_switch,
     67                                       debug_info_param info)
     68     {
     69         thread_info_base* th = c.threadx_;
     70         thread_desc desc = {th, (unsigned)count, ws, wo, wait_all, do_switch};
     71         for (unsigned wsi = 0; wsi != count; ++wsi)
     72         {
     73             RL_VERIFY(ws[wsi]->size_ < thread_count);
     74             ws[wsi]->set_[ws[wsi]->size_] = desc;
     75             ws[wsi]->size_ += 1;
     76         }
     77         unpark_reason reason = c.park_current_thread(is_timed, false, do_switch, info);
     78         if (reason == unpark_reason_normal)
     79         {
     80             if (do_switch)
     81                 RL_VERIFY(c.threadx_->temp_switch_from_ != -1);
     82             else
     83                 RL_VERIFY(c.threadx_->temp_switch_from_ == -1);
     84         }
     85         else
     86         {
     87             remove(th, ws, (unsigned)count);
     88         }
     89         return reason;
     90     }
     91 
     92     bool unpark_one(context& c, debug_info_param info)
     93     {
     94         if (0 == size_)
     95             return false;
     96         //!!! too high preassure on full sched
     97         thread_id_t idx = c.rand(size_, sched_type_user);
     98         if (try_remove(c, idx, info))
     99             return true;
    100         for (idx = 0; idx != size_; idx += 1)
    101         {
    102             if (try_remove(c, idx, info))
    103                 return true;
    104         }
    105         return false;
    106     }
    107 
    108     thread_id_t unpark_all(context& c, debug_info_param info)
    109     {
    110         thread_id_t cnt = 0;
    111         for (thread_id_t idx = 0; idx != size_; idx += 1)
    112         {
    113             if (try_remove(c, idx, info))
    114             {
    115                 cnt += 1;
    116                 idx -= 1;
    117             }
    118         }
    119         return cnt;
    120     }
    121 
    122     thread_id_t size() const
    123     {
    124         return size_;
    125     }
    126 
    127     operator bool () const
    128     {
    129         return 0 != size_;
    130     }
    131 
    132 private:
    133     struct thread_desc
    134     {
    135         thread_info_base*       th_;
    136         unsigned                count_;     // 0 - wfso, !0 - wfmo
    137         waitset**               ws_;        // 0 - wfso, !0 - wfmo
    138         win_waitable_object**   wo_;        // 0 - wfso, !0 - wfmo
    139         bool                    wait_all_;
    140         bool                    do_switch_;
    141     };
    142 
    143     thread_desc                 set_ [thread_count];
    144     thread_id_t                 size_;
    145 
    146     bool try_remove(context& c, thread_id_t const idx, debug_info_param info)
    147     {
    148         RL_VERIFY(idx < size_);
    149         thread_desc const& d = set_[idx];
    150         if (d.count_ != 0 && d.wait_all_ == true)
    151         {
    152             for (size_t i = 0; i != d.count_; i += 1)
    153             {
    154                 if (d.wo_[i]->is_signaled(info) == false)
    155                     return false;
    156             }
    157         }
    158         size_t const tid = d.th_->index_;
    159         bool const do_switch = d.do_switch_;
    160         if (d.ws_)
    161             remove(d.th_, d.ws_, d.count_);
    162         else
    163             remove(d.th_);
    164         c.unpark_thread(tid, do_switch, info);
    165         return true;
    166     }
    167 
    168     void remove(thread_info_base* th)
    169     {
    170         thread_id_t size = size_;
    171         thread_id_t i = 0;
    172         for (; i != size; ++i)
    173         {
    174             if (set_[i].th_ == th)
    175                 break;
    176         }
    177         RL_VERIFY(i != size);
    178         for (thread_id_t j = i + 1; j != size; ++j)
    179         {
    180             set_[j - 1] = set_[j];
    181         }
    182         size_ -= 1;
    183     }
    184 
    185     static void remove(thread_info_base* th, waitset** ws, unsigned count)
    186     {
    187         for (unsigned wsi = 0; wsi != count; ++wsi)
    188         {
    189             ws[wsi]->remove(th);
    190         }
    191     }
    192 };
    193 
    194 
    195 }
    196 
    197 
    198 #endif