<commit_before>#include "yarn.h"
#define _XOPEN_SOURCE
#include <ucontext.h>
#include <stdlib.h>
#include "smp_scheduler.h"
#include <assert.h>
#include "config.h"
#include <stdio.h>
#include "pages.h"
#include <pthread.h>

typedef struct _yarn_meta
{
	ucontext_t context;
	//unsigned long smp_sched_data;
} yarn_meta;

#define STACK_SIZE (YARNS_STACK_PAGES*4096)

typedef struct _yarn
{
	yarn_meta meta;
	yarn_t next;
	yarn_t prev;
} yarn;

static yarn* yarn_list = 0;
typedef struct _yarn_thread_data
{
	ucontext_t sched_context;
	yarn* yarn_current;
	unsigned long runtime_remaining;
} yarn_thread_data;
#ifdef YARNS_ENABLE_SMP
pthread_key_t _ttd;
#define TTD (*(yarn_thread_data*)(pthread_getspecific(_ttd)))
#define TTDINIT() { int rc; yarn_thread_data* ttd = (yarn_thread_data*)malloc(sizeof(yarn_thread_data)); ttd->yarn_current = NULL; ttd->runtime_remaining = 0; rc = pthread_key_create(&_ttd, 0); assert(rc == 0); }
#else
static yarn_thread_data _ttd;
#define TTD _ttd
#define TTDINIT() { _ttd.yarn_current = 0; _ttd.runtime_remaining = 0; }
#endif

#if YARNS_SELECTED_TARGET == YARNS_TARGET_MACH
#define BASE_CONTEXT_NEEDS_STACK
#endif

static void yarn_check_stack ( const void* base )
{
	// make sure that base is page-aligned (ie a multiple of 4096)
	unsigned long ul = (unsigned long)base;
	if (ul & 4095 || !ul)
	{
		printf("ul&4095=%d\n", (int)(ul % 4096));
		assert(0);
	}
}

static void yarn_launcher ( yarn* active_yarn, void (*routine)(void*), void* udata )
{
	// basically a bootstrap routine for each yarn which runs the routine then cleans up
	routine(udata);
	TTD.runtime_remaining = SCHEDULER_UNSCHEDULE;
}

static void allocate_stack ( ucontext_t* ctx )
{
	ctx->uc_stack.ss_size = STACK_SIZE;
	ctx->uc_stack.ss_sp = page_allocate(STACK_SIZE);
	assert(ctx->uc_stack.ss_sp);
	ctx->uc_stack.ss_flags = 0;
	yarn_check_stack(ctx->uc_stack.ss_sp);
}

static void deallocate_stack ( ucontext_t* ctx )
{
	page_deallocate(ctx->uc_stack.ss_sp, STACK_SIZE);
}

static void basic_launch ()
{
	puts("basic_launch");
	_Exit(0);
}

int __make_trap = 1; // this traps the odd situation where makecontext doesn't work and we get random code jumping in here

static void list_insert ( yarn* active_yarn )
{
	if (yarn_list)
	{
		if (yarn_list->prev)
		{
			active_yarn->prev = yarn_list->prev;
			active_yarn->next = yarn_list;
			active_yarn->prev->next = active_yarn;
			yarn_list->prev = active_yarn;
		}
		else
		{
			yarn_list->prev = yarn_list->next = active_yarn;
			active_yarn->prev = active_yarn->next = yarn_list;
		}
	}
	else
	{
		active_yarn->next = 0;
		active_yarn->prev = 0;
	}
	yarn_list = active_yarn;
}

yarn_t yarn_new ( void (*routine)(void*), void* udata )
{
	// grab memory
	yarn* active_yarn;
	active_yarn = (yarn*)malloc(sizeof(yarn));
	assert(active_yarn);
	// set up stack and such
	allocate_stack(&(active_yarn->meta.context));
	// prepare the context
	__make_trap = 0;
	getcontext(&active_yarn->meta.context);
	assert(__make_trap == 0);
	__make_trap = 1;
	// insert it into the yarn list
	list_insert(active_yarn);
	// run getcontext & makecontext to direct it over to the bootstrap
	//makecontext(&(active_yarn->meta.context), (void (*)())yarn_launcher, 3, active_yarn, routine, udata);
	makecontext(&(active_yarn->meta.context), basic_launch, 0);
	return (yarn_t)active_yarn;
}

