I am trying to generate a function call using AsmJit to which I pass an char*. This char* is in itself retrieved from another function call. I tried out this:
typedef
const char* getStr();
const char* getStrImpl() {
return "hello pie";
}
void use_str_impl(int id, const char* c_str) {
// do stuff...
}
int main() {
JitRuntime rt;
CodeHolder code;
code.init(rt.getCodeInfo());
X86Compiler c(&code);
auto jitted_func = c.addFunc(FuncSignature0<const char*>(code.getCodeInfo().getCdeclCallConv()));
auto err = c.getLastError();
auto call = c.call((uint64_t) fooFuncImpl, FuncSignature0<intptr_t>());
X86Gpd res(call->getRet().getId());
auto call2 = c.call((uint64_t) send_input, FuncSignature2<void, int, intptr_t>());
err = !call2->setArg(0, Imm(42));
err = !call2->setArg(1, res);
c.ret();
c.endFunc();
err = c.finalize();
if(err) return 0;
size_t size = code.getCodeSize();
VMemMgr vm;
void* p = vm.alloc(size);
if (!p) return 0;
code.relocate(p);
auto fun = (entrypoint*) p;
fun();
}
It turns out this does not generate any instructions for the second parameter or second call to setArg. I also tried to use .newIntPtr and using move instructions to move the result of call into place. But this generated dec and add instructions which made no sense to me and my small experience with assembly. What is the correct way of doing this type of thing?
Btw I am using the AsmJit next branch.
I have done few corrections to your sample with some comments.
Better Usage of JitRuntime:
JitRuntime rt;
size_t size = code.getCodeSize();
VMemMgr vm;
....
void* p = vm.alloc(size);
if (!p) return 0;
code.relocate(p);
auto fun = (entrypoint*) p;
You have used JitRuntime just to setup the parameters for CodeHolder, but then avoided it and allocated the memory for the function yourself. While that's a valid use case it's not what most people do. Using runtime's add() is sufficient in most cases.
Invalid use of CCFuncCall::getRet():
X86Gpd res(call->getRet().getId());
The call node at this point doesn't have any return register assigned so it would return an invalid id. If you need to create a virtual register you always have to call compiler's newSomething(). AsmJit's compiler provides API to check for that case at runtime, if you are unsure:
// Would print 0
printf("%d", (int)c.isVirtRegValid(call->getRet().getId()));
The solution is to create a new virtual register and ASSIGN it to the function's return value. Assigning return value requires an index (like assigning an argument), the reason is that some functions may return multiple values(like 64-bit value in 32-bit mode), using 0 as index is sufficient most of the time.
X86Gp reg = c.newIntPtr("reg");
call->setRet(0, reg);
You can verify getRet() functionality:
X86Gp reg = c.newIntPtr("reg");
assert(call->getRet(0).isNone());
call->setRet(0, reg);
assert(call->getRet(0) == reg);
Fully working example:
#include <stdio.h>
#include <asmjit/asmjit.h>
const char* func_a() {
printf("func_a(): Called\n");
return "hello pie";
}
void func_b(int id, const char* c_str) {
printf("func_b(%d, %s): Called\n", id, c_str);
}
int main() {
using namespace asmjit;
JitRuntime rt;
CodeHolder code;
code.init(rt.getCodeInfo());
X86Compiler c(&code);
X86Gp reg = c.newIntPtr("reg");
// Compilation step...
c.addFunc(FuncSignature0<void>(code.getCodeInfo().getCdeclCallConv()));
auto call_a = c.call((uint64_t)func_a, FuncSignature0<intptr_t>());
call_a->setRet(0, reg);
auto call_b = c.call((uint64_t)func_b, FuncSignature2<void, int, intptr_t>());
call_b->setArg(0, Imm(42));
call_b->setArg(1, reg);
c.ret();
c.endFunc();
// Finalize does the following:
// - allocates virtual registers
// - inserts prolog / epilog
// - assembles to CodeHolder
auto err = c.finalize();
if (err) {
printf("COMPILER FAILED: %s\b", DebugUtils::errorAsString(err));
return 1;
}
typedef void (*EntryPoint)(void);
EntryPoint entry;
// Adds function to the runtime. Should be freed by rt.release().
// Function is valid until the runtime is valid if not released.
err = rt.add(&entry, &code);
if (err) {
printf("RUNTIME FAILED: %s\b", DebugUtils::errorAsString(err));
return 1;
}
entry();
return 0;
}
I am trying to create a function that receives and returns a double. For the call method I used the approach with Mem. At the end I need to save the result in the variable xmm1.
I can't identify the error. The sine function is called correctly. But for the final assembler generation error occurs.
JitRuntime rt;
CodeHolder code;
code.init(rt.codeInfo());
asmjit::x86::Compiler cc(&code);
asmjit::x86::Gp reg = cc.newIntPtr("reg");
asmjit::Zone zonee(1024);
asmjit::ConstPool constPool(&zonee);
asmjit::Label constPoolLabel = cc.newLabel();
// Compilation step...
// c.addFunc(asmjit::FuncSignatureT<void>(code.codeInfo().getCdeclCallConv()));
cc.addFunc(asmjit::FuncSignatureT<void>());
auto call_a = cc.call((uint64_t)func_a, FuncSignatureT<intptr_t>());
call_a->setRet(0, reg);
auto call_b = cc.call((uint64_t)func_b, FuncSignatureT<void, int, intptr_t>());
call_b->setArg(0, Imm(42));
call_b->setArg(1, reg);
auto seno = [&](double value) {
size_t valueOffset;
double seno = static_cast<double_t>(std::sin(value));
cout << " seno " << seno << endl;
constPool.add(&seno, sizeof(double), valueOffset);
return asmjit::x86::ptr(constPoolLabel, valueOffset);
};
asmjit::x86::Mem mem;
double test = 180.5;
auto call_c = cc.call(seno(test), asmjit::FuncSignatureT<double_t>());
call_c->setArg(0, asmjit::Imm(test));
call_c->_setRet(0, mem);
cc.movsd(asmjit::x86::xmm1, mem);
cc.ret();
cc.endFunc();
// Finalize does the following:
// - allocates virtual registers
// - inserts prolog / epilog
// - assembles to CodeHolder
auto err = cc.finalize();
if (err) {
printf("COMPILER FAILED: %s\b", DebugUtils::errorAsString(err));
return;
}
typedef void (*EntryPoint)(void);
EntryPoint entry;
// Adds function to the runtime. Should be freed by rt.release().
// Function is valid until the runtime is valid if not released.
err = rt.add(&entry, &code);
if (err) {
printf("RUNTIME FAILED: %s\b", DebugUtils::errorAsString(err));
return;
}
entry();
return;
perhaps the memory object should relate to some memory address?
Mem mem = qword_ptr ((uint64_t) &test);
Related
Hello nano developers,
I'd like to realize the following proto:
message container {
enum MessageType {
TYPE_UNKNOWN = 0;
evt_resultStatus = 1;
}
required MessageType mt = 1;
optional bytes cmd_evt_transfer = 2;
}
message evt_resultStatus {
required int32 operationMode = 1;
}
...
The dots denote, there are more messages with (multiple) primitive containing datatypes to come. The enum will grow likewise, just wanted to keep it short.
The container gets generated as:
typedef struct _container {
container_MessageType mt;
pb_callback_t cmd_evt_transfer;
} container;
evt_resultStatus is:
typedef struct _evt_resultStatus {
int32_t operationMode;
} evt_resultStatus;
The field cmd_evt_transfer should act as a proxy of subsequent messages like evt_resultStatus holding primitive datatypes.
evt_resultStatus shall be encoded into bytes and be placed into the cmd_evt_transfer field.
Then the container shall get encoded and the encoding result will be used for subsequent transfers.
The background why to do so, is to shorten the proto definition and avoid the oneof thing. Unfortunately syntax version 3 is not fully supported, so we can not make use of any fields.
The first question is: will this approach be possible?
What I've got so far is the encoding including the callback which seems to behave fine. But on the other side, decoding somehow skips the callback. I've read issues here, that this happened also when using oneof and bytes fields.
Can someone please clarify on how to proceed with this?
Sample code so far I got:
bool encode_msg_test(pb_byte_t* buffer, int32_t sval, size_t* sz, char* err) {
evt_resultStatus rs = evt_resultStatus_init_zero;
rs.operationMode = sval;
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
/*encode container*/
container msg = container_init_zero;
msg.mt = container_MessageType_evt_resultStatus;
msg.cmd_evt_transfer.arg = &rs;
msg.cmd_evt_transfer.funcs.encode = encode_cb;
if(! pb_encode(&stream, container_fields, &msg)) {
const char* local_err = PB_GET_ERROR(&stream);
sprintf(err, "pb_encode error: %s", local_err);
return false;
}
*sz = stream.bytes_written;
return true;
}
bool encode_cb(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
evt_resultStatus* rs = (evt_resultStatus*)(*arg);
//with the below in place a stream full error rises
// if (! pb_encode_tag_for_field(stream, field)) {
// return false;
// }
if(! pb_encode(stream, evt_resultStatus_fields, rs)) {
return false;
}
return true;
}
//buffer holds previously encoded data
bool decode_msg_test(pb_byte_t* buffer, int32_t* sval, size_t msg_len, char* err) {
container msg = container_init_zero;
evt_resultStatus res = evt_resultStatus_init_zero;
msg.cmd_evt_transfer.arg = &res;
msg.cmd_evt_transfer.funcs.decode = decode_cb;
pb_istream_t stream = pb_istream_from_buffer(buffer, msg_len);
if(! pb_decode(&stream, container_fields, &msg)) {
const char* local_err = PB_GET_ERROR(&stream);
sprintf(err, "pb_encode error: %s", local_err);
return false;
}
*sval = res.operationMode;
return true;
}
bool decode_cb(pb_istream_t *istream, const pb_field_t *field, void **arg) {
evt_resultStatus * rs = (evt_resultStatus*)(*arg);
if(! pb_decode(istream, evt_resultStatus_fields, rs)) {
return false;
}
return true;
}
I feel, I don't have a proper understanding of the encoding / decoding process.
Is it correct to assume:
the first call of pb_encode (in encode_msg_test) takes care of the mt field
the second call of pb_encode (in encode_cb) handles the cmd_evt_transfer field
If I do:
bool encode_cb(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
evt_resultStatus* rs = (evt_resultStatus*)(*arg);
if (! pb_encode_tag_for_field(stream, field)) {
return false;
}
if(! pb_encode(stream, evt_resultStatus_fields, rs)) {
return false;
}
return true;
}
then I get a stream full error on the call of pb_encode.
Why is that?
Yes, the approach is reasonable. Nanopb callbacks do not care what the actual data read or written by the callback is.
As for why your decode callback is not working, you'll need to post the code you are using for decoding.
(As an aside, Any type does work in nanopb and is covered by this test case. But the type_url included in all Any messages makes them have a quite large overhead.)
I have a script to C++ callback/functor system that can call any "registered" C++ function using strings and/or variants.
//REMOVED ERROR CHECKS AND ERRONEOUS STUFF FOR THIS POST
int LuaGameObject::LuaCallFunction( lua_State *luaState )
{
if ( lua_isuserdata( luaState, 1 ) == 1 )
{
int nArgs = lua_gettop( luaState );
//Get GameObject
OGameObject* pGameObject = static_cast<OGameObject*>(lua_touserdata( luaState, 1 ));
if ( pGameObject )
{
//Get FunctionName
const char* functionNameString = lua_tostring( luaState, 2 );
//Get Args
std::vector<OVariant> args;
for ( int i = 3; i <= nArgs; ++i )
{
OVariant variant;
variant.SetFromLua( luaState, i );
args.push_back( variant );
}
//Call it!
CallGameObjectFunction( luaState, pGameObject, functionNameString, args );
return 1;
}
}
return 0;
}
OVariant LuaGameObject::ExecuteLua()
{
lua_State *lState = luaL_newstate();
luaL_openlibs( lState );
lua_register( lState, "Call", LuaCallFunction );
luaL_loadstring( lState, m_pScript );
//now run it
lua_pcall( lState, 0, 1, 0 );
//process return values
OVariant result;
result.SetFromLua( lState, -1 );
lua_close( lState );
return result;
}
In lua I can do something like this...
local king = Call("EmpireManager","GetKing")
Call("MapCamera","ZoomToActor",king)
However, I am feeling that I can use the __index metamethod to simplify the lua...
local king = EmpireManager:GetKing()
MapCamera:ZoomToActor(king)
I was hoping to achieve the simplified lua by using the following implemenation of the __index metamethod
Here is how I register the __index metafunction... (mostly copied from online examples)
void LuaGameObject::Register( lua_State * l )
{
luaL_Reg sRegs[] =
{
{ "__index", &LuaGameObject::LuaCallFunction },
{ NULL, NULL }
};
luaL_newmetatable( l, "luaL_EmpireManager" );
// Register the C functions into the metatable we just created.
luaL_setfuncs( l, sRegs, 0 );
lua_pushvalue( l, -1 );
// Set the "__index" field of the metatable to point to itself
// This pops the stack
lua_setfield( l, -1, "__index" );
// Now we use setglobal to officially expose the luaL_EmpireManager metatable
// to Lua. And we use the name "EmpireManager".
lua_setglobal( l, "EmpireManager" );
}
Unfortunately, I cant seem to get the callback setup right. Lua correctly calls my LuaGameObject::LuaCallFunction, but the stack does not contain what I would like. From within the LuaGameObject::LuaCallFunction, I can find the function name and EmpireManager object on the stack. But, I cant find the args on the stack. What is the proper way to set this up? Or is it not possible?
It is definitely possible to add methods to a userdata type in Lua, as explained in the Programming in Lua guide from the official website.
When you type the following Lua code:
myUserdata:someMethod(arg1,arg2,arg3)
Assuming myUserdata is a "userdata" object, the interpreter will do the following.
Call getmetatable(myUserdata).__index(myUserdata,"someMethod") to get the value of someMethod.
Call someMethod(myUserdata,arg1,arg2,arg3). someMethod can be anything callable from Lua. Examples: a Lua or C function, or a table/userdata with a __call metamethod.
Your __index metamethod should just return a function (or another object callable from Lua) implementing the method. Something like this:
// IMO, quite a misleading name for the __index metamethod (there is a __call metamethod)
int LuaGameObject::LuaCallFunction( lua_State *l)
{
// todo: error checking
OGameObject* pGameObject = static_cast<OGameObject*>(lua_touserdata( luaState, 1 ));
std::string memberName = lua_tostring( luaState, 2 );
int result = 1;
if (memberName == "method1") {
lua_pushcfunction(l,LuaGameObject::luaMethod1);
} else if (memberName == "method2") {
lua_pushcfunction(l,LuaGameObject::luaMethod2);
} else {
result = 0;
}
return result;
}
Basic skeleton of the functions returned by the __index metamethod:
int LuaGameObject::luaMethod1(lua_State* l) {
// todo: error checking.
OGameObject* pGameObject = static_cast<OGameObject*>(lua_touserdata(l, 1));
float arg1 = lua_tonumber(l, 2);
// get other args
pGameObject->method1(arg1 /*, more args if any.*/);
// optionally push return values on the stack.
return 0; // <-- number of return values.
}
Ok so after more research, I now believe that I cannot use __index metafunction to call a c functor with arguments. It only passes the table name and the key to the callback.
However, for anyone interested, it can be used for table-like objects, but not functions (as arguments are not pushed onto the stack). I will it for my "property" objects. They have no arguments and can be used in lua as follows...
local king = EmpireManager:king
king:name = "Arthur"
local name = king:name
These properly link to and call the appropriate C++ objects.functions
Actor::SetName(std::string name)
std::string Actor::GetName()
I had the same problem to call a method from my object and have used this post to develop the solution.
I hope that the example below can be useful to you.
#include <iostream>
#include <string>
#include <map>
#include <functional>
extern "C" {
#include "lua/lua.h"
#include "lua/lauxlib.h"
#include "lua/lualib.h"
}
//template<class UserdataType> // if will be work with lua garbage collector, use a function like that to delete the this_ptr (1st param)
//int DeletePtr(lua_State *lua_state) { // It's necessary register the metatable.__gc and to trust in gc (create just pointer of LuaObjects
// UserdataType** this_ptr = reinterpret_cast<UserdataType**>(lua_touserdata(lua_state, 1));
// delete (*this_ptr);
// return 0;
//}
template<class UserdataType>
int Closure(lua_State *lua_state) {
UserdataType** ptr = reinterpret_cast<UserdataType**>(lua_touserdata(lua_state, 1)); // This closure is being called by call operator ()
return (*ptr)->CallFunction(lua_state); // To access the function name called use lua stack index with lua_upvalueindex(-1)
} // Call the object method to resolve this called there
template<class UserdataType>
int ReturnClosure(lua_State *lua_state) { // This function is called as a lookup of metatable.__index
lua_pushcclosure(lua_state, Closure<UserdataType>, 1); // then we will return a closure to be called through call operator ()
return 1; // The 1st param (the only one) is the action name of function
} // Then a closure will grant access to ReturnClosure params as upvalues (lua_upvalueindex)
class LuaObject {
public:
LuaObject() : userdata_name("userdata1") {
}
void CreateNewUserData(lua_State* lua_ptr, const std::string& global_name) {
RegisterUserData(lua_ptr);
LuaObject** this_ptr = reinterpret_cast<LuaObject**>(lua_newuserdata(lua_ptr, sizeof(LuaObject*)));
*this_ptr = this;
luaL_getmetatable(lua_ptr, userdata_name.c_str());
lua_setmetatable(lua_ptr, -2); // setmetatable(this_ptr, userdata_name)
lua_setglobal(lua_ptr, global_name.c_str()); // store to global scope
}
int CallFunction(lua_State* lua_state) const {
std::string name = lua_tostring(lua_state, lua_upvalueindex(1)); // userdata:<function>(param2, param3)
auto it = functions.find(name); // <function> lua_tostring(lua_state, lua_upvalueindex(1))
if (it != functions.end()) { // <implicit this> lua_touserdata(l, 1)
return it->second(lua_state); // <param #1> lua_touserdata(l, 2)
} // <param #2> lua_touserdata(l, 3)
return 0; // <param #n> lua_touserdata(l, n+1)
}
void NewFunction(const std::string& name, std::function<int(lua_State*)> func) {
functions[name] = func;
}
private:
void RegisterUserData(lua_State* lua_ptr) {
luaL_getmetatable(lua_ptr, userdata_name.c_str());
if (lua_type(lua_ptr, -1) == LUA_TNIL) {
/* create metatable for userdata_name */
luaL_newmetatable(lua_ptr, userdata_name.c_str());
lua_pushvalue(lua_ptr, -1); /* push metatable */
/* metatable.__gc = DeletePtr<LuaObject> */
//lua_pushcfunction(lua_ptr, DeletePtr<LuaObject>);
//lua_setfield(lua_ptr, -2, "__gc");
/* metatable.__index = ReturnClosure<LuaObject> */
lua_pushcfunction(lua_ptr, ReturnClosure<LuaObject>);
lua_setfield(lua_ptr, -2, "__index");
}
}
std::map<std::string, std::function<int(lua_State*)>> functions;
std::string userdata_name;
};
int main(int argc, char* argv[]) {
lua_State* lua_state = luaL_newstate();
luaL_openlibs(lua_state);
LuaObject luaobj;
luaobj.CreateNewUserData(lua_state, "test_obj");
luaobj.NewFunction("action", [](lua_State* l)->int {
std::string result = "action has been executed";
LuaObject** ptr = reinterpret_cast<LuaObject**>(lua_touserdata(l, 1));
result += "\n #1 param is user_data (self == this) value = " + std::to_string(reinterpret_cast<size_t>(*ptr));
for (int i = 2; i <= lua_gettop(l); ++i) {
result += "\n #" + std::to_string(i)+ " = " + lua_tostring(l, i);
}
result += "\n #n param is passed on call operator () #n = " + std::to_string(lua_gettop(l));
lua_pushfstring(l, result.c_str());
return 1;
});
std::string lua_code;
lua_code += "print(test_obj:unknown_function()) \n";
lua_code += "print(test_obj:action()) \n";
lua_code += "print(test_obj:action(1)) \n";
lua_code += "print(test_obj:action(1, 2)) \n";
lua_code += "print(test_obj:action(1, 2, 'abc'))\n";
if (!(luaL_loadbuffer(lua_state, lua_code.c_str(), lua_code.length(), NULL) == 0 && lua_pcall(lua_state, 0, LUA_MULTRET, 0) == 0)) {
std::cerr << "Lua Code Fail: " << lua_tostring(lua_state, -1) << std::endl;
}
lua_close(lua_state);
return 0;
}
Output:
action has been executed
#1 param is user_data (self == this) value = 13629232
#n param is passed on call operator () #n = 1
action has been executed
#1 param is user_data (self == this) value = 13629232
#2 = 1
#n param is passed on call operator () #n = 2
action has been executed
#1 param is user_data (self == this) value = 13629232
#2 = 1
#3 = 2
#n param is passed on call operator () #n = 3
action has been executed
#1 param is user_data (self == this) value = 13629232
#2 = 1
#3 = 2
#4 = abc
#n param is passed on call operator () #n = 4
What I'm trying to do is check for the existence of a file in the local folder and then copy it there if it isn't found (the file was previously added to the project as an asset).
Here is the code:
Windows::Storage::StorageFile^ MainPage::GetCustomFileAsync(Platform::String^ fileName)
{
using Windows::Storage::StorageFile;
using Windows::Storage::StorageFolder;
auto localFolder = Windows::Storage::ApplicationData::Current->LocalFolder;
auto localTask = concurrency::create_task(localFolder->GetFileAsync(fileName));
StorageFile^ retVal = nullptr;
localTask.then([&](StorageFile^ t){
retVal = t;
}).then([](concurrency::task<void> t)
{
try
{
t.get();
OutputDebugString(L"Found\n");
}
catch (Platform::COMException^ e)
{
OutputDebugString(e->Message->Data());
}
}).wait();
return retVal;
}
StorageFile^ fileVar;
if ((fileVar = this->GetCustomFileAsync("somefile.txt")) == nullptr)
{
String^ path = Windows::ApplicationModel::Package::Current->InstalledLocation->Path + "\\Assets";
concurrency::create_task(Windows::Storage::StorageFolder::GetFolderFromPathAsync(path)).then([](StorageFolder^ folder){
return (folder->GetFileAsync("somefile.txt"));
}).then([](StorageFile^ file){
return (file->CopyAsync(Windows::Storage::ApplicationData::Current->LocalFolder));
}).then([&](StorageFile^ file){
fileVar = file;
OutputDebugString(file->DisplayName->Data());
});
}
What happens is that I get an access violation exception at the point where "file" is being assigned to "fileVar" (because of cross-thread access perhaps?). How to fix this?
Edit: I can't do all the processing there because the file will be accessed many times. In short I need to know when it has been successfully copied and get a handle to it. Here is the code that works
Windows::Storage::StorageFile^ GetFile(Platform::String^ fileName)
{
using Windows::Storage::StorageFile;
using Windows::Storage::StorageFolder;
using Windows::Foundation::AsyncOperationCompletedHandler;
using Windows::Foundation::AsyncStatus;
using Windows::Foundation::IAsyncOperation;
using Platform::String;
auto localFolder = Windows::Storage::ApplicationData::Current->LocalFolder;
bool completed = false;
StorageFile^ retVal = nullptr;
localFolder->GetFileAsync(fileName)->Completed = ref new AsyncOperationCompletedHandler<StorageFile^>([&completed, &retVal, &fileName](IAsyncOperation<StorageFile^>^ fileOperation, AsyncStatus status)
{
if (status == AsyncStatus::Error)
{
String^ path = Windows::ApplicationModel::Package::Current->InstalledLocation->Path + "\\Assets";
Windows::Storage::StorageFolder::GetFolderFromPathAsync(path)->Completed = ref new AsyncOperationCompletedHandler<Windows::Storage::StorageFolder^>(
[&completed, &retVal, &fileName](IAsyncOperation<Windows::Storage::StorageFolder^>^ folderOperation, AsyncStatus status)->void{
auto assetFolder = folderOperation->GetResults();
assetFolder->GetFileAsync(fileName)->Completed = ref new AsyncOperationCompletedHandler<Windows::Storage::StorageFile^>([&completed, &retVal, &fileName](IAsyncOperation<Windows::Storage::StorageFile^>^ fileOperation, AsyncStatus status)->void{
auto file = fileOperation->GetResults();
file->CopyAsync(Windows::Storage::ApplicationData::Current->LocalFolder)->Completed = ref new AsyncOperationCompletedHandler<Windows::Storage::StorageFile^>
([&completed, &retVal, &fileName](IAsyncOperation<Windows::Storage::StorageFile^>^ fileOperation, AsyncStatus status)->void {
retVal = fileOperation->GetResults();
completed = true;
});
});
});
}
else
{
retVal = fileOperation->GetResults();
completed = true;
}
});
while (completed == false);
return retVal;
}
Rather than passing a delegate as an argument and returning void, make your method return task<StorageFile^> and then the caller can do a .then() to continue working once the operation has succeeded.
Or if this is exposed as a public WinRT method (not an internal / private C++ method) then use IAsyncOperation<StorageFile^>^ as the return type, and wrap the whole thing in create_async():
IAsyncOperation<StorageFile^>^ DoStuff(params)
{
return concurrency::create_async([params]
{
// function body goes here
});
}
Here's a solution I put together. Two things that are important to know:
When executing an asynchronous operation using concurrency::create_task the async operation(s) can still be executing when the parent function returns. So the captured variables MUST outlive the context of the parent function. Which obviously won't happen if they are being passed by reference. It took a while to realize this.
WinRT imposes certain restrictions on the concurrency runtime. Calling concurrency::task::get() or concurrency::task::wait() will throw an exception in an STA thread, unless the call is in a task continuation.
More information in this post:
http://social.msdn.microsoft.com/Forums/windowsapps/en-US/ae54980b-41ce-4337-a059-2213b549be4b/concurrencyinvalidoperation-when-calling-tasktget?forum=winappswithnativecode
In that case how to know when the function has finished doing it's job? I opted to pass in a callback (AKA delegate).
delegate void FileOperation(Windows::Storage::StorageFile^ file);
void GetFileConcurrency(Platform::String^ fileName, FileOperation^ fileOp)
{
using Windows::Storage::StorageFile;
using Windows::Storage::StorageFolder;
using Platform::String;
auto localFolder = Windows::Storage::ApplicationData::Current->LocalFolder;
String^ assetFolderPath = Windows::ApplicationModel::Package::Current->InstalledLocation->Path + "\\Assets";
auto localFolderTask = concurrency::create_task(localFolder->GetFileAsync(fileName));
localFolderTask.then([localFolder, assetFolderPath, fileName, fileOp](concurrency::task<StorageFile^> theTask){
try
{
StorageFile^ theFile = theTask.get();
fileOp(theFile);
}
catch (Platform::Exception^ e)
{
OutputDebugString(e->Message->Data());
auto assetFolderTask = concurrency::create_task(StorageFolder::GetFolderFromPathAsync(assetFolderPath));
assetFolderTask.then([localFolder, assetFolderPath, fileName, fileOp](StorageFolder^ assetFolder){
auto assetFileTask = concurrency::create_task(assetFolder->GetFileAsync(fileName));
assetFileTask.then([localFolder, assetFolderPath, fileName, fileOp](StorageFile^ file){
auto copyFileTask = concurrency::create_task(file->CopyAsync(localFolder));
copyFileTask.then([localFolder, assetFolderPath, fileName, fileOp](StorageFile^ file){
OutputDebugString(file->Path->Data());
fileOp(file);
});
});
});
}
});
}
Iam new to using Core Foundations. I want to use dictionary to store some key value pair. The value must be a pointer to a struct. This pointer is pointing to dynamically allocated buffer.
CFMutableDictionaryRef init_hash_table() {
return CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
This is used to create the dictionary and the return value is stored as global variable.
CFNumberRef
create_hash_key(int sd) {
return CFNumberCreate(NULL, kCFNumberIntType, &sd);
}
int
add_hash_entry(CFMutableDictionaryRef dict, int sd, void *pkt) {
CFNumberRef key = create_hash_key(sd);
CFDictionarySetValue(dict, key, pkt);
return 0;
}
When I execute this code, I get segfault. I see that pkt has a valid address and key seems to be created. Does anyone know how to assign a pointer to value part?
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000011
0x00007fff8c9f339f in objc_msgSend_fixup ()
Any ideas?
The problem is the kCFTypeDictionaryValueCallBacks argument. From the documentation:
kCFTypeDictionaryValueCallBacks
Predefined CFDictionaryValueCallBacks structure containing a set of
callbacks appropriate for use when the values in a CFDictionary are
all CFType-derived objects.
So in your case, CFRetain() is called on the pointer when the value is added to the
dictionary. This causes the crash because the pointer does not point to a CoreFoundation
object.
You can create the dictionary with
CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, NULL);
instead, so that no "reference counting" will be done on the value.
Alternatively, you can wrap the pointer into a CFDataRef and put that into the
dictionary.
In both cases it is your responsibility that the pointer is still valid
when the value is retrieved from the dictionary later.
Here is a simple example how you could implement refcounting for your custom objects:
typedef struct {
int refcount;
int val;
} mystruct;
const void *myretain(CFAllocatorRef allocator, const void *value)
{
mystruct *p = (mystruct *)value;
p->refcount++;
return p;
}
void myrelease(CFAllocatorRef allocator, const void *value)
{
mystruct *p = (mystruct *)value;
if (p->refcount == 1)
free(p);
else
p->refcount--;
}
int main(int argc, const char * argv[])
{
mystruct *p = malloc(sizeof(*p));
p->refcount = 1;
p->val = 13;
CFDictionaryValueCallBacks vcb = { 0 , myretain, myrelease, NULL, NULL };
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &vcb);
int sd = 13;
CFNumberRef key = CFNumberCreate(NULL, kCFNumberIntType, &sd);
CFDictionarySetValue(dict, key, p);
// refcount == 2
myrelease(NULL, p);
// refcount == 1
mystruct *q = CFDictionaryGetValue(dict, key);
// refcount is still 1, "GetValue" does not increment the refcount
CFRelease(dict);
// object is deallocated
return 0;
}
I have a situation in Visual C++ 2008 that I have not seen before. I have a class with 4 STL objects (list and vector to be precise) and integers.
It has a method:
inline int id() { return m_id; }
The return value from this method is corrupt, and I have no idea why.
debugger screenshot http://img687.imageshack.us/img687/6728/returnvalue.png
I'd like to believe its a stack smash, but as far as I know, I have no buffer over-runs or allocation issues.
Some more observations
Here's something that puts me off. The debugger prints right values in the place mentioned // wrong ID.
m_header = new DnsHeader();
assert(_CrtCheckMemory());
if (m_header->init(bytes, size))
{
eprintf("0The header ID is %d\n", m_header->id()); // wrong ID!!!
inside m_header->init()
m_qdcount = ntohs(h->qdcount);
m_ancount = ntohs(h->ancount);
m_nscount = ntohs(h->nscount);
m_arcount = ntohs(h->arcount);
eprintf("The details are %d,%d,%d,%d\n", m_qdcount, m_ancount, m_nscount, m_arcount);
// copy the flags
// this doesn't work with a bitfield struct :(
// memcpy(&m_flags, bytes + 2, sizeof(m_flags));
//unpack_flags(bytes + 2); //TODO
m_init = true;
}
eprintf("Assigning an id of %d\n", m_id); // Correct ID.
return
m_header->id() is an inline function in the header file
inline int id() { return m_id; }
I don't really know how best to post the code snippets I have , but here's my best shot at it. Please do let me know if they are insufficient:
Class DnsHeader has an object m_header inside DnsPacket.
Main body:
DnsPacket *p ;
p = new DnsPacket(r);
assert (_CrtCheckMemory());
p->add_bytes(buf, r); // add bytes to a vector m_bytes inside DnsPacket
if (p->parse())
{
read_packet(sin, *p);
}
p->parse:
size_t size = m_bytes.size(); // m_bytes is a vector
unsigned char *bytes = new u_char[m_bytes.size()];
copy(m_bytes.begin(), m_bytes.end(), bytes);
m_header = new DnsHeader();
eprintf("m_header allocated at %x\n", m_header);
assert(_CrtCheckMemory());
if (m_header->init(bytes, size)) // just set the ID and a bunch of other ints here.
{
size_t pos = DnsHeader::SIZE; // const int
if (pos != size)
; // XXX perhaps generate a warning about extraneous data?
if (ok)
m_parsed = true;
}
else
{
m_parsed = false;
}
if (!ok) {
m_parsed = false;
}
return m_parsed;
}
read_packet:
DnsHeader& h = p.header();
eprintf("The header ID is %d\n", h.id()); // ID is wrong here
...
DnsHeader constructor:
m_id = -1;
m_qdcount = m_ancount = m_nscount = m_arcount = 0;
memset(&m_flags, 0, sizeof(m_flags)); // m_flags is a struct
m_flags.rd = 1;
p.header():
return *m_header;
m_header->init: (u_char* bytes, int size)
header_fmt *h = (header_fmt *)bytes;
m_id = ntohs(h->id);
eprintf("Assigning an id of %d/%d\n", ntohs(h->id), m_id); // ID is correct here
m_qdcount = ntohs(h->qdcount);
m_ancount = ntohs(h->ancount);
m_nscount = ntohs(h->nscount);
m_arcount = ntohs(h->arcount);
You seem to be using a pointer to an invalid class somehow. The return value shown is the value that VS usually uses to initialize memory with:
2^32 - 842150451 = 0xCDCDCDCD
You probably have not initialized the class that this function is a member of.
Without seeing more of the code in context.. it might be that the m_id is out of the scope you expect it to be in.
Reinstalled VC++. That fixed everything.
Thank you for your time and support everybody! :) Appreciate it!