1/*
2 * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "BPlatform.h"
29#include "DeferredDecommit.h"
30#include "Mutex.h"
31#include "StaticPerProcess.h"
32#include "Vector.h"
33#include <chrono>
34#include <condition_variable>
35#include <mutex>
36
37#if BOS(DARWIN)
38#include <dispatch/dispatch.h>
39#endif
40
41namespace bmalloc {
42
43class Scavenger : public StaticPerProcess<Scavenger> {
44public:
45 BEXPORT Scavenger(std::lock_guard<Mutex>&);
46
47 ~Scavenger() = delete;
48
49 void scavenge();
50
51#if BOS(DARWIN)
52 void setScavengerThreadQOSClass(qos_class_t overrideClass) { m_requestedScavengerThreadQOSClass = overrideClass; }
53 qos_class_t requestedScavengerThreadQOSClass() const { return m_requestedScavengerThreadQOSClass; }
54#endif
55
56 bool willRun() { return m_state == State::Run; }
57 void run();
58
59 bool willRunSoon() { return m_state > State::Sleep; }
60 void runSoon();
61
62 BEXPORT void didStartGrowing();
63 BEXPORT void scheduleIfUnderMemoryPressure(size_t bytes);
64 BEXPORT void schedule(size_t bytes);
65
66 // This is only here for debugging purposes.
67 // FIXME: Make this fast so we can use it to help determine when to
68 // run the scavenger:
69 // https://bugs.webkit.org/show_bug.cgi?id=184176
70 size_t freeableMemory();
71 // This doesn't do any synchronization, so it might return a slightly out of date answer.
72 // It's unlikely, but possible.
73 size_t footprint();
74
75 void enableMiniMode();
76
77private:
78 enum class State { Sleep, Run, RunSoon };
79
80 void runHoldingLock();
81 void runSoonHoldingLock();
82
83 void scheduleIfUnderMemoryPressureHoldingLock(size_t bytes);
84
85 BNO_RETURN static void threadEntryPoint(Scavenger*);
86 BNO_RETURN void threadRunLoop();
87
88 void setSelfQOSClass();
89 void setThreadName(const char*);
90
91 std::chrono::milliseconds timeSinceLastFullScavenge();
92
93 std::atomic<State> m_state { State::Sleep };
94 size_t m_scavengerBytes { 0 };
95 std::chrono::milliseconds m_waitTime;
96 bool m_isProbablyGrowing { false };
97 bool m_isInMiniMode { false };
98
99 Mutex m_scavengingMutex;
100 std::condition_variable_any m_condition;
101
102 std::thread m_thread;
103 std::chrono::steady_clock::time_point m_lastFullScavengeTime { std::chrono::steady_clock::now() };
104
105#if BOS(DARWIN)
106 dispatch_source_t m_pressureHandlerDispatchSource;
107 qos_class_t m_requestedScavengerThreadQOSClass { QOS_CLASS_USER_INITIATED };
108#endif
109
110 Vector<DeferredDecommit> m_deferredDecommits;
111};
112DECLARE_STATIC_PER_PROCESS_STORAGE(Scavenger);
113
114} // namespace bmalloc
115
116
117