void yarn_yield ( yarn_t target )
{
	// ignore target for now
	TTD.runtime_remaining = 1;
	// pop back over to the scheduler
	swapcontext(&(TTD.yarn_current->meta.context), &(TTD.sched_context));
}

static void yarn_processor ( unsigned long procID )
{
	// this is the main routine run by each thread
	volatile int breakProcessor = 0;
	int rc;
	// init the thread yarn data
	TTDINIT();
	// make sure it initted properly
	assert(&TTD);
	// repeatedly ask the scheduler for the next job
	scheduler_job activeJob;
#ifdef BASE_CONTEXT_NEEDS_STACK
	allocate_stack(&(TTD.sched_context));
#endif
	activeJob.pid = 0;
	activeJob.runtime = 0;
	activeJob.data = 0;
	while (!breakProcessor)
	{
		smp_sched_select(procID, &activeJob);
		printf("job %lu @ proc %d\n", activeJob.pid, (int)procID);
		// set all the stuff up
		TTD.yarn_current = (yarn*)activeJob.pid;
		TTD.yarn_current->meta.context.uc_link = &(TTD.sched_context);
		// swap contexts
		rc = swapcontext(&(TTD.sched_context), &(TTD.yarn_current->meta.context));
		// check it actually worked
		if (rc == -1)
			perror("swapcontext failed");
		// set the runtime
		activeJob.runtime = TTD.runtime_remaining;
		// if we're unscheduling, free up memory
		if (TTD.runtime_remaining == SCHEDULER_UNSCHEDULE)
		{
			TTD.yarn_current->prev->next = TTD.yarn_current->next;
			TTD.yarn_current->next->prev = TTD.yarn_current->prev;
			deallocate_stack(&(TTD.yarn_current->meta.context));
			free(TTD.yarn_current);
		}
	}
	deallocate_stack(&(TTD.sched_context));
}

// number of parallel processing cores, for the moment assume 2
#ifdef YARNS_ENABLE_SMP
static unsigned long numprocs ()<commit_msg>Removed the meta structure in yarn.c.<commit_after>#include "yarn.h"
#define _XOPEN_SOURCE
#include <ucontext.h>
#include <stdlib.h>
#include "smp_scheduler.h"
#include <assert.h>
#include "config.h"
#include <stdio.h>
#include "pages.h"
#include <pthread.h>

#define STACK_SIZE (YARNS_STACK_PAGES*4096)

typedef struct _yarn
{
	ucontext_t context;
	yarn_t next;
	yarn_t prev;
} yarn;

static yarn* yarn_list = 0;
typedef struct _yarn_thread_data
{
	ucontext_t sched_context;
	yarn* yarn_current;
	unsigned long runtime_remaining;
} yarn_thread_data;
#ifdef YARNS_ENABLE_SMP
pthread_key_t _ttd;
#define TTD (*(yarn_thread_data*)(pthread_getspecific(_ttd)))
#define TTDINIT() { int rc; yarn_thread_data* ttd = (yarn_thread_data*)malloc(sizeof(yarn_thread_data)); ttd->yarn_current = NULL; ttd->runtime_remaining = 0; rc = pthread_key_create(&_ttd, 0); assert(rc == 0); }
#else
static yarn_thread_data _ttd;
#define TTD _ttd
#define TTDINIT() { _ttd.yarn_current = 0; _ttd.runtime_remaining = 0; }
#endif

#if YARNS_SELECTED_TARGET == YARNS_TARGET_MACH
#define BASE_CONTEXT_NEEDS_STACK
#endif

static void yarn_check_stack ( const void* base )
{
	// make sure that base is page-aligned (ie a multiple of 4096)
	unsigned long ul = (unsigned long)base;
	if (ul & 4095 || !ul)
	{
		printf("ul&4095=%d\n", (int)(ul % 4096));
		assert(0);
	}
}

static void yarn_launcher ( yarn* active_yarn, void (*routine)(void*), void* udata )
{
	// basically a bootstrap routine for each yarn which runs the routine then cleans up
	routine(udata);
	TTD.runtime_remaining = SCHEDULER_UNSCHEDULE;
}

