.
, , , setjmp longjmp msvcrt.dll.
[DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl, EntryPoint="_setjmp")]
static extern int setjmp(out Jmp_buf env);
[DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]
static extern void longjmp(ref Jmp_buf env, int val);
[StructLayout(LayoutKind.Sequential,Size=16*4)]
struct Jmp_buf{}
, , . P/Invoke native setjmp, setjmp P/Invoke. , longjmp AccessViolationException.
. mounta... , # . , , - "" , JITted setjmp. , , - .
#, , , ++/CLI!
#include <csetjmp>
#include <iostream>
using namespace System;
using namespace System::Runtime::InteropServices;
using namespace std;
typedef void (*UnmanagedHandler)(int code);
void mysetjmp(jmp_buf env, UnmanagedHandler handler)
{
handler(setjmp(env));
throw 0;
}
void mylongjmp(jmp_buf env, int val)
{
longjmp(env, val);
}
namespace jmptestdll
{
public delegate void JumpHandler(int code);
public ref class JumpBuffer
{
private:
jmp_buf *env;
public:
JumpBuffer()
{
env = new jmp_buf[1];
}
~JumpBuffer()
{
this->!JumpBuffer();
}
void Set(JumpHandler^ handler)
{
if(env)
{
IntPtr ptr = Marshal::GetFunctionPointerForDelegate(handler);
UnmanagedHandler act = static_cast<UnmanagedHandler>(ptr.ToPointer());
try{
mysetjmp(*env, act);
}catch(int code)
{
}
}
}
void Jump(int value)
{
if(env)
{
mylongjmp(*env, value);
}
}
protected:
!JumpBuffer()
{
if(env)
{
delete[] env;
}
}
};
}
, , , ++ , . . - mysetjmp AccessViolationException, . "" throw .
var env = new JumpBuffer();
env.Set(
delegate(int code)
{
Console.WriteLine(code);
env.Jump(code+1);
Console.WriteLine("Goodbye world!");
}
);
" !" , 0 . :
static JumpBuffer buf = new JumpBuffer();
static void second()
{
Console.WriteLine("second");
try{
buf.Jump(1);
}finally{
Console.WriteLine("finally");
}
}
static void first()
{
second();
Console.WriteLine("first");
}
public static void Main(string[] args)
{
buf.Set(
val => {
Console.WriteLine(val);
if(val == 0) first();
else Console.WriteLine("main");
}
);
Console.ReadKey(true);
}
:
0
1
, finally, , . , Set .
, .
, # async. , await , .
public class LongJump
{
Continuation continuation;
public SetAwaiter Set()
{
return new SetAwaiter(this);
}
public JumpAwaiter Jump()
{
return new JumpAwaiter(this);
}
public struct JumpAwaiter : INotifyCompletion
{
readonly LongJump jump;
public JumpAwaiter(LongJump jump)
{
this.jump = jump;
}
public JumpAwaiter GetAwaiter()
{
return this;
}
public bool IsCompleted{
get{
return false;
}
}
public void OnCompleted(Action callerContinuation)
{
jump.continuation.Continue();
}
public void GetResult()
{
}
}
public struct SetAwaiter : INotifyCompletion
{
readonly LongJump jump;
public SetAwaiter(LongJump jump)
{
this.jump = jump;
}
public SetAwaiter GetAwaiter()
{
return this;
}
public bool IsCompleted{
get{
return false;
}
}
public void OnCompleted(Action callerContinuation)
{
jump.continuation = new Continuation(callerContinuation);
callerContinuation();
}
public void GetResult()
{
}
}
private class Continuation
{
private readonly int savedState;
private readonly object stateMachine;
private readonly FieldInfo field;
private readonly Action action;
internal Continuation(Action action)
{
stateMachine = action.Target.GetType().InvokeMember("m_stateMachine", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField, null, action.Target, null);
field = stateMachine.GetType().GetField("<>1__state", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
savedState = (int)field.GetValue(stateMachine);
this.action = action;
}
internal void Continue()
{
field.SetValue(stateMachine, savedState);
action();
}
}
}
public static void Main(string[] args)
{
MainAsync().Wait();
Console.ReadKey(true);
}
public static async Task MainAsync()
{
var jump = new LongJump();
Console.WriteLine("Begin");
int code = 0;
await jump.Set();
Console.WriteLine(code);
code += 1;
await InnerMethod(code, jump);
Console.WriteLine("End");
}
public static async Task InnerMethod(int code, LongJump jump)
{
if(code < 5)
{
await jump.Jump();
}
}
COMEFROM #.
, await jump.Set(); , . await jump.Jump(); . , , , , .
, ++/CLI, await jump.Jump(), .
, # " " - .