What exactly does native task stack mean? When looking for example at the WinAPI Fibers, as Windows native coroutines, there each Fiber has it's own stack, and when switching to another fiber, execution will continue on the stack of that fiber.
When I understand correctly, for COMTAY this works differently, but I don't fully understand how. Could you maybe explain a bit further, how does each co routine handle it's stack, and how to switch from one co routine stack to another (i.e. in this example, how to switch over to CoTask2 within the execution of CoTask1)
A COMTAY task uses its own separate stack such as Fibers. When some A task resumes some B task, then after a context switching the B task uses its own stack. So, COMTAY task behaves like a typical stackful coroutine.
The main task is resumed using the ResumeAsMain or ResumeAsMainExtra function. This function must be called from the standard thread stack as a normal function.
If the main task completes or terminates, control returns to point right after the call to the ResumeAsMain or ResumeAsMainExtra function.
From this address point and below, the thread stack is unused until the main task is complete or terminated. This is the idle thread stack area. Despite this area must not be used, some compilers can use it.
When the pJoinThreadStack function is called within a task, the task stack is switched over to the thread stack area. This allows exceptions to be thrown and constructors such as TFileStream.Create to be called. The code for such things contains some thread stack fixed addresses and cause a critical error when called from the task (coroutine).
After some actions in the thread stack area, the own task stack (native stack) must be returned back. That is done with the pJoinNativeStack function.
Now the answer to the example.
In order for TCoTask1 to resume TCotask2, you need to call Resume(TCotask2.Create). The task stack must be its own TCoTask1 stack (native stack). Calling the Resume function while thread stack causes an error.
So, I put Resume(TCotask2.Create) in the TCotask1.Body and comment out in the TestException.
This can be seen in the WithExceptions_2 example that I uploaded.
procedure TestException;
var
F: file;
begin
try
// CT1.Resume(TCotask2.Create);
AssignFile(F, 'TheFileThatDoesNotExist');
Reset(F);
except
on e: EInOutError do
WriteLn('Error: ' + E.ClassName + EOL + E.Message);
end;
end;
procedure TCotask1.Body;
begin
pJoinThreadStack();
TestException;
pJoinNativeStack();
Resume(TCotask2.Create); // <-
end;
If it's still not clear, feel free to ask again.