<commit_before>#include <stutter/coroutine.h>
#include <stutter/log.h>

#ifdef USE_VALGRIND
#include <valgrind/valgrind.h>
#endif

#define COROUTINE_STACK_SIZE (32 * 1024)

using namespace std;

void
entry_point(void *ptr)
{
	Coroutine *co = reinterpret_cast<Coroutine*>(ptr);
	co->run();
}

////////////////////////////////////////////////////////////

Coroutine::Coroutine()
		: m_state(INIT)
		, m_stack(0)
{
	// create new context based on current one:
	create_stack();     // allocate stack for new context
	int gc = getcontext(&m_ctx); // copy current context into m_ctx
	if (gc != 0) {
		Log::get(Log::CRIT) << "Could not run getcontext"
		<< endl;
	} else {
		makecontext(&m_ctx, (void (*)())entry_point, 1, this); // create
	}
}

Coroutine::~Coroutine()
{
	if (m_stack) {
		delete[] m_stack;

#ifdef USE_VALGRIND
		VALGRIND_STACK_DEREGISTER(m_id);
#endif
	}
}

Coroutine::State
Coroutine::state() const
{
	return m_state;
}

void
Coroutine::run()
{
	int v = exec();
	m_state = DONE;
	yield(v);
}

int
Coroutine::resume()
{
	if (m_state == INIT)
		m_state = RUNNING;
	else if (m_state == DONE)
		return -1;

	ucontext_t prev_ctx = m_switcher.caller;
	swapcontext(&m_switcher.caller, &m_ctx); // switch to function
    // yield() brings us back here
	m_ctx = m_switcher.callee;               // save m_ctx
	m_switcher.caller = prev_ctx;            // save ctx for next use as "prev"

	return m_value;
}

void
Coroutine::yield(int value)
{
	// make available to .value()
	m_value = value;

	// switch out function context, get back to caller.
	swapcontext(&m_switcher.callee, &m_switcher.caller);
}

void
Coroutine::create_stack()
{
	m_stack = new char[COROUTINE_STACK_SIZE];

	m_ctx.uc_stack.ss_sp = (void*)m_stack;
	m_ctx.uc_stack.ss_size = COROUTINE_STACK_SIZE;
	m_ctx.uc_stack.ss_flags = 0;
	m_ctx.uc_link = 0;

#ifdef USE_VALGRIND
	m_id = VALGRIND_STACK_REGISTER(m_stack, m_stack + COROUTINE_STACK_SIZE);
#endif
}
<commit_msg>Fix stack creation as getcontext might clear it<commit_after>#include <stutter/coroutine.h>
#include <stutter/log.h>

#ifdef USE_VALGRIND
#include <valgrind/valgrind.h>
#endif

#define COROUTINE_STACK_SIZE (32 * 1024)

using namespace std;

void
entry_point(void *ptr)
{
	Coroutine *co = reinterpret_cast<Coroutine*>(ptr);
	co->run();
}

////////////////////////////////////////////////////////////

Coroutine::Coroutine()
		: m_state(INIT)
		, m_stack(0)
{
	// create new context based on current one:
	int gc = getcontext(&m_ctx); // copy current context into m_ctx
	create_stack();     // allocate stack for new context
	if (gc != 0) {
		Log::get(Log::CRIT) << "Could not run getcontext"
		<< endl;
	} else {
		makecontext(&m_ctx, (void (*)())entry_point, 1, this); // create
	}
}

Coroutine::~Coroutine()
{
	if (m_stack) {
		delete[] m_stack;

#ifdef USE_VALGRIND
		VALGRIND_STACK_DEREGISTER(m_id);
#endif
	}
}

Coroutine::State
Coroutine::state() const
{
	return m_state;
}

void
Coroutine::run()
{
	int v = exec();
	m_state = DONE;
	yield(v);
}

int
Coroutine::resume()
{
	if (m_state == INIT)
		m_state = RUNNING;
	else if (m_state == DONE)
		return -1;

	ucontext_t prev_ctx = m_switcher.caller;
	swapcontext(&m_switcher.caller, &m_ctx); // switch to function
    // yield() brings us back here
	m_ctx = m_switcher.callee;               // save m_ctx
	m_switcher.caller = prev_ctx;            // save ctx for next use as "prev"

	return m_value;
}

void
Coroutine::yield(int value)
{
	// make available to .value()
	m_value = value;

	// switch out function context, get back to caller.
	swapcontext(&m_switcher.callee, &m_switcher.caller);
}

void
Coroutine::create_stack()
{
	m_stack = new char[COROUTINE_STACK_SIZE];

	m_ctx.uc_stack.ss_sp = (void*)m_stack;
	m_ctx.uc_stack.ss_size = COROUTINE_STACK_SIZE;
	m_ctx.uc_stack.ss_flags = 0;
	m_ctx.uc_link = 0;

#ifdef USE_VALGRIND
	m_id = VALGRIND_STACK_REGISTER(m_stack, m_stack + COROUTINE_STACK_SIZE);
#endif
}

{'fraction_non_alphanumeric': 0.16274309109518936, 'fraction_numerical': 0.006141248720573183, 'mean_word_length': 3.555944055944056, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6921435', 'n_tokens_mistral': 1573, 'n_tokens_neox': 1558, 'n_words': 337}