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
|
/*
* Copyright (C) 2018-2021 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "shared/source/memory_manager/deferred_deleter.h"
#include "shared/source/memory_manager/deferrable_deletion.h"
#include "shared/source/os_interface/os_thread.h"
namespace NEO {
DeferredDeleter::DeferredDeleter() {
doWorkInBackground = false;
elementsToRelease = 0;
}
void DeferredDeleter::stop() {
// Called with threadMutex acquired
if (worker != nullptr) {
// Working thread was created so we can safely stop it
std::unique_lock<std::mutex> lock(queueMutex);
// Make sure that working thread really started
while (!doWorkInBackground) {
lock.unlock();
lock.lock();
}
// Signal working thread to finish its job
doWorkInBackground = false;
lock.unlock();
condition.notify_one();
// Wait for the working job to exit
worker->join();
// Delete working thread
worker.reset();
}
drain(false);
}
void DeferredDeleter::safeStop() {
std::lock_guard<std::mutex> lock(threadMutex);
stop();
}
DeferredDeleter::~DeferredDeleter() {
safeStop();
}
void DeferredDeleter::deferDeletion(DeferrableDeletion *deletion) {
std::unique_lock<std::mutex> lock(queueMutex);
elementsToRelease++;
queue.pushTailOne(*deletion);
lock.unlock();
condition.notify_one();
}
void DeferredDeleter::addClient() {
std::lock_guard<std::mutex> lock(threadMutex);
++numClients;
ensureThread();
}
void DeferredDeleter::removeClient() {
std::lock_guard<std::mutex> lock(threadMutex);
--numClients;
if (numClients == 0) {
stop();
}
}
void DeferredDeleter::ensureThread() {
if (worker != nullptr) {
return;
}
worker = Thread::create(run, reinterpret_cast<void *>(this));
}
bool DeferredDeleter::areElementsReleased() {
return elementsToRelease == 0;
}
bool DeferredDeleter::shouldStop() {
return !doWorkInBackground;
}
void *DeferredDeleter::run(void *arg) {
auto self = reinterpret_cast<DeferredDeleter *>(arg);
std::unique_lock<std::mutex> lock(self->queueMutex);
// Mark that working thread really started
self->doWorkInBackground = true;
do {
if (self->queue.peekIsEmpty()) {
// Wait for signal that some items are ready to be deleted
self->condition.wait(lock);
}
lock.unlock();
// Delete items placed into deferred delete queue
self->clearQueue();
lock.lock();
// Check whether working thread should be stopped
} while (!self->shouldStop());
lock.unlock();
return nullptr;
}
void DeferredDeleter::drain(bool blocking) {
clearQueue();
if (blocking) {
while (!areElementsReleased())
;
}
}
void DeferredDeleter::clearQueue() {
do {
auto deletion = queue.removeFrontOne();
if (deletion) {
if (deletion->apply()) {
elementsToRelease--;
} else {
queue.pushTailOne(*deletion.release());
}
}
} while (!queue.peekIsEmpty());
}
} // namespace NEO
|