tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

EventTokenBucket.h (5864B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef NetEventTokenBucket_h__
      8 #define NetEventTokenBucket_h__
      9 
     10 #include "ARefBase.h"
     11 #include "nsCOMPtr.h"
     12 #include "nsDeque.h"
     13 #include "nsINamed.h"
     14 #include "nsITimer.h"
     15 
     16 #include "mozilla/TimeStamp.h"
     17 
     18 class nsICancelable;
     19 
     20 namespace mozilla {
     21 namespace net {
     22 
     23 /* A token bucket is used to govern the maximum rate a series of events
     24   can be executed at. For instance if your event was "eat a piece of cake"
     25   then a token bucket configured to allow "1 piece per day" would spread
     26   the eating of a 8 piece cake over 8 days even if you tried to eat the
     27   whole thing up front. In a practical sense it 'costs' 1 token to execute
     28   an event and tokens are 'earned' at a particular rate as time goes by.
     29 
     30   The token bucket can be perfectly smooth or allow a configurable amount of
     31   burstiness. A bursty token bucket allows you to save up unused credits, while
     32   a perfectly smooth one would not. A smooth "1 per day" cake token bucket
     33   would require 9 days to eat that cake if you skipped a slice on day 4
     34   (use the token or lose it), while a token bucket configured with a burst
     35   of 2 would just let you eat 2 slices on day 5 (the credits for day 4 and day
     36   5) and finish the cake in the usual 8 days.
     37 
     38   EventTokenBucket(hz=20, burst=5) creates a token bucket with the following
     39   properties:
     40 
     41  + events from an infinite stream will be admitted 20 times per second (i.e.
     42    hz=20 means 1 event per 50 ms). Timers will be used to space things evenly
     43    down to 5ms gaps (i.e. up to 200hz). Token buckets with rates greater than
     44    200hz will admit multiple events with 5ms gaps between them. 10000hz is the
     45    maximum rate and 1hz is the minimum rate.
     46 
     47  + The burst size controls the limit of 'credits' that a token bucket can
     48    accumulate when idle. For our (20,5) example each event requires 50ms of
     49    credit (again, 20hz = 50ms per event). a burst size of 5 means that the
     50    token bucket can accumulate a maximum of 250ms (5 * 50ms) for this bucket.
     51    If no events have been admitted for the last full second the bucket can
     52    still only accumulate 250ms of credit - but that credit means that 5 events
     53    can be admitted without delay. A burst size of 1 is the minimum.  The
     54    EventTokenBucket is created with maximum credits already applied, but they
     55    can be cleared with the ClearCredits() method. The maximum burst size is 15
     56    minutes worth of events.
     57 
     58  + An event is submitted to the token bucket asynchronously through
     59    SubmitEvent().  The OnTokenBucketAdmitted() method of the submitted event
     60    is used as a callback when the event is ready to run. A cancelable event is
     61    returned to the SubmitEvent() caller for use in the case they do not wish
     62    to wait for the callback.
     63 */
     64 
     65 class EventTokenBucket;
     66 
     67 class ATokenBucketEvent {
     68 public:
     69  virtual void OnTokenBucketAdmitted() = 0;
     70 };
     71 
     72 class TokenBucketCancelable;
     73 
     74 class EventTokenBucket : public nsITimerCallback,
     75                         public nsINamed,
     76                         public ARefBase {
     77 public:
     78  NS_DECL_THREADSAFE_ISUPPORTS
     79  NS_DECL_NSITIMERCALLBACK
     80  NS_DECL_NSINAMED
     81 
     82  // This should be constructed on the main thread
     83  EventTokenBucket(uint32_t eventsPerSecond, uint32_t burstSize);
     84 
     85  // These public methods are all meant to be called from the socket thread
     86  void ClearCredits();
     87  uint32_t BurstEventsAvailable();
     88  uint32_t QueuedEvents();
     89 
     90  // a paused token bucket will not process any events, but it will accumulate
     91  // credits. ClearCredits can be used before unpausing if desired.
     92  void Pause();
     93  void UnPause();
     94  void Stop();
     95 
     96  // The returned cancelable event can only be canceled from the socket thread
     97  nsresult SubmitEvent(ATokenBucketEvent* event, nsICancelable** cancelable);
     98 
     99 private:
    100  virtual ~EventTokenBucket();
    101  void CleanupTimers();
    102 
    103  friend class RunNotifyEvent;
    104  friend class SetTimerEvent;
    105 
    106  bool TryImmediateDispatch(TokenBucketCancelable* cancelable);
    107  void SetRate(uint32_t eventsPerSecond, uint32_t burstSize);
    108 
    109  void DispatchEvents();
    110  void UpdateTimer();
    111  void UpdateCredits();
    112 
    113  const static uint64_t kUsecPerSec = 1000000;
    114  const static uint64_t kUsecPerMsec = 1000;
    115  const static uint64_t kMaxHz = 10000;
    116 
    117  uint64_t
    118      mUnitCost;  // usec of credit needed for 1 event (from eventsPerSecond)
    119  uint64_t mMaxCredit;  // usec mCredit limit (from busrtSize)
    120  uint64_t mCredit;     // usec of accumulated credit.
    121 
    122  bool mPaused;
    123  bool mStopped;
    124  nsRefPtrDeque<TokenBucketCancelable> mEvents;
    125  bool mTimerArmed;
    126  TimeStamp mLastUpdate;
    127 
    128  // The timer is created on the main thread, but is armed and executes Notify()
    129  // callbacks on the socket thread in order to maintain low latency of event
    130  // delivery.
    131  nsCOMPtr<nsITimer> mTimer;
    132 
    133 #ifdef XP_WIN
    134  // Windows timers are 15ms granularity by default. When we have active events
    135  // that need to be dispatched at 50ms  or less granularity we change the OS
    136  // granularity to 1ms. 90 seconds after that need has elapsed we will change
    137  // it back
    138  const static uint64_t kCostFineGrainThreshold = 50 * kUsecPerMsec;
    139 
    140  void FineGrainTimers();   // get 1ms granularity
    141  void NormalTimers();      // reset to default granularity
    142  void WantNormalTimers();  // reset after 90 seconds if not needed in interim
    143  void FineGrainResetTimerNotify();  // delayed callback to reset
    144 
    145  TimeStamp mLastFineGrainTimerUse;
    146  bool mFineGrainTimerInUse;
    147  bool mFineGrainResetTimerArmed;
    148  nsCOMPtr<nsITimer> mFineGrainResetTimer;
    149 #endif
    150 };
    151 
    152 }  // namespace net
    153 }  // namespace mozilla
    154 
    155 #endif