#include #include #include #include // // Reference: Original code was by Evan Jones as basic-uc.c. // [[ Mostly changed stdout messages to be more informative or // accurate ]] // Purpose: Context switch between main thread and child thread using // swapcontext // Usage: ucontext-basic // Calls: makecontext, swapcontext // Notes: // o A "fiber" is a user-level thread (i.e., no kernel thread support) // o ucontext makes it trivial to manipulate contexts // Ideas: // o swapcontext(&from,&to) is equivalent to Yield(&from,&to) where the // context is stored in 'from' and the new context is in 'to'. // o Control is: // Parent Child // ------ ----- // getcontext // makecontext // swapcontext ----------> ... // ... <---------- swapcontext // swapcontext ----------> ... // ... <---------- swapcontext // exit // o See end of file for ucontext // History: // o 5 Jan 2007 kenw: Modified from Evan Jones' basic-uc.c code // // 64kB stack #define FIBER_STACK 1024*64 ucontext_t child, parent; // The child thread will execute this function void childFiber() { int x = 99; // data on stack (use gdb to see it) printf( "\t+ BEGIN: Child fiber with x = %d\n", x ); printf( "\t+ Child fiber yielding to parent\n" ); swapcontext( &child, &parent ); printf( "\t+ Child thread to parent AGAIN\n" ); swapcontext( &child, &parent ); // should never return from this printf( "\t+ EXIT: Child fiber\n" ); } int main() { int x = 88; // data on stack (use gdb to see it) printf( "\t+ BEGIN: Parent fiber with x = %d\n", x ); // Get the current execution context getcontext( &child ); // Modify the context to a new stack child.uc_link = 0; child.uc_stack.ss_sp = malloc( FIBER_STACK ); child.uc_stack.ss_size = FIBER_STACK; child.uc_stack.ss_flags = 0; if ( child.uc_stack.ss_sp == 0 ) { perror( "malloc: Could not allocate stack" ); exit( 1 ); } // Create the new context printf( "Create child fiber\n" ); makecontext( &child, &childFiber, 0 ); // Execute the child context printf( "Switching to child fiber\n" ); swapcontext( &parent, &child ); printf( "Switching to child fiber AGAIN\n" ); swapcontext( &parent, &child ); // Free the stack free( child.uc_stack.ss_sp ); printf( "Child fiber stack freed in parent and parent fiber exiting\n" ); return 0; } // // o Machine and User Context // // typedef struct // Machine context (processor state) // { // gregset_t gregs; // general-purpose registers // fpregset_t fpregs; // floating point registers // unsigned long int oldmask; // old signal mask // unsigned long int cr2; // virtual memory related // } mcontext_t; // // typedef struct ucontext // Userlevel context // { // unsigned long int uc_flags; // // struct ucontext *uc_link; // addr of next ucontext_t // stack_t uc_stack; // stack descriptor // mcontext_t uc_mcontext; // machine context (above) // __sigset_t uc_sigmask; // signal mask // struct _libc_fpstate __fpregs_mem; // floating point related // } ucontext_t; //