xpcom/threads/ThreadEventQueue.h
author Henri Sivonen <hsivonen@hsivonen.fi>
Fri, 06 Jul 2018 10:44:43 +0300
changeset 489140 4ef0f163fdeb9afeddd87b37bfd987298c038542
parent 485689 e3f3506f327c421dcffc00266382669bbe2d101a
child 508163 6f3709b3878117466168c40affa7bca0b60cf75b
permissions -rw-r--r--
Bug 1402247 - Use encoding_rs for XPCOM string encoding conversions. r=Nika,erahm,froydnj. Correctness improvements: * UTF errors are handled safely per spec instead of dangerously truncating strings. * There are fewer converter implementations. Performance improvements: * The old code did exact buffer length math, which meant doing UTF math twice on each input string (once for length calculation and another time for conversion). Exact length math is more complicated when handling errors properly, which the old code didn't do. The new code does UTF math on the string content only once (when converting) but risks allocating more than once. There are heuristics in place to lower the probability of reallocation in cases where the double math avoidance isn't enough of a saving to absorb an allocation and memcpy. * Previously, in UTF-16 <-> UTF-8 conversions, an ASCII prefix was optimized but a single non-ASCII code point pessimized the rest of the string. The new code tries to get back on the fast ASCII path. * UTF-16 to Latin1 conversion guarantees less about handling of out-of-range input to eliminate an operation from the inner loop on x86/x86_64. * When assigning to a pre-existing string, the new code tries to reuse the old buffer instead of first releasing the old buffer and then allocating a new one. * When reallocating from the new code, the memcpy covers only the data that is part of the logical length of the old string instead of memcpying the whole capacity. (For old callers old excess memcpy behavior is preserved due to bogus callers. See bug 1472113.) * UTF-8 strings in XPConnect that are in the Latin1 range are passed to SpiderMonkey as Latin1. New features: * Conversion between UTF-8 and Latin1 is added in order to enable faster future interop between Rust code (or otherwise UTF-8-using code) and text node and SpiderMonkey code that uses Latin1. MozReview-Commit-ID: JaJuExfILM9

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_ThreadEventQueue_h
#define mozilla_ThreadEventQueue_h

#include "mozilla/AbstractEventQueue.h"
#include "mozilla/CondVar.h"
#include "mozilla/SynchronizedEventQueue.h"
#include "nsCOMPtr.h"
#include "nsTArray.h"

class nsIEventTarget;
class nsISerialEventTarget;
class nsIThreadObserver;

namespace mozilla {

class EventQueue;

template<typename InnerQueueT>
class PrioritizedEventQueue;

class LabeledEventQueue;

class ThreadEventTarget;

// A ThreadEventQueue implements normal monitor-style synchronization over the
// InnerQueueT AbstractEventQueue. It also implements PushEventQueue and
// PopEventQueue for workers (see the documentation below for an explanation of
// those). All threads use a ThreadEventQueue as their event queue. InnerQueueT
// is a template parameter to avoid virtual dispatch overhead.
template<class InnerQueueT>
class ThreadEventQueue final : public SynchronizedEventQueue
{
public:
  explicit ThreadEventQueue(UniquePtr<InnerQueueT> aQueue);

  bool PutEvent(already_AddRefed<nsIRunnable>&& aEvent,
                EventPriority aPriority) final;

  already_AddRefed<nsIRunnable> GetEvent(bool aMayWait,
                                         EventPriority* aPriority) final;
  bool HasPendingEvent() final;

  bool ShutdownIfNoPendingEvents() final;

  void Disconnect(const MutexAutoLock& aProofOfLock) final {}

  void EnableInputEventPrioritization() final;
  void FlushInputEventPrioritization() final;
  void SuspendInputEventPrioritization() final;
  void ResumeInputEventPrioritization() final;

  /**
   * This method causes any events currently enqueued on the thread to be
   * suppressed until PopEventQueue is called, and any event dispatched to this
   * thread's nsIEventTarget will queue as well. Calls to PushEventQueue may be
   * nested and must each be paired with a call to PopEventQueue in order to
   * restore the original state of the thread. The returned nsIEventTarget may
   * be used to push events onto the nested queue. Dispatching will be disabled
   * once the event queue is popped. The thread will only ever process pending
   * events for the innermost event queue. Must only be called on the target
   * thread.
   */
  already_AddRefed<nsISerialEventTarget> PushEventQueue();

  /**
   * Revert a call to PushEventQueue. When an event queue is popped, any events
   * remaining in the queue are appended to the elder queue. This also causes
   * the nsIEventTarget returned from PushEventQueue to stop dispatching events.
   * Must only be called on the target thread, and with the innermost event
   * queue.
   */
  void PopEventQueue(nsIEventTarget* aTarget);

  already_AddRefed<nsIThreadObserver> GetObserver() final;
  already_AddRefed<nsIThreadObserver> GetObserverOnThread() final;
  void SetObserver(nsIThreadObserver* aObserver) final;

  Mutex& MutexRef() { return mLock; }

  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;

private:
  class NestedSink;

  virtual ~ThreadEventQueue();

  bool PutEventInternal(already_AddRefed<nsIRunnable>&& aEvent,
                        EventPriority aPriority,
                        NestedSink* aQueue);

  UniquePtr<InnerQueueT> mBaseQueue;

  struct NestedQueueItem
  {
    UniquePtr<EventQueue> mQueue;
    RefPtr<ThreadEventTarget> mEventTarget;

    NestedQueueItem(UniquePtr<EventQueue> aQueue,
                    ThreadEventTarget* aEventTarget)
      : mQueue(std::move(aQueue))
      , mEventTarget(aEventTarget)
    {}
  };

  nsTArray<NestedQueueItem> mNestedQueues;

  Mutex mLock;
  CondVar mEventsAvailable;

  bool mEventsAreDoomed = false;
  nsCOMPtr<nsIThreadObserver> mObserver;
};

extern template class ThreadEventQueue<EventQueue>;
extern template class ThreadEventQueue<PrioritizedEventQueue<EventQueue>>;
extern template class ThreadEventQueue<PrioritizedEventQueue<LabeledEventQueue>>;

}; // namespace mozilla

#endif // mozilla_ThreadEventQueue_h