forked from 0ad/0ad
Resolve Loader memory leak from 1f1642bfe3
.
Use C++11 featured shared_ptr to avoid conditional deletion in multiple locations. Drops C compatibility(?) of Loader.h. Differential Revision: https://code.wildfiregames.com/D2331 Tested on: clang 8.0.1., Jenkins Comments on IRC #wfg 2005-05-07 Refs77d3c5d0b5
,5e3b0f06ec
,f19d8dafee
. This was SVN commit r23019.
This commit is contained in:
parent
218399bf3d
commit
1679510bb8
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -62,18 +62,17 @@ struct LoadRequest
|
||||
// member documentation is in LDR_Register (avoid duplication).
|
||||
|
||||
LoadFunc func;
|
||||
void* param;
|
||||
|
||||
// MemFun_t<T> instance
|
||||
std::shared_ptr<void> param;
|
||||
|
||||
// Translatable string shown to the player.
|
||||
CStrW description;
|
||||
// rationale for storing as CStrW here:
|
||||
// - needs to be WCS because it's user-visible and will be translated.
|
||||
// - don't just store a pointer - the caller's string may be volatile.
|
||||
// - the module interface must work in C, so we get/set as wchar_t*.
|
||||
|
||||
int estimated_duration_ms;
|
||||
|
||||
// LDR_Register gets these as parameters; pack everything together.
|
||||
LoadRequest(LoadFunc func_, void* param_, const wchar_t* desc_, int ms_)
|
||||
LoadRequest(LoadFunc func_, std::shared_ptr<void> param_, const wchar_t* desc_, int ms_)
|
||||
: func(func_), param(param_), description(desc_),
|
||||
estimated_duration_ms(ms_)
|
||||
{
|
||||
@ -109,13 +108,13 @@ void LDR_BeginRegistering()
|
||||
|
||||
// register a task (later processed in FIFO order).
|
||||
// <func>: function that will perform the actual work; see LoadFunc.
|
||||
// <param>: (optional) parameter/persistent state; must be freed by func.
|
||||
// <param>: (optional) parameter/persistent state.
|
||||
// <description>: user-visible description of the current task, e.g.
|
||||
// "Loading Textures".
|
||||
// <estimated_duration_ms>: used to calculate progress, and when checking
|
||||
// whether there is enough of the time budget left to process this task
|
||||
// (reduces timeslice overruns, making the main loop more responsive).
|
||||
void LDR_Register(LoadFunc func, void* param, const wchar_t* description,
|
||||
void LDR_Register(LoadFunc func, std::shared_ptr<void> param, const wchar_t* description,
|
||||
int estimated_duration_ms)
|
||||
{
|
||||
ENSURE(state == REGISTERING); // must be called between LDR_(Begin|End)Register
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -116,17 +116,17 @@ extern void LDR_BeginRegistering();
|
||||
// != 0, or it's treated as "finished")
|
||||
// - on failure, return a negative error code or 'warning' (see above);
|
||||
// LDR_ProgressiveLoad will abort immediately and return that.
|
||||
typedef int (*LoadFunc)(void* param, double time_left);
|
||||
typedef int (*LoadFunc)(std::shared_ptr<void> param, double time_left);
|
||||
|
||||
// register a task (later processed in FIFO order).
|
||||
// <func>: function that will perform the actual work; see LoadFunc.
|
||||
// <param>: (optional) parameter/persistent state; must be freed by func.
|
||||
// <param>: (optional) parameter/persistent state.
|
||||
// <description>: user-visible description of the current task, e.g.
|
||||
// "Loading Textures".
|
||||
// <estimated_duration_ms>: used to calculate progress, and when checking
|
||||
// whether there is enough of the time budget left to process this task
|
||||
// (reduces timeslice overruns, making the main loop more responsive).
|
||||
extern void LDR_Register(LoadFunc func, void* param, const wchar_t* description,
|
||||
extern void LDR_Register(LoadFunc func, std::shared_ptr<void> param, const wchar_t* description,
|
||||
int estimated_duration_ms);
|
||||
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -18,15 +18,6 @@
|
||||
#ifndef INCLUDED_LOADERTHUNKS
|
||||
#define INCLUDED_LOADERTHUNKS
|
||||
|
||||
// rationale for allocating MemFun_t dynamically:
|
||||
// need to store class pointer, function, and argument for each registered
|
||||
// function; single static storage isn't possible. we don't want to break
|
||||
// C compat in the Loader.h interface, so we can't have it take care of this.
|
||||
// that leaves dynamic alloc or reserving some static storage freed when
|
||||
// load registration begins. the former is slower and requires checking
|
||||
// the thunked function's return value (because we mustn't free MemFun_t
|
||||
// if the function times out), but is simpler.
|
||||
|
||||
// VC7 warns if T::*func is not aligned to its size (4..16 bytes on IA-32).
|
||||
// this is a bug, since sizeof(void*) would be enough. MS says it won't
|
||||
// be fixed: see http://www.dotnet247.com/247reference/msgs/1/7782.aspx
|
||||
@ -54,21 +45,16 @@ public:
|
||||
: this_(this__), func(func_) {}
|
||||
};
|
||||
|
||||
template<class T> static int MemFunThunk(void* param, double UNUSED(time_left))
|
||||
template<class T> static int MemFunThunk(std::shared_ptr<void> param, double UNUSED(time_left))
|
||||
{
|
||||
MemFun_t<T>* const mf = (MemFun_t<T>*)param;
|
||||
int ret = (mf->this_->*mf->func)();
|
||||
|
||||
if(!ldr_was_interrupted(ret))
|
||||
delete mf;
|
||||
return ret;
|
||||
MemFun_t<T>* const mf = static_cast<MemFun_t<T>*>(param.get());
|
||||
return (mf->this_->*mf->func)();
|
||||
}
|
||||
|
||||
template<class T> void RegMemFun(T* this_, int(T::*func)(void),
|
||||
const wchar_t* description, int estimated_duration_ms)
|
||||
{
|
||||
void* param = new MemFun_t<T>(this_, func);
|
||||
LDR_Register(MemFunThunk<T>, param, description, estimated_duration_ms);
|
||||
LDR_Register(MemFunThunk<T>, std::make_shared<MemFun_t<T>>(this_, func), description, estimated_duration_ms);
|
||||
}
|
||||
|
||||
|
||||
@ -86,20 +72,16 @@ public:
|
||||
: this_(this__), func(func_), arg(arg_) {}
|
||||
};
|
||||
|
||||
template<class T, class Arg> static int MemFun1Thunk(void* param, double UNUSED(time_left))
|
||||
template<class T, class Arg> static int MemFun1Thunk(shared_ptr<void> param, double UNUSED(time_left))
|
||||
{
|
||||
MemFun1_t<T, Arg>* const mf = (MemFun1_t<T, Arg>*)param;
|
||||
int ret = (mf->this_->*mf->func)(mf->arg);
|
||||
if(!ldr_was_interrupted(ret))
|
||||
delete mf;
|
||||
return ret;
|
||||
MemFun1_t<T, Arg>* const mf = static_cast<MemFun1_t<T, Arg>*>(param.get());
|
||||
return (mf->this_->*mf->func)(mf->arg);
|
||||
}
|
||||
|
||||
template<class T, class Arg> void RegMemFun1(T* this_, int(T::*func)(Arg), Arg arg,
|
||||
const wchar_t* description, int estimated_duration_ms)
|
||||
{
|
||||
void* param = new MemFun1_t<T, Arg>(this_, func, arg);
|
||||
LDR_Register(MemFun1Thunk<T, Arg>, param, description, estimated_duration_ms);
|
||||
LDR_Register(MemFun1Thunk<T, Arg>, std::make_shared<MemFun1_t<T, Arg> >(this_, func, arg), description, estimated_duration_ms);
|
||||
}
|
||||
|
||||
#endif // INCLUDED_LOADERTHUNKS
|
||||
|
Loading…
Reference in New Issue
Block a user