如何保存状态并返回深层C函数?

时间:2014-11-23 13:41:18

标签: c emscripten

背景

我正在移植现有的C程序,以便使用Emscripten作为在线游戏。

问题在于Emscripten希望程序围绕一个每秒调用60次的函数进行组织。这对于主游戏循环是可以的,除了有很多地方代码显示一组选项然后等待按键来选择选项。这表示为使用getch()等待按键的调用层次结构中的深层函数。我发现很难看出如何将其纳入运行然后完成的函数所需的Emscripten样式。

问题

当代码调用一个调用了函数的函数时,它调用了一个函数,有一种简单的方法可以保存调用堆栈的整个状态,以便以后可以返回到同一个地方吗?

我尝试了什么

  1. 我目前使用的方法是设置一个全局状态变量来指示我当前的位置,并将堆栈中所有看起来很重要的东西写入静态变量。然后我从所有功能返回。要重新输入,我使用全局变量来决定调用哪个函数以及从保存的数据重新加载哪些变量。但是,这涉及编写大量额外代码,并且非常容易出错。

  2. 我想知道如何将线程用于游戏逻辑并只是从GUI线程发送消息,但Emscripten中的当前thread API似乎要求我尝试将所有游戏数据复制到消息所以这感觉就像更多的工作,没什么好处。

  3. Emscripten支持setjmp / longjmp,但据我所知,这只能完成一半的工作。我想我可以使用longjmp简单地从深层函数返回到上层,但我不知道我可以用它来以后再回到原来的位置。

  4. 关于如何做到这一点的任何更好的想法?

2 个答案:

答案 0 :(得分:1)

您无法从callstack返回并再次重新输入。您只能进行更深入的调用才能仍然能够返回当前状态。一旦函数返回,相同的堆栈(相同的物理内存位置)将被重用于以下调用,并且值将被覆盖。

我不知道Emscripten; getch()包装器可以递归地驱动循环,直到按下一个键吗?

setjmp / longjmp保存堆栈偏移量,但不保存堆栈上的值。它只对从堆栈弹出多个帧有用;它是最接近抛出异常的C。

答案 1 :(得分:1)

您可以尝试使用asyncify(https://github.com/kripken/emscripten/wiki/Asyncify),但不建议这样做。更好的方法是使用emterpreter(https://github.com/kripken/emscripten/wiki/Emterpreter)或doppio(https://github.com/plasma-umass/doppio)。但是,如果您可以使用WebAssembly的演进标准,将来可能会有更好的解决方案。到目前为止,使此类程序运行的唯一特定方法是消除所有递归或实现您自己的调用堆栈。但是,您将不得不将状态保存在JavaScript堆栈之外,因为程序本身无法对其进行操作。这也是longjmp在这种情况下不起作用的原因。