I am trying to bind some functions from glib into Crystal. I've done this and it works:
#[Link("glib-2.0")]
lib LibG
fun g_utf8_strup(str : UInt8*, len : UInt32) : UInt8*
fun g_utf8_strdown(str : UInt8*, len : UInt32) : UInt8*
end
However it introduces memory leak: the objects create with g_* functions will never be garbage collected.
Is it possible to make glib play well with Boehm GC in Crystal? Inspired by PCRE, I've tried this :
#[Link("glib-2.0")]
lib LibG
# These 2 functions work perfectly
fun g_utf8_strup(str : UInt8*, len : UInt32) : UInt8*
fun g_utf8_strdown(str : UInt8*, len : UInt32) : UInt8*
alias Malloc = LibC::SizeT -> Void*
alias Free = Void* ->
$g_malloc : Malloc
$g_free : Free
end
# At this point happens segmentation fault
LibG.g_malloc = ->GC.malloc(LibC::SizeT)
LibG.g_free = ->GC.free(Void*)
In hope to override/redefine g_malloc and g_free functions.
But it does not work out: it fails with segmentation fault.
Any ideas how to make glib play with GC?
I've found somehow related question, but it haven't helped me: Garbage collection with glib?
Thanks in advence.
I would suggest using gobject-introspection for this purpose. It provides a .GIR file for each library which is a large XML file describing the API of each function, class, and method in the library, and how memory is handled for each input and output parameter. You can use it to dynamically generate bindings for libraries such as GLib.
It also provides an extensive unit testing library which you can use to check that your bindings are working correctly.
As for memory management, it seems like asking for trouble to override g_malloc and g_free. The equivalent way it's done in the gobject-introspection bindings for JavaScript is to always make sure that the JS environment owns the memory. For example, for strings being returned from a C function; if ownership of the returned string is given to the caller, then a JS string is created from the returned string (which copies the string) and the returned string is freed. If the library retains ownership of the returned string, then a JS string is created and the returned string is not freed. In both cases, the only memory in use is owned by the JS environment and is subject to JS's garbage collector.
GLib objects are another story, since they are reference-counted, and so the JS wrapper object can simply hold a reference to them; when the JS object is GC'd, it releases its reference and the C object is destroyed as well if no other JS object is holding on to it.
Related
I have a code that's a mixture of standard C++ and cli/c++
And i am trying to create the following object:
std::map<std::string, System::IO::StreamWriter> streamWrite;
But it doesn't work. the compiler actually crushes when i try to build the project.
Is there a way to make it work?
Edit: my code is originally cli c++ and i am slowly converting it to native c++, and that's why i have a mixture of both native and managed objects.
I have no idea yet how to convert StreaReader and StreamWriter objects to native C++ so i am leaving this to the very end, so i n the meantime i have this "strange creature" - std::map that holds a managed object as its value.
Standard C++ things (like std::map) and managed objects do not mix out of the box. It is however possible by using GCHandle to get an intptr_t that represents a managed object and keeps it from getting garbage collected.
intptr_t GetHandle(System::Object^ obj) {
auto gch = System::Runtime::InteropServices::GCHandle::Alloc(obj);
auto ip = System::Runtime::InteropServices::GCHandle::ToIntPtr(gch);
return static_cast<intptr_t>(ip);
}
Now you have an intptr_t that represents a your object and can be freely used with native C++ code. std::map<std::string, intptr_t>
To get your object from the intptr_t:
System::IO::StreamWriter^ ToStreamWriter(intptr_t h) {
auto gch = System::Runtime::InteropServices::GCHandle::FromIntPtr(static_cast<System::IntPtr>(h));
return safe_cast<System::IO::StreamWriter^>(gch.Target);
}
The intptr_t value represents a resource the needs to be freed so it should ideally be kept in an RAII object whose destructor will convert it back to a GCHandle (see above) and Free() that. If you don't do that then the StreamWriter object will never be garbage collected and you have a heap leak.
void FreeHandle(intptr_t h) {
auto gch = System::Runtime::InteropServices::GCHandle::FromIntPtr(static_cast<System::IntPtr>(h));
gch.Free();
}
I made a whole template library to do this kind of stuff so I can use managed objects freely in native code. I like this kind of thing but I don't necessarily recommend it. I've never seen it done by anyone else, but it does work nicely once you build good tools for it.
In Win CE 6.0, class TankObject is defined in a static library, C++ compiler is VS2008; target is ARM4 (/QRarch4).
An instance of class TankObject is constructed by a call of the form
*TankObject myTankObject = new TankObject(parm1, parm2 ...);
Last attribute declared in TankObject definition is an object pointer, and when an assignment is made to same, memory corruption of another dynamically allocated object occurs.
Step into constructor reveals that operator new is called with a size of 0x500. sizeof(TankObject) reveals two different values, depending on the context:
In instantiating context (the application), sizeof(TankObject) and sizeof(*myTankObject) is 0x500.
In context of the object itself (the constructor, or object methods), sizeof(TankObject) and sizeof(*this) is 0x508. The address of last declared attribute is 0x500, relative to object.
The call to new requests and receives 0x500 bytes. The object itself expects and uses 0x508 bytes, which can cause assignments to last attribute to step on other dynamically allocated objects.
Work around is to declare another unused attribute at the end of the object definition, to pad the request to new.
Both contexts include the same .h file, to debug I changed include statement to an explicit path name. I also went through compiler switches, made them identical. So I am puzzled, if any one can shed light, I'm glad, I would like to know a proper solution.
I have a C++ project that is configured to use CLR. The project contains a subclass of CTreeCtrl, i.e. a class provided by Microsoft that I have no control over. Since the public interface of CTreeCtrl heavily uses the type HTREEITEM, it is unavoidable that the subclass also makes use of the type - but since the type is "opaque", the subclass only passes around HTREEITEM references without actually doing anything with the referenced objects.
By "opaque", I mean that HTREEITEM is only visible as a forward-declared type. Here's the declaration that I see in CommCtrl.h:
struct _TREEITEM;
typedef struct _TREEITEM *HTREEITEM;
Unfortunately, in a release build this usage of HTREEITEM generates the following linker warning:
foo.obj : warning LNK4248: unresolved typeref token (01000017) for '_TREEITEM'; image may not run
Here is the MSDN link for the warning. I have searched the net for a solution to get rid of the warning, but have found nothing - only confirmation that over the years other people have encountered this warning in relation to HTREEITEM as well.
Now I have been thinking of a workaround myself. Given that
My class only gets HTREEITEM references from CtreeCtrl and passes them back to CtreeCtrl, without any kind of interpretation or function calls
HTREEITEM is merely a pointer to _TREEITEM
It follows that all that my class ever does is pass around pointers to _TREEITEM. My idea for a workaround therefore is this: Why not define _TREEITEM as an empty struct in my project, like this:
struct _TREEITEM
{
};
Obviously this makes the linker happy since it now sees the complete type. The fact that the struct definition is incorrect is not relevant since my class is only passing around pointers to _TREEITEM, i.e. all that the compiler needs to know is the size of a HTREEITEM.
I have tried this workaround and it seems to work, not only at compile time but at runtime as well. So what do you think of this workaround? Did I overlook something? I certainly won't be offended if you call it an ugly hack :-)
FWIW: I am currently on Visual Studio 2010.
I'm trying to port a new versio of the Isis2 library from .NET on Windows to Mono/Linux. This new code uses MemoryMappedFile objects, and I suddenly am running into issues with the Mono.Posix.Helper library. I believe that my issues would vanish if I could successfully compile and run the following test program:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.MemoryMappedFiles;
namespace foobar
{
class Program
{
static int CAPACITY = 100000;
static void Main(string[] args)
{
MemoryMappedFile mmf = MemoryMappedFile.CreateNew("test", CAPACITY);
MemoryMappedViewAccessor mva = mmf.CreateViewAccessor();
for (int n = 0; n < CAPACITY; n++)
{
byte b = (byte)(n & 0xFF);
mva.Write<byte>(n, ref b);
}
}
}
}
... at present, when I try to compile this on Mono I get a bewildering set of linker errors: it seems unable to find libMonoPosixHelper.so, although my LD_LIBRARY_PATH includes the directory containing that file, and then if I manage to get past that stage, I get "System.NotImplementedException: The requested feature is not implemented." at runtime. Yet I've looked at the Mono implementation of the CreateNew method; it seems fully implemented, and the same is true for the CreateViewAccessor method. Thus I have a sense that something is going badly wrong when linking to the Mono libraries.
Does anyone have experience with MemoryMappedFile objects under Mono? I see quite a few questions about this kind of issue here and on other sites, but all seem to be old threads...
OK, I figured at least part of this out by inspection of the Mono code implementing this API. In fact they implemented CreateNew in a way that departs pretty drastically from the .NET API, causing these methods to behave very differently from what you would expect.
For CreateNew, they actually require that the file name you specify be the name of an existing Linux file of size at least as large as the capacity you specify, and also do some other checks for access permissions (of course), exclusive access (which is at odds with sharing...) and to make sure the capacity you requested is > 0. So if you had the file previously open, or someone else does, this will fail -- in contrast to .NET, where you explicitly use memory-mapped files for sharing.
In contrast, CreateOrOpen appears to be "more or less" correctly implemented; switching to this version seems to solve the problem. To get the effect of CreateNew, do a Delete first, wrapping it in a try/catch to catch IOException if the file doesn't exist. Then use File.WriteAllBytes to create a file with your desired content. Then call CreateOrOpen. Now this sounds dumb, but it works. Obviously you can't guarantee atomicity this way (three operations rather than one), but at least you get the desired functionality.
I can live with these restrictions as it works out, but they may surprise others, and are totally different from the .NET API definition for MemoryMappedFile.
As for my linking issues, as far as I can tell there is a situation in which Mono doesn't use the LD_LIBRARY_PATH you specify correctly and hence can't find the .so file or .dll file you used. I'll post more on this if I can precisely pin down the circumstances -- on this one, I've worked around the issue by statically linking to the library.
I'm having trouble finding out how to run a method in a seperate thread in C++ (using Visual C++ 2008), I've tried a number of ways to do this but none of them so far have been successful.
I'm very new to C++ but a fairly experienced programmer in Java, but have been given a task to fix some bugs in an old C++ application. The program uses an object called 'Mpeg' to control packetising and depackitising an Mpeg file. After setting up an Mpeg object properly, mpeg.Depacketise needs to be called, which then runs the method DepacketiseInputFile().
I've tried to make DepacketiseInputFile() run in a seperate thread by both using _beginthread and the System::Threading::Thread object using
Thread^ th = gcnew Thread(gcnew ThreadStart(DepacketiseInputFile));
however this returns the errors
using &Mpeg::Depacketise gives the error
when using _beginthread the code I tried was
However with this I constantly had trouble getting the arguments correct, with errors like
cropping up.
Is there any simple way to do this that anyone can reccomend? I've spent a few days playing around with this but seem to be getting nowhere :(
Any help would be greatly appreciated.
Cheers.
What kind of type is Mpeg? What kind of method is DepacketiseInputFile?
If it's a regular unmanaged, C++ class, then use _beginthread, but you have to make DepacketiseInputFile a static. It cannot take a member function.
Also, don't call DepacketiseInputFile with DepacketiseInputFile(), pass it in with
&Mpeg::DepacketiseInputFile
You should use the void* you get to pass it to pass in a pointer to the Mpeg object (and then cast it back).
If you want to use ThreadStart, then Mpeg needs to be a managed class.
EDIT: If you want to make DepacketiseInputFile, but it needs to access the object, then you use the void* argument to pass in a pointer.
So in the .h:
void DepacketiseInputFileMember();
static void DepacketiseInputFile(void *thisObj);
Your code goes in DepacketiseInputFileMember(), and write DepacketiseInputFile like this:
void Mpeg::DepacketiseInputFile(void *thisObj)
{
Mpeg* mpeg = reinterpret_cast<Mpeg*>(thisObj);
mpeg->DepacketiseInputFileMember();
}
When you call _beginthread, use this
_beginnthread(&Mpeg::DepacketiseInputFile, (unsigned)0, anMpegObjectPointer);
where anMpegObjectPointer is a pointer to an object of type Mpeg. You have to make sure the lifetime of the object is longer than it would be needed in the thread.
Forgive my syntax, I am writing this in a textarea, not Visual Studio
Change
_beginthread(DepacketiseInputFile(), (unsigned)0, (void *)NULL);
to
_beginthread(DepacketiseInputFile, (unsigned)0, (void *)NULL);
You wanna pass the address of the function to run (DepacketiseInputFile) and not its return value of that function (which is what you get from DepacketiseInputFile()).
I'm assuming DepacketiseInputFile is declared as void DepacketiseInputFile(void*), and is not a non-static member function of some class. Otherwise, the types won't match even when you do remove the brackets.