fiber_call.h 1.88 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68

#ifndef PREDICTABLE_PARALLEL_PATTERNS_APP_CONTEXT_SWITCH_FIBER_CALL_H_
#define PREDICTABLE_PARALLEL_PATTERNS_APP_CONTEXT_SWITCH_FIBER_CALL_H_

#include <utility>
#include <cstdio>
#include <cstdint>
#include <new>

namespace pls {
namespace internal {
namespace base {

using continuation_t = void *;
using stack_pointer_t = char *;
using callback_t = continuation_t (*)(continuation_t, void *);

template<typename F>
struct lambda_capture {
  F lambda_;

  explicit lambda_capture(F &&lambda) : lambda_{std::forward<F>(lambda)} {}

  continuation_t operator()(continuation_t continuation) {
    return lambda_(continuation);
  }
};

template<typename T>
continuation_t execute_callable(continuation_t continuation, void *param) {
  T *callable = reinterpret_cast<T *>(param);
  continuation_t result = (*callable)(continuation);

  callable->~T();
  return result;
}

extern "C" {
continuation_t __fiber_call(stack_pointer_t stack_base,
                            void *callback_arg,
                            callback_t callback,
                            stack_pointer_t stack_limit);
continuation_t __fiber_continue(continuation_t continuation);
}

template<typename F>
static lambda_capture<F> *place_lambda_capture(F &&lambda, char *memory) {
  return new(memory) lambda_capture<F>(std::forward<F>(lambda));
}

template<typename F>
continuation_t fiber_call(stack_pointer_t stack_memory, size_t stack_size, F &&lambda) {
  stack_pointer_t lambda_memory = stack_memory + stack_size - sizeof(lambda_capture<F>);
  auto *captured_lambda = place_lambda_capture(std::forward<F>(lambda), lambda_memory);

  stack_pointer_t stack_base = lambda_memory;
  stack_pointer_t stack_limit = stack_memory;

  callback_t callback = execute_callable<lambda_capture<F>>;

  return __fiber_call(stack_base, captured_lambda, callback, stack_limit);
}

}
}
}

#endif //PREDICTABLE_PARALLEL_PATTERNS_APP_CONTEXT_SWITCH_FIBER_CALL_H_