2017-12-21 07:45:38 +08:00
|
|
|
/*
|
2025-04-09 22:39:29 +08:00
|
|
|
* Copyright (C) 2018-2025 Intel Corporation
|
2018-09-18 15:11:08 +08:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: MIT
|
|
|
|
*
|
|
|
|
*/
|
2017-12-21 07:45:38 +08:00
|
|
|
|
2020-02-24 05:44:01 +08:00
|
|
|
#include "shared/source/memory_manager/deferred_deleter.h"
|
2019-02-27 18:39:32 +08:00
|
|
|
|
2020-02-24 05:44:01 +08:00
|
|
|
#include "shared/source/memory_manager/deferrable_deletion.h"
|
|
|
|
#include "shared/source/os_interface/os_thread.h"
|
2017-12-21 07:45:38 +08:00
|
|
|
|
2019-03-26 18:59:46 +08:00
|
|
|
namespace NEO {
|
2024-10-08 20:20:29 +08:00
|
|
|
DeferredDeleter::DeferredDeleter() = default;
|
2017-12-21 07:45:38 +08:00
|
|
|
|
|
|
|
void DeferredDeleter::stop() {
|
2018-03-19 18:54:50 +08:00
|
|
|
// 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
|
2017-12-21 07:45:38 +08:00
|
|
|
doWorkInBackground = false;
|
2018-03-19 18:54:50 +08:00
|
|
|
lock.unlock();
|
2017-12-21 07:45:38 +08:00
|
|
|
condition.notify_one();
|
2025-04-17 03:33:13 +08:00
|
|
|
worker->detach();
|
|
|
|
// Wait for the working job to exit main loop
|
|
|
|
while (!exitedMainLoop) {
|
|
|
|
std::this_thread::yield();
|
|
|
|
}
|
2018-03-19 18:54:50 +08:00
|
|
|
// Delete working thread
|
2018-05-22 23:23:39 +08:00
|
|
|
worker.reset();
|
2017-12-21 07:45:38 +08:00
|
|
|
}
|
2024-10-08 20:20:29 +08:00
|
|
|
drain(false, false);
|
2017-12-21 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
2018-03-19 18:54:50 +08:00
|
|
|
void DeferredDeleter::safeStop() {
|
|
|
|
std::lock_guard<std::mutex> lock(threadMutex);
|
2017-12-21 07:45:38 +08:00
|
|
|
stop();
|
|
|
|
}
|
|
|
|
|
2018-03-19 18:54:50 +08:00
|
|
|
DeferredDeleter::~DeferredDeleter() {
|
|
|
|
safeStop();
|
|
|
|
}
|
|
|
|
|
2017-12-21 07:45:38 +08:00
|
|
|
void DeferredDeleter::deferDeletion(DeferrableDeletion *deletion) {
|
|
|
|
std::unique_lock<std::mutex> lock(queueMutex);
|
2024-10-08 20:20:29 +08:00
|
|
|
|
|
|
|
this->elementsToRelease++;
|
|
|
|
if (deletion->isExternalHostptr()) {
|
|
|
|
this->hostptrsToRelease++;
|
|
|
|
}
|
|
|
|
|
2017-12-21 07:45:38 +08:00
|
|
|
queue.pushTailOne(*deletion);
|
2024-10-08 20:20:29 +08:00
|
|
|
|
2017-12-21 07:45:38 +08:00
|
|
|
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() {
|
2018-03-19 18:54:50 +08:00
|
|
|
if (worker != nullptr) {
|
2017-12-21 07:45:38 +08:00
|
|
|
return;
|
2018-03-19 18:54:50 +08:00
|
|
|
}
|
2025-04-17 03:33:13 +08:00
|
|
|
exitedMainLoop = false;
|
2024-08-21 22:19:13 +08:00
|
|
|
worker = Thread::createFunc(run, reinterpret_cast<void *>(this));
|
2017-12-21 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
2024-10-08 20:20:29 +08:00
|
|
|
bool DeferredDeleter::areElementsReleased(bool hostptrsOnly) {
|
|
|
|
return hostptrsOnly ? this->hostptrsToRelease == 0 : this->elementsToRelease == 0;
|
2017-12-21 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool DeferredDeleter::shouldStop() {
|
|
|
|
return !doWorkInBackground;
|
|
|
|
}
|
|
|
|
|
2018-05-22 23:23:39 +08:00
|
|
|
void *DeferredDeleter::run(void *arg) {
|
|
|
|
auto self = reinterpret_cast<DeferredDeleter *>(arg);
|
2017-12-21 07:45:38 +08:00
|
|
|
std::unique_lock<std::mutex> lock(self->queueMutex);
|
2018-03-19 18:54:50 +08:00
|
|
|
// Mark that working thread really started
|
2017-12-21 07:45:38 +08:00
|
|
|
self->doWorkInBackground = true;
|
|
|
|
do {
|
|
|
|
if (self->queue.peekIsEmpty()) {
|
2018-03-19 18:54:50 +08:00
|
|
|
// Wait for signal that some items are ready to be deleted
|
2017-12-21 07:45:38 +08:00
|
|
|
self->condition.wait(lock);
|
|
|
|
}
|
|
|
|
lock.unlock();
|
2018-03-19 18:54:50 +08:00
|
|
|
// Delete items placed into deferred delete queue
|
2024-10-08 20:20:29 +08:00
|
|
|
self->clearQueue(false);
|
2017-12-21 07:45:38 +08:00
|
|
|
lock.lock();
|
2018-03-19 18:54:50 +08:00
|
|
|
// Check whether working thread should be stopped
|
2017-12-21 07:45:38 +08:00
|
|
|
} while (!self->shouldStop());
|
|
|
|
lock.unlock();
|
2025-05-09 20:43:16 +08:00
|
|
|
self->exitedMainLoop = true;
|
2018-05-22 23:23:39 +08:00
|
|
|
return nullptr;
|
2017-12-21 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
2024-10-08 20:20:29 +08:00
|
|
|
void DeferredDeleter::drain(bool blocking, bool hostptrsOnly) {
|
|
|
|
clearQueue(hostptrsOnly);
|
2017-12-21 07:45:38 +08:00
|
|
|
if (blocking) {
|
2024-10-08 20:20:29 +08:00
|
|
|
while (!areElementsReleased(hostptrsOnly))
|
2017-12-21 07:45:38 +08:00
|
|
|
;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-08 20:20:29 +08:00
|
|
|
void DeferredDeleter::clearQueue(bool hostptrsOnly) {
|
2017-12-21 07:45:38 +08:00
|
|
|
do {
|
2018-11-29 18:20:02 +08:00
|
|
|
auto deletion = queue.removeFrontOne();
|
2017-12-21 07:45:38 +08:00
|
|
|
if (deletion) {
|
2024-10-08 20:20:29 +08:00
|
|
|
bool isDeletionHostptr = deletion->isExternalHostptr();
|
|
|
|
if ((!hostptrsOnly || isDeletionHostptr) && deletion->apply()) {
|
|
|
|
this->elementsToRelease--;
|
|
|
|
if (isDeletionHostptr) {
|
|
|
|
this->hostptrsToRelease--;
|
|
|
|
}
|
2018-11-29 18:20:02 +08:00
|
|
|
} else {
|
2023-03-20 22:34:46 +08:00
|
|
|
queue.pushTailOne(*deletion.release());
|
2018-11-29 18:20:02 +08:00
|
|
|
}
|
2017-12-21 07:45:38 +08:00
|
|
|
}
|
2024-10-08 20:20:29 +08:00
|
|
|
} while (hostptrsOnly ? !areElementsReleased(hostptrsOnly) : !queue.peekIsEmpty());
|
2017-12-21 07:45:38 +08:00
|
|
|
}
|
2019-03-26 18:59:46 +08:00
|
|
|
} // namespace NEO
|