#include <stdio.h>
#include <unistd.h>


int open_closure_registration (void)
{
  return 0;
}

void *_register_closure_actual (void *func, int handle)
{
  return func;
}

#define register_closure(func)  ((typeof (func)*)_register_closure_actual((void *)func, holder_crh))

#if 1
#include <pthread.h>


#define RT_WCLOSURE1(function_name,return_type) \
  int crh = open_closure_registration (); \
  pthread_cond_t function_name##_local_cond  = PTHREAD_COND_INITIALIZER; \
  pthread_mutex_t function_name##_local_mutex = PTHREAD_MUTEX_INITIALIZER; \
  return_type return_variable; \
  void *function_name##_local_holding_function (void *function_name##_local_ignored_arg) \
  { \
    int holder_crh = crh;

#define RT_WCLOSURE2(function_name,return_type) \
    return_type function_name##_local_proxy_function (void) \
    {

#define RT_WCLOSURE3(function_name) \
    } \
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); \
    pthread_mutex_lock (&function_name##_local_mutex); \
    return_variable = function_name##_local_proxy_function (); \
    pthread_cond_signal (&function_name##_local_cond); \
    pthread_mutex_unlock (&function_name##_local_mutex); \
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); \
    for (;;) sleep (~0); \
    return NULL; \
  } \
  pthread_t function_name##_local_holding_thread; \
  pthread_mutex_lock (&function_name##_local_mutex); \
  pthread_create (&function_name##_local_holding_thread, NULL, function_name##_local_holding_function, NULL); \
  pthread_cond_wait (&function_name##_local_cond, &function_name##_local_mutex); \
  pthread_mutex_unlock (&function_name##_local_mutex); \
  return return_variable;

#else
  #include <ucontext.h>

ucontext_t context [10];
char stack [10][SIGSTKSZ*100];

int context_handle=-1;


#define RT_WCLOSURE1(function_name,return_type) \
  int function_name##crh = open_closure_registration (); \
  ucontext_t function_name##outer_context, *function_name##inner_context = &context [++context_handle]; \
  return_type function_name##rval; \
  volatile int function_name##done = 0; \
  \
  return_type function_name##inner (ucontext_t *function_name##outer_contextp, return_type *function_name##rvalp) \
  { \
  int holder_crh = function_name##crh;


#define RT_WCLOSURE2(function_name,return_type) \
    return_type function_name##proxy (void) \
    { \

#define RT_WCLOSURE3(function_name) \
    } \
    *function_name##rvalp = function_name##proxy (); \
    setcontext (function_name##outer_contextp); \
    return NULL; \
  } \
  \
  function_name##inner_context->uc_link = &function_name##outer_context; \
  function_name##inner_context->uc_stack.ss_sp = stack [context_handle]; \
  function_name##inner_context->uc_stack.ss_size = sizeof (stack [context_handle]); \
  getcontext (function_name##inner_context); \
  \
  makecontext (function_name##inner_context, (void (*) (void)) function_name##inner, 2, &function_name##outer_context, &function_name##rval); \
  \
  getcontext (&function_name##outer_context); \
  if (!function_name##done) \
  { \
    function_name##done = 1; \
    setcontext (function_name##inner_context); \
  } \
  return function_name##rval;
#endif

typedef void* (*func_t)(void *);
typedef int (*func2_t)(const char *);

func2_t outer (int a, int b)
{
  RT_WCLOSURE1 (outer, func2_t)

//    int foo [10];
//    int fee [10];
    int _a = a;
    int _b = b;
    int c = a + b;
    int d = a * b;
    int func1 (const char *who)
    {
      printf ("Hello %s from %s\n", who, __func__);
      fflush (stdout);
      _a++;
      _b++;
      printf ("Hello from %s (%d,%d)\n", __func__, _a, _b);

/*      for (int i = 0; i < 10; i++)
      {
        foo [i]++;
        fee [i]--;
      }
      for (int i = 0; i < 10; i++)
      {
        printf ("%d) Hello from %s (%d,%d)\n", i, __func__, fee [i], foo [i]);
      }*/
      return c + d;
    }
  RT_WCLOSURE2 (outer, func2_t)

      printf ("Hello from %s (%d,%d)\n", __func__, a, b);
      return register_closure (func1);

  RT_WCLOSURE3 (outer)
}

void get_them (func2_t *f1, func2_t *f2)
{
  *f1 = outer (20, 30);
  *f2 = outer (30, 40);
}

int main (int arch, const char **argv)
{
  func2_t f1;
  func2_t f2;

  get_them (&f1, &f2);

  printf ("returned = %p\n", f1);
  printf ("returned = %p\n", f2);

  printf ("%d\n", f1 ("cow"));
  printf ("%d\n", f2 ("bull"));
  printf ("%d\n", f1 ("cow"));
  printf ("%d\n", f2 ("bull"));
  printf ("%d\n", f1 ("cow"));
  printf ("%d\n", f2 ("bull"));
  printf ("%d\n", f1 ("cow"));
  printf ("%d\n", f2 ("bull"));

  return 0;
}
