Bug 1690340 - Part 2: Use the new naming for the developer tools menu items. r=jdescottes
[gecko.git] / xpcom / io / nsSegmentedBuffer.cpp
blob32e8fe35f15a44af6daa7d0db5ec5f3451c2a493
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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/. */
7 #include "nsSegmentedBuffer.h"
8 #include "nsMemory.h"
9 #include "nsNetCID.h"
10 #include "nsServiceManagerUtils.h"
11 #include "nsThreadUtils.h"
12 #include "mozilla/ScopeExit.h"
14 nsresult nsSegmentedBuffer::Init(uint32_t aSegmentSize, uint32_t aMaxSize) {
15 if (mSegmentArrayCount != 0) {
16 return NS_ERROR_FAILURE; // initialized more than once
18 mSegmentSize = aSegmentSize;
19 mMaxSize = aMaxSize;
20 #if 0 // testing...
21 mSegmentArrayCount = 2;
22 #else
23 mSegmentArrayCount = NS_SEGMENTARRAY_INITIAL_COUNT;
24 #endif
25 return NS_OK;
28 char* nsSegmentedBuffer::AppendNewSegment() {
29 if (GetSize() >= mMaxSize) {
30 return nullptr;
33 if (!mSegmentArray) {
34 uint32_t bytes = mSegmentArrayCount * sizeof(char*);
35 mSegmentArray = (char**)moz_xmalloc(bytes);
36 memset(mSegmentArray, 0, bytes);
39 if (IsFull()) {
40 uint32_t newArraySize = mSegmentArrayCount * 2;
41 uint32_t bytes = newArraySize * sizeof(char*);
42 mSegmentArray = (char**)moz_xrealloc(mSegmentArray, bytes);
43 // copy wrapped content to new extension
44 if (mFirstSegmentIndex > mLastSegmentIndex) {
45 // deal with wrap around case
46 memcpy(&mSegmentArray[mSegmentArrayCount], mSegmentArray,
47 mLastSegmentIndex * sizeof(char*));
48 memset(mSegmentArray, 0, mLastSegmentIndex * sizeof(char*));
49 mLastSegmentIndex += mSegmentArrayCount;
50 memset(&mSegmentArray[mLastSegmentIndex], 0,
51 (newArraySize - mLastSegmentIndex) * sizeof(char*));
52 } else {
53 memset(&mSegmentArray[mLastSegmentIndex], 0,
54 (newArraySize - mLastSegmentIndex) * sizeof(char*));
56 mSegmentArrayCount = newArraySize;
59 char* seg = (char*)malloc(mSegmentSize);
60 if (!seg) {
61 return nullptr;
63 mSegmentArray[mLastSegmentIndex] = seg;
64 mLastSegmentIndex = ModSegArraySize(mLastSegmentIndex + 1);
65 return seg;
68 bool nsSegmentedBuffer::DeleteFirstSegment() {
69 NS_ASSERTION(mSegmentArray[mFirstSegmentIndex] != nullptr,
70 "deleting bad segment");
71 FreeOMT(mSegmentArray[mFirstSegmentIndex]);
72 mSegmentArray[mFirstSegmentIndex] = nullptr;
73 int32_t last = ModSegArraySize(mLastSegmentIndex - 1);
74 if (mFirstSegmentIndex == last) {
75 mLastSegmentIndex = last;
76 return true;
77 } else {
78 mFirstSegmentIndex = ModSegArraySize(mFirstSegmentIndex + 1);
79 return false;
83 bool nsSegmentedBuffer::DeleteLastSegment() {
84 int32_t last = ModSegArraySize(mLastSegmentIndex - 1);
85 NS_ASSERTION(mSegmentArray[last] != nullptr, "deleting bad segment");
86 FreeOMT(mSegmentArray[last]);
87 mSegmentArray[last] = nullptr;
88 mLastSegmentIndex = last;
89 return (bool)(mLastSegmentIndex == mFirstSegmentIndex);
92 bool nsSegmentedBuffer::ReallocLastSegment(size_t aNewSize) {
93 int32_t last = ModSegArraySize(mLastSegmentIndex - 1);
94 NS_ASSERTION(mSegmentArray[last] != nullptr, "realloc'ing bad segment");
95 char* newSegment = (char*)realloc(mSegmentArray[last], aNewSize);
96 if (newSegment) {
97 mSegmentArray[last] = newSegment;
98 return true;
100 return false;
103 void nsSegmentedBuffer::Empty() {
104 auto clearMembers = mozilla::MakeScopeExit([&] {
105 mSegmentArray = nullptr;
106 mSegmentArrayCount = NS_SEGMENTARRAY_INITIAL_COUNT;
107 mFirstSegmentIndex = mLastSegmentIndex = 0;
110 // If mSegmentArray is null, there's no need to actually free anything
111 if (!mSegmentArray) {
112 return;
115 // Dispatch a task that frees up the array. This may run immediately or on
116 // a background thread.
117 FreeOMT([segmentArray = mSegmentArray, arrayCount = mSegmentArrayCount]() {
118 for (uint32_t i = 0; i < arrayCount; i++) {
119 if (segmentArray[i]) {
120 free(segmentArray[i]);
123 free(segmentArray);
127 void nsSegmentedBuffer::FreeOMT(void* aPtr) {
128 FreeOMT([aPtr]() { free(aPtr); });
131 void nsSegmentedBuffer::FreeOMT(std::function<void()>&& aTask) {
132 if (!NS_IsMainThread()) {
133 aTask();
134 return;
137 if (mFreeOMT) {
138 // There is a runnable pending which will handle this object
139 if (mFreeOMT->AddTask(std::move(aTask)) > 1) {
140 return;
142 } else {
143 mFreeOMT = MakeRefPtr<FreeOMTPointers>();
144 mFreeOMT->AddTask(std::move(aTask));
147 if (!mIOThread) {
148 mIOThread = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
151 // During the shutdown we are not able to obtain the IOThread and/or the
152 // dispatching of runnable fails.
153 if (!mIOThread || NS_FAILED(mIOThread->Dispatch(NS_NewRunnableFunction(
154 "nsSegmentedBuffer::FreeOMT",
155 [obj = mFreeOMT]() { obj->FreeAll(); })))) {
156 mFreeOMT->FreeAll();
160 void nsSegmentedBuffer::FreeOMTPointers::FreeAll() {
161 // Take all the tasks from the object. If AddTask is called after we release
162 // the lock, then another runnable will be dispatched for that task. This is
163 // necessary to avoid blocking the main thread while memory is being freed.
164 nsTArray<std::function<void()>> tasks = [this]() {
165 auto t = mTasks.Lock();
166 return std::move(*t);
167 }();
169 // Finally run all the tasks to free memory.
170 for (auto& task : tasks) {
171 task();
175 ////////////////////////////////////////////////////////////////////////////////