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
|
/*
* Copyright (C) 2018-2025 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() = default;
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();
worker->detach();
// Wait for the working job to exit main loop
while (!exitedMainLoop) {
std::this_thread::yield();
}
// Delete working thread
worker.reset();
}
drain(false, 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);
this->elementsToRelease++;
if (deletion->isExternalHostptr()) {
this->hostptrsToRelease++;
}
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;
}
exitedMainLoop = false;
worker = Thread::createFunc(run, reinterpret_cast<void *>(this));
}
bool DeferredDeleter::areElementsReleased(bool hostptrsOnly) {
return hostptrsOnly ? this->hostptrsToRelease == 0 : this->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(false);
lock.lock();
// Check whether working thread should be stopped
} while (!self->shouldStop());
lock.unlock();
self->exitedMainLoop = true;
return nullptr;
}
void DeferredDeleter::drain(bool blocking, bool hostptrsOnly) {
clearQueue(hostptrsOnly);
if (blocking) {
while (!areElementsReleased(hostptrsOnly))
;
}
}
void DeferredDeleter::clearQueue(bool hostptrsOnly) {
do {
auto deletion = queue.removeFrontOne();
if (deletion) {
bool isDeletionHostptr = deletion->isExternalHostptr();
if ((!hostptrsOnly || isDeletionHostptr) && deletion->apply()) {
this->elementsToRelease--;
if (isDeletionHostptr) {
this->hostptrsToRelease--;
}
} else {
queue.pushTailOne(*deletion.release());
}
}
} while (hostptrsOnly ? !areElementsReleased(hostptrsOnly) : !queue.peekIsEmpty());
}
} // namespace NEO
|