-
Notifications
You must be signed in to change notification settings - Fork 2
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
Can Julia free unmanaged memory allocated in a native DLL? #10
Comments
Yes, we could simply call The approach that I would recommend is to implement malloc/free pairing within the char *plc_tag_get_string(int32_t tag_id, int string_start_offset) {
static size_t len = 0;
static char *buf = NULL;
size_t nameLen = length_of_tag_name(tag_id, string_start_offset);
if (!buf || nameLen > len) {
if (buf)
free(buf);
len = nameLen;
buf = malloc(len*sizeof(*buf));
}
// fill buf with the string contents
return buf;
} or if implementing in C++ namespace "C" char *plc_tag_get_string(int32_t tag_id, int string_start_offset) {
static std::string result;
result = get_tag_name(tag_id, string_start_offset);
return result.c_str();
} The buffer will be valid for the calling code to use until the next time |
Hi Keith, Hmm, that is an interesting idea. It also turns out that in C#/.Net this is difficult to do as well. I think the above idea may not work because tags are explicitly usable between threads and I think this would cause problems. Perhaps there is a trick I can use with thread locals to make this more thread safe? I will rethink the API. As you note, generally the cleanest way to do this is to have memory managed completely on one side or the other. Something like: int plc_tag_get_string_length(int32_t tag_id, int string_start_offset);
int plc_tag_get_string(int32_t tag_id, int string_start_offset, char *buffer, int buffer_size);
int plc_tag_set_string(int32_t tag_id, int string_start_offset, const char *string_val);
int plc_tag_get_string_capacity(int32_t tag_id, int string_start_offset);
int plc_tag_get_string_total_length(int32_t tag_id, int string_start_offset); It is only one more function, where you call it to get the string length. Then you pass a buffer in which to copy the string along with a size. Or I could have you just call the capacity function to get the maximum capacity of the string (i.e. 82 on most AB PLCs). You allocate that and then you get the length as the result of What is most ergonomic for you? |
Or... Perhaps put all the memory handling in the wrapper? int plc_tag_get_string(int32_t tag_id, int string_start_offset, char *buffer, int buffer_size);
int plc_tag_set_string(int32_t tag_id, int string_start_offset, const char *string_val);
int plc_tag_get_string_capacity(int32_t tag_id, int string_start_offset);
int plc_tag_get_string_total_length(int32_t tag_id, int string_start_offset); First you call plc_tag_get_string_capacity() to get the maximum capacity. Then you create a byte buffer sufficiently large to handle that. Then you call plc_tag_get_string() with that buffer. You get back a value that is the length of the string, or a negative number that is an error (i.e. PLCTAG_ERR_TOO_SMALL if there is insufficient space). This is most consistent because you need to do a similar thing when you want to write a string. Would that work for you? |
Yes, this is precisely the kind of API I was thinking when I said:
And it will work fine for the Julia wrapper! |
I will aim for something close the last API proposed above. Might take a while as I am still fighting Java and Android and have very, very little time due to work right now. Sorry for the delays! |
Sorry guys, dumb question: I am really close to figuring out how to dispose of C-style string data allocated in the native DLL for Java and I have been poking around a bit but my Google fu is weak today; can Julia do this too?
The reason I am asking is that I think I can make a C string API that is much, much easier to use than what I came up with before. But it requires that I return a newly allocated C string. Here is what the new string API would look like:
It is that first function that is the problem child. I have to allocate memory in order for this to really be easy to use. But then the caller needs to free it. I am about 99% certain that I have figured out how to do this in Java, I want to make sure that it can be done in Julia.
From what I can see of Julia's FFI, it looks like you just call free more or less directly once the string is converted to a Julia string.
The text was updated successfully, but these errors were encountered: