I'm starting to learn Vulkan, and want to know if VkCreate[...] functions copy the resources pointed in structs into his own buffers.
To clarify my question, in this code I load a SPIR shader into my own mkShader struct and then I create the shadermodule with vkCreateShaderModule.
static VkShaderModule mkVulkanCreateShaderModule(MkVulkanContext *vc,
const char *filename)
{
VkShaderModule shaderModule;
struct mkShader *shader = mkVulkanLoadShaderBinary(filename);
VkShaderModuleCreateInfo createInfo = {0};
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
createInfo.codeSize = shader->size;
createInfo.pCode = (uint32_t *)shader->buffer;
if (vkCreateShaderModule(vc->device, &createInfo, NULL,
&shaderModule) != VK_SUCCESS) {
printf(ANSI_COLOR_RED
"Failed to create shader module\n" ANSI_COLOR_RESET);
assert(0);
exit(EXIT_FAILURE);
}
mkVulkanFreeShaderBinary(shader);
return shaderModule;
}
As you can see I'm freeing the mkShader struct with mkVulkanFreeShaderBinaryafter shader module creation and I'm not receiving any error from my program. So my question is if this is safe to do, or I have to keep the mkShader struct until I destroy the shader module. And also, if this is valid to all VkCreate[...] functions or not, and if this information is anywhere in the Vulkan spec.
See Object Lifetime of the Vulkan specification.
The ownership of application-owned memory is immediately acquired by any Vulkan command it is passed into. Ownership of such memory must be released back to the application at the end of the duration of the command, so that the application can alter or free this memory as soon as all the commands that acquired it have returned.
In other words, anything you allocate you are free to delete as soon as a Vulkan function call returns. Additionally, once you've created your pipeline, you're free to destroy the VkShaderModule too.
Related
In C when I return a pointer of a stack-created variable from a function, the memory discards after the function is returned, thus making the pointer impossible to dereference. But in Go, the compiler is not giving me any errors. Does that mean that this is safe to do?
package main
import (
"fmt"
)
func main() {
fmt.Println(*(something()))
}
func something() *string {
s := "a"
return &s
}
Yes, this is safe and a normal pattern in Go programming. Go uses escape analysis to move any values with pointers that escape the stack to the heap automatically. You don't need to be concerned with where values are allocated.
From the Go FAQ: "How do I know whether a variable is allocated on the heap or the stack?"
if the compiler cannot prove that the variable is not referenced after the function returns, then the compiler must allocate the variable on the garbage-collected heap to avoid dangling pointer errors
You can see these optimization choices during compilation by using the -gcflags -m option.
Yes, in Golang it is fine to return a pointer to a local variable. Golang will manage the objects lifetime for you and free it when all pointers to it are gone.
In another answer I point out all the differences between C/C++ pointers and Golang pointers: What is the meaning of '*' and '&' in Golang?
Why C++ hasn't placement delete that directly corresponds to the placement new, i.e. calls the destructor and calls appropriate placement delete operator?
For example:
MyType *p = new(arena) MyType;
...
//current technique
p->~MyType();
operator delete(p, arena);
//proposed technique
delete(arena) p;
operator delete is unique in being a non-member or static member function that is dynamically dispatched. A type with a virtual destructor performs the call to its own delete from the most derived destructor.
struct abc {
virtual ~abc() = 0;
};
struct d : abc {
operator delete() { std::cout << "goodbye\n"; }
};
int main() {
abc *p = new d;
delete p;
}
(Run this example.)
For this to work with placement delete, the destructor would have to somehow pass the additional arguments to operator delete.
Solution 1: Pass the arguments through the virtual function. This requires a separate virtual destructor for every static member and global operator delete overload with different arguments.
Solution 2: Let the virtual destructor return a function pointer to the caller specifying what operator delete should be called. But if the destructor does lookup, this hits the same problem of requiring multiple virtual function definitions as #1. Some kind of abstract overload set would have to be created, which the caller would resolve.
You have a perfectly good point, and it would be a nice addition to the language. Retrofitting it into the existing semantics of delete is probably even possible, in theory. But most of the time we don't use the full functionality of delete and it suffices to use a pseudo-destructor call followed by something like arena.release(p).
Probably because there was syntax for explicitly calling a destructor without deallocation (exactly as in your question), but no syntax for explicit construction in raw memory?
Actually there is a placement delete which is called by the implementation for an object that was "allocated" using placement new if the constructor threw an exception.
From Wikipedia.
The placement delete functions are called from placement new expressions. In particular, they are called if the constructor of the object throws an exception. In such a circumstance, in order to ensure that the program does not incur a memory leak, the placement delete functions are called.
The whole point of placement new is to separate object creation from its memory management. So it makes no sense to tie it back during object destruction.
If memory for your objects is from heap and you want same lifetime for objects and their memory just use operator new and operator delete, maybe overriding them if you want any special behavior.
Placement new is good for example in vector, which keeps a large chunk of raw memory and creates and destroys object inside of it, but without releasing memory.
When using MySQL in C you free the memory using the MySQL API, like so:
MYSQL* connection = NULL;
connection = mysql_init(NULL);
// Stuff...
mysql_close(connection);
But Splint doesn't know that mysql_close is in fact freeing memory, so I get this error:
Fresh storage connection not released before return
A memory leak has been detected. Storage allocated locally is
not released before the last reference to it is lost. (Use
-mustfreefresh to inhibit warning)
How do I tell Splint that mysql_close is deallocating memory? A special annotation to the mysql.h file?
EDIT: OK, maybe the releases *p annotation, if that can be used in a header file. Will try.
EDIT 2: Added /*#releases *sock#*/ to mysql.h, but now get this error:
Releases clauses includes *sock of non-dynamically allocated
type MYSQL
A declaration uses an invalid annotation. (Use -annotationerror to inhibit
warning)
This is the signaure of mysql_close:
void STDCALL mysql_close(/*#notnull#*/ MYSQL *sock) /*#releases *sock#*/;
I believe that proper annotation would be:
void STDCALL mysql_close(/*#special#*/ /*#notnull#*/ MYSQL *sock)
/*#releases sock#*/;
The key, that you have missed is /*#special#*/ annotation, that is required to "activate" so called state clauses. From Splint's documentation, 7.4 State Clauses:
The /*#special#*/ annotation is used to mark a parameter, global
variable, or return value that is described using state clauses.
I'm having trouble getting MmFile to work in a directory scanning algorithm.
When I'm stress-testing it as follows
foreach (dent; dirEntries(..)) {
const size_t K = ...;
const ulong size = ...;
scope auto mf = new MmFile(dent.name, MmFile.Mode.read, size, null, win)
}
I can't find a combination of size and win that works for all cases when reading data.
When I set
const size = 0;
const win = 64*1024;
the length gets calculated correctly.
But when dent.name is an existing empty file it crashes in the destruction of the MMFile throwing a
core.exception.FinalizeError...std.exception.ErrnoException#std.mmfile.d(490): munmap failed (Invalid argument).
And I can't recover this error by catching core.exception.FinalizeError because its thrown in the destructor. I haven't tried
try { delete mm; } catch (core.exception.FinalizeError) { ; /* pass */}
Maybe that works.
Is this the default behavior when calling mmap in C on existing empty files?
If so I think that MmFile should check for this error during construction.
The except gets thrown also when I replace scope with an explicit delete.
For now I simply skip calling MmFile on empty files.
It sounds like a bug to me for MmFile to barf on empty files regardless of what mmap itself does. Please report it.
On a side note, I'd advise against using either scope or delete, as they're going to be removed from the language, because they're both unsafe. std.typecons.scoped replaces scope in this context if you want to do that (though it's still unsafe). And as for delete, destroy will destroy the object without freeing its memory, and core.memory can be used to free memory if you really want to, but in general, if you want to be worrying about freeing memory, then you should be manually managing your memory (with malloc and free and possibly emplace) and not using the GC at all.
I'd like to ask for an advice. I am working with small embedded uP.
I'd like to assign my various functions to myfunctions struct. How to do that correctly?
Then I want to place this myfunctions (struct of function pointers) to specific memory address (e.g. 0x1000). Whats is the best procedure to achieve this?
typedef void (*fptr)(void);
typedef struct FCN_IMAGE
{
fptr fcn1;
fptr fcn2;
fptr fcn3;
} FUNC_T;
FUNC_T myfunctions;
Actually it should be sort of jump table.
Secondly I want to read this function pointers from within other program - directly from specified address location (e.g. 0x1000).
It means the first code should assign the struct of function pointers to specific memory location and other independent code should read this table from specific memory. Interconnection between those two programs should be
#define FCN_BASE_ADDRESS (0x1000)
Any ideas what is the best way to achieve it?
P.S. This will run on embedded processor - not PC.
Locating objects at specific locations is usually most easily performed by the use of compiler specific extension; there is no standard method defined by the language. It may also be possible to locate a global object at a specific location by modifying the linker script, but that will be specific to your particular tool-chain
What compiler/tool-chain are you using? Refer to its documentation.
Maybe the following will help you:
// assign my various functions to myfunctions struct
myfunctions.fcn1 = &YourFunction1;
myfunctions.fcn2 = &YourFunction2;
myfunctions.fcn3 = &YourFunction3;
// assign the struct of function pointers to specific memory location
memcpy((void*)FCN_BASE_ADDRESS, &myfunctions, sizeof(myfunctions));
// read this table from specific memory
memcpy(&myfunctions, (void*)FCN_BASE_ADDRESS, sizeof(myfunctions));
This is based on my guess on what you actually want to do.
This is the best way to solve it in a portable manner:
typedef void (*fptr)(void);
#define FCN_BASE_ADDRESS ((volatile fptr*)0x1000)
/* Make myfunctions an array, not a struct.
Structs can have padding and aren't portable.
It doesn't look like you need a struct in this case.
*/
fptr myfunctions [N] =
{
fptr fcn1;
fptr fcn2;
fptr fcn3;
};
memcpy(&FCN_BASE_ADDRESS, myfunctions, sizeof(myfunctions));
Though if you are using Codewarrior, you could probably use a #pragma to allocate them where you want them. Here is an example assuming they are stored in read/write RAM and a 32-bit address bus.
// .prm file
SECTIONS
MEM_FCN_BASE_ADDRESS = READ_WRITE 0x2000 TO 0x200C;
END
PLACEMENT
FCN_BASE_ADDRESS INTO MEM_FCN_BASE_ADDRESS;
END
// .c file
#pragma DATA_SEG FCN_BASE_ADDRESS
fptr myfunctions[N] = ...;
#pragma DATA_SEG DEFAULT
If they should be stored in ROM/flash, for example a vector table, then it must be done differently with READ_ONLY sections, #pragma CONST_SEG and const fptr. (Note that the const keyword in C behaves in irrational ways when combined with typedef:ed pointers. In this case I believe it would give a constant pointer to a non-constant function and thus it should end up in NVM as desired.)