#include <stdio.h>
#include <stdlib.h>
#include <ucontext.h>
#include <sys/mman.h>
#include <errno.h>

static ucontext_t uctx_main, uctx_func1, uctx_func2;

static unsigned long get_sp(void)
{
   unsigned long sp;
   asm("copy %%sp, %0" : "=r"(sp));
   return sp;
}

#define handle_error(msg) \
   do { perror(msg); exit(EXIT_FAILURE); } while (0)

static int counter = 0;

static void
func1(void)
{
   printf("%s: started  counter %d  sp %lx\n", __func__, counter++, get_sp());
// while (1) ;
	func1();
   printf("%s: swapcontext(&uctx_func1, &uctx_func2)\n", __func__);
   if (swapcontext(&uctx_func1, &uctx_func2) == -1)
       handle_error("swapcontext");
   printf("%s: returning\n", __func__);
}

static void
func2(void)
{
   printf("%s: started\n", __func__);
   printf("%s: swapcontext(&uctx_func2, &uctx_func1)\n", __func__);
   if (swapcontext(&uctx_func2, &uctx_func1) == -1)
       handle_error("swapcontext");
   printf("%s: returning\n", __func__);
}

int
main(int argc, char *argv[])
{
	#define STACK_SZ 8192
   char *func1_stack = malloc(STACK_SZ);
   char func2_stack[16384];

   // printf("%s: started  counter %d  sp %lx\n", __func__, counter++, get_sp());
   // main(argc,argv); // recursive loop!

  /* code from Camm: */
  func1_stack = mmap((void *)0xbe000000,STACK_SZ,
	     PROT_READ|PROT_WRITE|PROT_EXEC,MAP_FIXED|MAP_PRIVATE|MAP_ANON|MAP_STACK,-1,0);
  if (func1_stack ==(void *)-1) {
      printf("cannot mmap new stack %d\n",errno);
      exit(-1);
    }

   if (getcontext(&uctx_func1) == -1)
       handle_error("getcontext");
   uctx_func1.uc_stack.ss_sp = func1_stack;
   uctx_func1.uc_stack.ss_size = STACK_SZ;
   uctx_func1.uc_link = &uctx_main;
   makecontext(&uctx_func1, func1, 0);

   if (getcontext(&uctx_func2) == -1)
       handle_error("getcontext");
   uctx_func2.uc_stack.ss_sp = func2_stack;
   uctx_func2.uc_stack.ss_size = sizeof(func2_stack);
   /* Successor context is f1(), unless argc > 1 */
   uctx_func2.uc_link = (argc > 1) ? NULL : &uctx_func1;
   makecontext(&uctx_func2, func2, 0);

   printf("%s: swapcontext(&uctx_main, &uctx_func2)\n", __func__);
   if (swapcontext(&uctx_main, &uctx_func2) == -1)
       handle_error("swapcontext");

   printf("%s: exiting\n", __func__);
   exit(EXIT_SUCCESS);
}