static void allocate_stack ( ucontext_t* ctx )
{
	ctx->uc_stack.ss_size = STACK_SIZE;
	ctx->uc_stack.ss_sp = page_allocate(STACK_SIZE);
	assert(ctx->uc_stack.ss_sp);
	ctx->uc_stack.ss_flags = 0;
	yarn_check_stack(ctx->uc_stack.ss_sp);
}

static void deallocate_stack ( ucontext_t* ctx )
{
	page_deallocate(ctx->uc_stack.ss_sp, STACK_SIZE);
}

static void basic_launch ()
{
	puts("basic_launch");
	_Exit(0);
}

int __make_trap = 1; // this traps the odd situation where makecontext doesn't work and we get random code jumping in here

static void list_insert ( yarn* active_yarn )
{
	if (yarn_list)
	{
		if (yarn_list->prev)
		{
			active_yarn->prev = yarn_list->prev;
			active_yarn->next = yarn_list;
			active_yarn->prev->next = active_yarn;
			yarn_list->prev = active_yarn;
		}
		else
		{
			yarn_list->prev = yarn_list->next = active_yarn;
			active_yarn->prev = active_yarn->next = yarn_list;
		}
	}
	else
	{
		active_yarn->next = 0;
		active_yarn->prev = 0;
	}
	yarn_list = active_yarn;
}

yarn_t yarn_new ( void (*routine)(void*), void* udata )
{
	// grab memory
	yarn* active_yarn;
	active_yarn = (yarn*)malloc(sizeof(yarn));
	assert(active_yarn);
	// set up stack and such
	allocate_stack(&(active_yarn->context));
	// prepare the context
	__make_trap = 0;
	getcontext(&active_yarn->context);
	assert(__make_trap == 0);
	__make_trap = 1;
	// insert it into the yarn list
	list_insert(active_yarn);
	// run getcontext & makecontext to direct it over to the bootstrap
	//makecontext(&(active_yarn->context), (void (*)())yarn_launcher, 3, active_yarn, routine, udata);
	makecontext(&(active_yarn->context), basic_launch, 0);
	return (yarn_t)active_yarn;
}

void yarn_yield ( yarn_t target )
{
	// ignore target for now
	TTD.runtime_remaining = 1;
	// pop back over to the scheduler
	swapcontext(&(TTD.yarn_current->context), &(TTD.sched_context));
}

static void yarn_processor ( unsigned long procID )
{
	// this is the main routine run by each thread
	volatile int breakProcessor = 0;
	int rc;
	// init the thread yarn data
	TTDINIT();
	// make sure it initted properly
	assert(&TTD);
	// repeatedly ask the scheduler for the next job
	scheduler_job activeJob;
#ifdef BASE_CONTEXT_NEEDS_STACK
	allocate_stack(&(TTD.sched_context));
#endif
	activeJob.pid = 0;
	activeJob.runtime = 0;
	activeJob.data = 0;
	while (!breakProcessor)
	{
		smp_sched_select(procID, &activeJob);
		printf("job %lu @ proc %d\n", activeJob.pid, (int)procID);
		// set all the stuff up
		TTD.yarn_current = (yarn*)activeJob.pid;
		TTD.yarn_current->context.uc_link = &(TTD.sched_context);
		// swap contexts
		rc = swapcontext(&(TTD.sched_context), &(TTD.yarn_current->context));
		// check it actually worked
		if (rc == -1)
			perror("swapcontext failed");
		// set the runtime
		activeJob.runtime = TTD.runtime_remaining;
		// if we're unscheduling, free up memory
		if (TTD.runtime_remaining == SCHEDULER_UNSCHEDULE)
		{
			TTD.yarn_current->prev->next = TTD.yarn_current->next;
			TTD.yarn_current->next->prev = TTD.yarn_current->prev;
			deallocate_stack(&(TTD.yarn_current->context));
			free(TTD.yarn_current);
		}
	}
	deallocate_stack(&(TTD.sched_context));
}

// number of parallel processing cores, for the moment assume 2
#ifdef YARNS_ENABLE_SMP
static unsigned long numprocs ()
{'fraction_non_alphanumeric': 0.1271411092985318, 'fraction_numerical': 0.00897226753670473, 'mean_word_length': 4.756455399061033, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 83, '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': '837959', 'n_tokens_mistral': 3982, 'n_tokens_neox': 3727, 'n_words': 858}