Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

attempt to fix some memory leaks #119

Merged
merged 1 commit into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dll/dll/local_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class Local_Storage {
unsigned int data_settings_size(std::string file);
int get_data_settings(std::string file, char *data, unsigned int max_length);
int count_files(std::string folder);
bool iterate_file(std::string folder, int index, char *output_filename, int32 *output_size);
bool iterate_file(std::string folder, int index, std::string &output_filename, int32 *output_size);
bool file_exists(std::string folder, std::string file);
unsigned int file_size(std::string folder, std::string file);
bool file_delete(std::string folder, std::string file);
Expand Down
3 changes: 3 additions & 0 deletions dll/dll/steam_matchmaking_servers.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#define __INCLUDED_STEAM_MATCHMAKING_SERVERS_H__

#include "base.h"
#include "common_helpers/forgettable_memory.hpp"
#include <ssq/a2s.h>

struct Steam_Matchmaking_Servers_Direct_IP_Request {
Expand Down Expand Up @@ -68,6 +69,8 @@ public ISteamMatchmakingServers
std::vector <struct Steam_Matchmaking_Request> requests{};
std::vector <struct Steam_Matchmaking_Servers_Direct_IP_Request> direct_ip_requests{};

common_helpers::ForgettableMemory<gameserveritem_t> requests_from_GetServerDetails{};

HServerListRequest RequestServerList(AppId_t iApp, ISteamMatchmakingServerListResponse *pRequestServersResponse, EMatchMakingType type);
void RequestOldServerList(AppId_t iApp, ISteamMatchmakingServerListResponse001 *pRequestServersResponse, EMatchMakingType type);

Expand Down
11 changes: 10 additions & 1 deletion dll/dll/steam_remote_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "base.h"
#include "ugc_remote_storage_bridge.h"
#include "common_helpers/forgettable_memory.hpp"

struct Async_Read {
SteamAPICall_t api_call{};
Expand Down Expand Up @@ -86,6 +87,7 @@ public ISteamRemoteStorage
class Local_Storage *local_storage{};
class SteamCallResults *callback_results{};
class SteamCallBacks *callbacks{};
class RunEveryRunCB *run_every_runcb{};

std::vector<struct Async_Read> async_reads{};
std::vector<struct Stream_Write> stream_writes{};
Expand All @@ -94,9 +96,16 @@ public ISteamRemoteStorage

bool steam_cloud_enabled = true;

common_helpers::ForgettableMemory<std::string> requests_GetFileNameAndSize{};
common_helpers::ForgettableMemory<std::string> requests_GetUGCDetails{};

static void steam_run_every_runcb(void *object);
void RunCallbacks();

public:

Steam_Remote_Storage(class Settings *settings, class Ugc_Remote_Storage_Bridge *ugc_bridge, class Local_Storage *local_storage, class SteamCallResults *callback_results, class SteamCallBacks *callbacks);
Steam_Remote_Storage(class Settings *settings, class Ugc_Remote_Storage_Bridge *ugc_bridge, class Local_Storage *local_storage, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb);
~Steam_Remote_Storage();

// NOTE
//
Expand Down
11 changes: 8 additions & 3 deletions dll/local_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ uint64_t Local_Storage::file_timestamp(std::string folder, std::string file)
return 0;
}

bool Local_Storage::iterate_file(std::string folder, int index, char *output_filename, int32 *output_size)
bool Local_Storage::iterate_file(std::string folder, int index, std::string &output_filename, int32 *output_size)
{
return false;
}
Expand Down Expand Up @@ -766,8 +766,11 @@ uint64_t Local_Storage::file_timestamp(std::string folder, std::string file)
return buffer.st_mtime;
}

bool Local_Storage::iterate_file(std::string folder, int index, char *output_filename, int32 *output_size)
bool Local_Storage::iterate_file(std::string folder, int index, std::string &output_filename, int32 *output_size)
{
output_filename.clear();
if (output_size) *output_size = 0;

if (folder.size() && folder.back() != *PATH_SEPARATOR) {
folder.append(PATH_SEPARATOR);
}
Expand All @@ -777,10 +780,12 @@ bool Local_Storage::iterate_file(std::string folder, int index, char *output_fil

std::string name(desanitize_file_name(files[index].name));
if (output_size) *output_size = file_size(folder, name);

#if defined(STEAM_WIN32)
name = replace_with(name, PATH_SEPARATOR, "/");
#endif
strcpy(output_filename, name.c_str());

output_filename = std::move(name);
return true;
}

Expand Down
2 changes: 1 addition & 1 deletion dll/steam_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ Steam_Client::Steam_Client()
steam_user_stats = new Steam_User_Stats(settings_client, network, local_storage, callback_results_client, callbacks_client, run_every_runcb, steam_overlay);
steam_apps = new Steam_Apps(settings_client, callback_results_client, callbacks_client);
steam_networking = new Steam_Networking(settings_client, network, callbacks_client, run_every_runcb);
steam_remote_storage = new Steam_Remote_Storage(settings_client, ugc_bridge, local_storage, callback_results_client, callbacks_client);
steam_remote_storage = new Steam_Remote_Storage(settings_client, ugc_bridge, local_storage, callback_results_client, callbacks_client, run_every_runcb);
steam_screenshots = new Steam_Screenshots(local_storage, callbacks_client);
steam_http = new Steam_HTTP(settings_client, network, callback_results_client, callbacks_client);
steam_controller = new Steam_Controller(settings_client, callback_results_client, callbacks_client, run_every_runcb);
Expand Down
8 changes: 5 additions & 3 deletions dll/steam_matchmaking_servers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -395,10 +395,10 @@ gameserveritem_t *Steam_Matchmaking_Servers::GetServerDetails( HServerListReques
}

Gameserver *gs = &gameservers_filtered[iServer].server;
gameserveritem_t *server = new gameserveritem_t(); //TODO: is the new here ok?
server_details(gs, server);
auto &server = requests_from_GetServerDetails.create(std::chrono::hours(1));
server_details(gs, &server);
PRINT_DEBUG(" Returned server details");
return server;
return &server;
}


Expand Down Expand Up @@ -910,6 +910,8 @@ void Steam_Matchmaking_Servers::RunCallbacks()
if (r.players_response) r.players_response->PlayersRefreshComplete();
if (r.ping_response) r.ping_response->ServerFailedToRespond();
}

