| Software |
Example |
Has its own... |
| Function |
foo(); |
Scratch registers and area of the stack |
| Coroutine / Userspace Thread |
see below |
Registers and stack |
| OS Kernel Thread |
std::thread t(foo); |
... and thread-local storage |
| OS Process |
fork(); |
... and memory space, open files, and
permissions |
| OS Container |
see docker |
... and filesystem, and network configuration |
| Virtual Machine |
see VM
software |
... and OS, and hardware |
; swap64(old,new): switch coroutines global swap64 swap64: ; Save preserved registers to old stack push rdi push rbp push rbx push r12 push r13 push r14 push r15 ; Save old stack pointer mov [rdi],rsp ; Load new stack pointer mov rsp,[rsi] ; Restore preserved regs from new stack pop r15 pop r14 pop r13 pop r12 pop rbx pop rbp pop rdi ret
typedef void (*coroutine_run_t)(void *arg);
void coroutine_exit(void) {
std::cout<<"Coroutine has exited. Goodbye.\n";
exit(0);
}
class coroutine {
public:
long *stack; // top of coroutine's stack
long *stack_alloc; // allocated memory for stack
// Used to make main into a coroutine
coroutine() {
stack=0;
stack_alloc=0;
}
// Used to create a new coroutine
coroutine(coroutine_run_t run,void *arg,int stacksize=1024*1024) {
stack_alloc=new long[stacksize/sizeof(long)];
stack=&stack_alloc[stacksize/sizeof(long)-1]; // top of stack
*(--stack)=(long)coroutine_exit; // coroutine cleanup
*(--stack)=(long)run; // user's function to run (rop style!)
*(--stack)=(long)arg; // user's function argument (rdi)
for (int saved=0;saved<6;saved++)
*(--stack)=0xdeadbeef; // initial values for saved registers
}
// Cleanup
~coroutine() {
delete[] stack_alloc;
}
};
extern "C" void swap64(coroutine *old_co,coroutine *new_co);
coroutine *main_co;
coroutine *sub_co;
void sub(void *arg) {
int i; // random local, to see stack pointer
std::cout<<" Inside sub-coroutine. Stack="<<&i<<endl;
swap64(sub_co,main_co); // back to main
std::cout<<" Back in sub. Stack="<<&i<<endl;
swap64(sub_co,main_co); // back to main
}
long foo(void) {
int i;
std::cout<<"Making coroutines. Stack="<<&i<<std::endl;
main_co=new coroutine();
sub_co=new coroutine(sub,0);
std::cout<<"Switching to coroutine"<<std::endl;
swap64(main_co,sub_co);
std::cout<<"Back in main from coroutine. Stack="<<&i<<std::endl;
swap64(main_co,sub_co);
std::cout<<"Any questions?"<<std::endl;
return 0;
}
On my machine, this prints:Making coroutines. Stack=0x7fffffffe61c Switching to coroutine Inside sub-coroutine. Stack=0x2aaaab8f2fe4 Back in main from coroutine. Stack=0x7fffffffe61c Back in sub. Stack=0x2aaaab8f2fe4 Any questions? Program complete. Return 0 (0x0)
If you use
this in a real project, you should use a real library like boost::coroutines
or libconcurrency.