taisei/src/coroutine/cotask_internal.h
2024-05-17 14:11:48 +02:00

169 lines
3.5 KiB
C

/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2024, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2024, Andrei Alexeyev <akari@taisei-project.org>.
*/
#pragma once
#include "taisei.h"
#include "cotask.h"
#ifdef __EMSCRIPTEN__
#define CO_STACK_SIZE (64 * 1024)
#else
#define CO_STACK_SIZE (256 * 1024)
#endif
#ifdef CO_TASK_DEBUG
#define TASK_DEBUG(...) log_debug(__VA_ARGS__)
extern size_t _cotask_debug_event_id;
#define TASK_DEBUG_EVENT(ev) uint64_t ev = _cotask_debug_event_id++
#else
#define TASK_DEBUG(...) ((void)0)
#define TASK_DEBUG_EVENT(ev) ((void)0)
#endif
#ifdef DEBUG
#define CO_TASK_STATS
#endif
#ifdef ADDRESS_SANITIZER
#include <sanitizer/asan_interface.h>
#else
#define ASAN_UNPOISON_MEMORY_REGION(addr, size) ((void)0)
#endif
#define MEM_AREA_SIZE (1 << 12)
#define MEM_ALLOC_ALIGNMENT alignof(max_align_t)
#define MEM_ALIGN_SIZE(x) (x + (MEM_ALLOC_ALIGNMENT - 1)) & ~(MEM_ALLOC_ALIGNMENT - 1)
enum {
COTASK_WAIT_NONE,
COTASK_WAIT_DELAY,
COTASK_WAIT_EVENT,
COTASK_WAIT_SUBTASKS,
};
typedef struct CoTaskData CoTaskData;
struct CoTask {
LIST_INTERFACE(CoTask);
koishi_coroutine_t ko;
// Pointer to a control structure on the coroutine's stack
CoTaskData *data;
uint32_t unique_id;
const char *name;
char _end[0];
#ifdef CO_TASK_DEBUG
char debug_label[256];
#endif
};
#ifdef CO_TASK_STATS
typedef struct CoTaskStats {
size_t num_tasks_allocated;
size_t num_tasks_in_use;
size_t num_switches_this_frame;
size_t peak_stack_usage;
} CoTaskStats;
extern CoTaskStats cotask_stats;
#define STAT_VAL(name) (cotask_stats.name)
#define STAT_VAL_SET(name, value) ((cotask_stats.name) = (value))
// enable stack usage tracking (loose)
#ifndef _WIN32
// NOTE: disabled by default because of heavy performance overhead under ASan
// #define CO_TASK_STATS_STACK
#endif
#else // CO_TASK_STATS
#define STAT_VAL(name) ((void)0)
#define STAT_VAL_SET(name, value) ((void)0)
#endif // CO_TASK_STATS
#define STAT_VAL_ADD(name, value) STAT_VAL_SET(name, STAT_VAL(name) + (value))
typedef struct CoTaskHeapMemChunk {
struct CoTaskHeapMemChunk *next;
alignas(MEM_ALLOC_ALIGNMENT) char data[];
} CoTaskHeapMemChunk;
struct CoTaskData {
LIST_INTERFACE(CoTaskData);
CoTask *task;
CoSched *sched;
CoTaskData *master; // AKA supertask
LIST_ANCHOR(CoTaskData) slaves; // AKA subtasks
BoxedEntity bound_ent;
CoTaskEvents events;
bool finalizing;
struct {
CoWaitResult result;
union {
struct {
int remaining;
} delay;
struct {
CoEvent *pevent;
CoEventSnapshot snapshot;
} event;
};
uint wait_type;
} wait;
struct {
EntityInterface *ent;
CoEvent *events;
uint num_events;
} hosted;
struct {
CoTaskHeapMemChunk *onheap_alloc_head;
char *onstack_alloc_head;
alignas(MEM_ALLOC_ALIGNMENT) char onstack_alloc_area[MEM_AREA_SIZE];
} mem;
};
typedef struct CoTaskInitData {
CoTask *task;
CoSched *sched;
CoTaskFunc func;
void *func_arg;
size_t func_arg_size;
CoTaskData *master_task_data;
} CoTaskInitData;
void cotask_global_init(void);
void cotask_global_shutdown(void);
CoTask *cotask_new_internal(koishi_entrypoint_t entry_point);
void *cotask_resume_internal(CoTask *task, void *arg);
CoTask *cotask_unbox_notnull(BoxedTask box);
void cotask_force_finish(CoTask *task);
void *cotask_entry(void *varg);
attr_returns_nonnull attr_nonnull_all
INLINE CoTaskData *cotask_get_data(CoTask *task) {
CoTaskData *data = task->data;
assume(data != NULL);
assume(data->task == task);
return data;
}