requests_from_GetServerDetails.cleanup();
}

void Steam_Matchmaking_Servers::Callback(Common_Message *msg)
Expand Down
48 changes: 36 additions & 12 deletions dll/steam_remote_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,35 @@ static void copy_file(const std::string &src_filepath, const std::string &dst_fi

const auto dst_p(std::filesystem::u8path(dst_filepath));
std::filesystem::create_directories(dst_p.parent_path()); // make the folder tree if needed
std::filesystem::copy_file(src_p, dst_p, std::filesystem::copy_options::overwrite_existing);
std::filesystem::copy_file(src_p, dst_p, std::filesystem::copy_options::overwrite_existing | std::filesystem::copy_options::copy_symlinks);
} catch(...) {}
}

Steam_Remote_Storage::Steam_Remote_Storage(class Settings *settings, class Ugc_Remote_Storage_Bridge *ugc_bridge, class Local_Storage *local_storage, class SteamCallResults *callback_results, class SteamCallBacks *callbacks)

void Steam_Remote_Storage::steam_run_every_runcb(void *object)
{
// PRINT_DEBUG_ENTRY();

auto inst = reinterpret_cast<Steam_Remote_Storage *>(object);
inst->RunCallbacks();
}

Steam_Remote_Storage::Steam_Remote_Storage(class Settings *settings, class Ugc_Remote_Storage_Bridge *ugc_bridge, class Local_Storage *local_storage, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
{
this->settings = settings;
this->ugc_bridge = ugc_bridge;
this->local_storage = local_storage;
this->callback_results = callback_results;
this->callbacks = callbacks;
this->run_every_runcb = run_every_runcb;

steam_cloud_enabled = true;
this->run_every_runcb->add(&Steam_Remote_Storage::steam_run_every_runcb, this);
}

Steam_Remote_Storage::~Steam_Remote_Storage()
{
this->run_every_runcb->remove(&Steam_Remote_Storage::steam_run_every_runcb, this);
}

// NOTE
Expand Down Expand Up @@ -329,16 +345,17 @@ int32 Steam_Remote_Storage::GetFileCount()

const char* Steam_Remote_Storage::GetFileNameAndSize( int iFile, int32 *pnFileSizeInBytes )
{
PRINT_DEBUG("%i", iFile);
PRINT_DEBUG("%i %p", iFile, pnFileSizeInBytes);
std::lock_guard<std::recursive_mutex> lock(global_mutex);

static char output_filename[MAX_FILENAME_LENGTH];
std::string output_filename{};
if (local_storage->iterate_file(Local_Storage::remote_storage_folder, iFile, output_filename, pnFileSizeInBytes)) {
PRINT_DEBUG("|%s|, size: %i", output_filename, pnFileSizeInBytes ? *pnFileSizeInBytes : 0);
return output_filename;
} else {
return "";
auto &request = requests_GetFileNameAndSize.create(std::chrono::minutes(15), std::move(output_filename));
PRINT_DEBUG("file '%s', size: %i", request.c_str(), pnFileSizeInBytes ? *pnFileSizeInBytes : 0);
return request.c_str();
}

return "";
}


Expand Down Expand Up @@ -504,17 +521,17 @@ bool Steam_Remote_Storage::GetUGCDetails( UGCHandle_t hContent, AppId_t *pnAppID
if (ppchName) *ppchName = nullptr;

if (auto query_res = ugc_bridge->get_ugc_query_result(hContent)) {
auto mod = settings->getMod(query_res.value().mod_id);
auto &mod_name = query_res.value().is_primary_file
const auto mod = settings->getMod(query_res.value().mod_id);
const auto &mod_name = query_res.value().is_primary_file
? mod.primaryFileName
: mod.previewFileName;
int32 mod_size = query_res.value().is_primary_file
? mod.primaryFileSize
: mod.previewFileSize;

if (ppchName) {
*ppchName = new char[mod_name.size() + 1];
std::strcpy(*ppchName, mod_name.c_str());
auto &new_str = requests_GetUGCDetails.create(std::chrono::minutes(30), mod_name); // this will make a copy of mod_name
*ppchName = const_cast<char *>(new_str.c_str());
}
if (pnFileSizeInBytes) *pnFileSizeInBytes = mod_size;
if (pSteamIDOwner) *pSteamIDOwner = mod.steamIDOwner;
Expand Down Expand Up @@ -1238,3 +1255,10 @@ bool Steam_Remote_Storage::EndFileWriteBatch()
return true;
}



void Steam_Remote_Storage::RunCallbacks()
{
requests_GetFileNameAndSize.cleanup();
requests_GetUGCDetails.cleanup();
}
72 changes: 72 additions & 0 deletions helpers/common_helpers/forgettable_memory.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#pragma once

#include <chrono>
#include <mutex>
#include <forward_list>
#include <utility>
#include <algorithm>


namespace common_helpers
{
template<typename Ty>
class ForgettableMemory {
struct ForgettableBlock {
Ty block;
std::chrono::high_resolution_clock::time_point due_time;

template<typename Rep, typename Period, class... Args>
ForgettableBlock(std::chrono::duration<Rep, Period> duration, Args&&... args)
: due_time(std::chrono::high_resolution_clock::now() + duration),
block( std::forward<Args>(args)... )
{ }
};

std::recursive_mutex mtx{};
std::forward_list<ForgettableBlock> storage{};


public:
template<typename Rep, typename Period, class... Args>
Ty& create(std::chrono::duration<Rep, Period> duration, Args&&... args) {
std::lock_guard lock(mtx);

auto& new_ele = storage.emplace_front(duration, std::forward<Args>(args)...);
return new_ele.block;
}

bool is_alive(const Ty& block) {
std::lock_guard lock(mtx);

auto ele_it = std::find_if(storage.begin(), storage.end(), [&block](const ForgettableBlock &item){
return &item.block == &block;
});
return storage.end() != ele_it;
}

void destroy(const Ty& block) {
std::lock_guard lock(mtx);

storage.remove_if([&block](const ForgettableBlock &item){
return &item.block == &block;
});
}

void destroy_all() {
std::lock_guard lock(mtx);

storage.clear();
}

void cleanup() {
std::lock_guard lock(mtx);

const auto now = std::chrono::high_resolution_clock::now();
storage.remove_if([&now](const ForgettableBlock &item){
return now > item.due_time;
});

}

};
}