summaryrefslogtreecommitdiffstats
path: root/xpcom/components/nsCategoryManager.h
blob: 765882fe475be8862168abb2ed0ae4c2c1745c3d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* -*- 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 NSCATEGORYMANAGER_H
#define NSCATEGORYMANAGER_H

#include "prio.h"
#include "nsClassHashtable.h"
#include "nsICategoryManager.h"
#include "nsIMemoryReporter.h"
#include "mozilla/ArenaAllocator.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Mutex.h"
#include "mozilla/Attributes.h"

class nsIMemoryReporter;

typedef mozilla::ArenaAllocator<1024 * 8, 8> CategoryAllocator;

/* 16d222a6-1dd2-11b2-b693-f38b02c021b2 */
#define NS_CATEGORYMANAGER_CID                       \
  {                                                  \
    0x16d222a6, 0x1dd2, 0x11b2, {                    \
      0xb6, 0x93, 0xf3, 0x8b, 0x02, 0xc0, 0x21, 0xb2 \
    }                                                \
  }

/**
 * a "leaf-node", managed by the nsCategoryNode hashtable.
 *
 * we need to keep a "persistent value" (which will be written to the registry)
 * and a non-persistent value (for the current runtime): these are usually
 * the same, except when aPersist==false. The strings are permanently arena-
 * allocated, and will never go away.
 */
class CategoryLeaf : public nsDepCharHashKey {
 public:
  explicit CategoryLeaf(const char* aKey)
      : nsDepCharHashKey(aKey), value(nullptr) {}
  const char* value;
};

/**
 * CategoryNode keeps a hashtable of its entries.
 * the CategoryNode itself is permanently allocated in
 * the arena.
 */
class CategoryNode {
 public:
  nsresult GetLeaf(const nsACString& aEntryName, nsACString& aResult);

  nsresult AddLeaf(const nsACString& aEntryName, const nsACString& aValue,
                   bool aReplace, nsACString& aResult,
                   CategoryAllocator* aArena);

  void DeleteLeaf(const nsACString& aEntryName);

  void Clear() {
    mozilla::MutexAutoLock lock(mLock);
    mTable.Clear();
  }

  uint32_t Count() {
    mozilla::MutexAutoLock lock(mLock);
    uint32_t tCount = mTable.Count();
    return tCount;
  }

  nsresult Enumerate(nsISimpleEnumerator** aResult);

  // CategoryNode is arena-allocated, with the strings
  static CategoryNode* Create(CategoryAllocator* aArena);
  ~CategoryNode();
  void operator delete(void*) {}

  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf);

 private:
  CategoryNode() : mLock("CategoryLeaf") {}

  void* operator new(size_t aSize, CategoryAllocator* aArena);

  nsTHashtable<CategoryLeaf> mTable MOZ_GUARDED_BY(mLock);
  mozilla::Mutex mLock;
};

/**
 * The main implementation of nsICategoryManager.
 *
 * This implementation is thread-safe.
 */
class nsCategoryManager final : public nsICategoryManager,
                                public nsIMemoryReporter {
 public:
  NS_DECL_ISUPPORTS
  NS_DECL_NSICATEGORYMANAGER
  NS_DECL_NSIMEMORYREPORTER

  /**
   * Suppress or unsuppress notifications of category changes to the
   * observer service. This is to be used by nsComponentManagerImpl
   * on startup while reading the stored category list.
   */
  nsresult SuppressNotifications(bool aSuppress);

  void AddCategoryEntry(const nsACString& aCategory, const nsACString& aKey,
                        const nsACString& aValue, bool aReplace,
                        nsACString& aOldValue);

  void AddCategoryEntry(const nsACString& aCategory, const nsACString& aKey,
                        const nsACString& aValue, bool aReplace = true) {
    nsCString oldValue;
    return AddCategoryEntry(aCategory, aKey, aValue, aReplace, oldValue);
  }

  static nsresult Create(REFNSIID aIID, void** aResult);
  void InitMemoryReporter();

  static nsCategoryManager* GetSingleton();
  static void Destroy();

 private:
  static nsCategoryManager* gCategoryManager;

  nsCategoryManager();
  ~nsCategoryManager();

  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);

  CategoryNode* get_category(const nsACString& aName) MOZ_REQUIRES(mLock);
  void NotifyObservers(
      const char* aTopic,
      const nsACString& aCategoryName,  // must be a static string
      const nsACString& aEntryName);

  CategoryAllocator mArena;  // Mainthread only
  nsClassHashtable<nsDepCharHashKey, CategoryNode> mTable MOZ_GUARDED_BY(mLock);
  mozilla::Mutex mLock;
  bool mSuppressNotifications;  // Mainthread only
};

#endif