feat: publish Android 1.0.1 candidate source and acceptance evidence
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-aide.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2022 - 2024 everyone.
|
||||
Description : Aide
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "kern/task/hev-task-private.h"
|
||||
#include "kern/io/hev-task-io-reactor.h"
|
||||
#include "lib/io/basic/hev-task-io.h"
|
||||
|
||||
#include "hev-task-aide.h"
|
||||
|
||||
static pthread_t thread;
|
||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static HevTaskIOReactor *reactor;
|
||||
|
||||
static void *
|
||||
hev_task_aide_entry (void *data)
|
||||
{
|
||||
for (;;) {
|
||||
HevTaskIOReactorWaitEvent events[256];
|
||||
int i, count;
|
||||
|
||||
count = hev_task_io_reactor_wait (reactor, events, 256, -1);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
HevTaskAideWork *work;
|
||||
unsigned int revents;
|
||||
|
||||
work = hev_task_io_reactor_wait_event_get_data (&events[i]);
|
||||
revents = hev_task_io_reactor_wait_event_get_events (&events[i]);
|
||||
|
||||
work->handler (revents, work->data);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
hev_task_aide_init (void)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
if (reactor)
|
||||
return 0;
|
||||
|
||||
pthread_mutex_lock (&mutex);
|
||||
if (!reactor) {
|
||||
reactor = hev_task_io_reactor_new ();
|
||||
if (!reactor) {
|
||||
res = -1;
|
||||
} else {
|
||||
res = pthread_create (&thread, NULL, hev_task_aide_entry, NULL);
|
||||
if (res != 0)
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock (&mutex);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
hev_task_aide_add (HevTaskAideWork *work)
|
||||
{
|
||||
HevTaskIOReactorSetupEvent revents[HEV_TASK_IO_REACTOR_EVENT_GEN_MAX];
|
||||
int count;
|
||||
|
||||
count = hev_task_io_reactor_setup_event_fd_gen (
|
||||
revents, work->fd, HEV_TASK_IO_REACTOR_OP_ADD, work->events, work);
|
||||
|
||||
return hev_task_io_reactor_setup (reactor, revents, count);
|
||||
}
|
||||
|
||||
int
|
||||
hev_task_aide_del (HevTaskAideWork *work)
|
||||
{
|
||||
HevTaskIOReactorSetupEvent revents[HEV_TASK_IO_REACTOR_EVENT_GEN_MAX];
|
||||
int count;
|
||||
|
||||
count = hev_task_io_reactor_setup_event_fd_gen (
|
||||
revents, work->fd, HEV_TASK_IO_REACTOR_OP_DEL, 0, NULL);
|
||||
|
||||
return hev_task_io_reactor_setup (reactor, revents, count);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-aide.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2022 everyone.
|
||||
Description : Aide
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_AIDE_H__
|
||||
#define __HEV_TASK_AIDE_H__
|
||||
|
||||
typedef struct _HevTaskAideWork HevTaskAideWork;
|
||||
typedef void (*HevTaskAideWorkHandler) (unsigned int revents, void *data);
|
||||
|
||||
struct _HevTaskAideWork
|
||||
{
|
||||
int fd;
|
||||
unsigned int events;
|
||||
HevTaskAideWorkHandler handler;
|
||||
void *data;
|
||||
};
|
||||
|
||||
int hev_task_aide_init (void);
|
||||
|
||||
int hev_task_aide_add (HevTaskAideWork *work);
|
||||
int hev_task_aide_del (HevTaskAideWork *work);
|
||||
|
||||
#endif /* __HEV_TASK_AIDE_H__ */
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-system-private.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2017 - 2025 everyone.
|
||||
Description :
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_SYSTEM_PRIVATE_H__
|
||||
#define __HEV_TASK_SYSTEM_PRIVATE_H__
|
||||
|
||||
#include <time.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "hev-task-system.h"
|
||||
#include "kern/task/hev-task.h"
|
||||
#include "kern/task/hev-task-private.h"
|
||||
#include "kern/time/hev-task-timer.h"
|
||||
#include "kern/io/hev-task-io-reactor.h"
|
||||
#include "lib/list/hev-list.h"
|
||||
#include "lib/dns/hev-task-dns-proxy.h"
|
||||
#include "lib/rbtree/hev-rbtree-cached.h"
|
||||
#include "lib/misc/hev-task-stack-detector.h"
|
||||
|
||||
#define CLOCK_NONE (-1)
|
||||
#define HEV_TASK_RUN_SCHEDULER HEV_TASK_YIELD_COUNT
|
||||
#define PRIORITY_COUNT (HEV_TASK_PRIORITY_MAX - HEV_TASK_PRIORITY_MIN + 1)
|
||||
|
||||
typedef struct _HevTaskSystemContext HevTaskSystemContext;
|
||||
|
||||
enum
|
||||
{
|
||||
HEV_TASK_SCHED_SWITCH = HEV_TASK_YIELD,
|
||||
HEV_TASK_SCHED_WAITIO = HEV_TASK_WAITIO,
|
||||
HEV_TASK_SCHED_REMOVE = HEV_TASK_YIELD_COUNT,
|
||||
};
|
||||
|
||||
struct _HevTaskSystemContext
|
||||
{
|
||||
unsigned int total_task_count;
|
||||
unsigned int running_task_count;
|
||||
|
||||
HevTaskTimer *timer;
|
||||
HevTaskIOReactor *reactor;
|
||||
HevTaskDNSProxy *dns_proxy;
|
||||
HevTaskStackDetector *stack_detector;
|
||||
|
||||
HevTask *current_task;
|
||||
HevRBTreeCached running_tasks;
|
||||
|
||||
struct timespec sched_time;
|
||||
|
||||
jmp_buf kernel_context;
|
||||
|
||||
HevList all_tasks;
|
||||
};
|
||||
|
||||
void hev_task_system_schedule (HevTaskYieldType type);
|
||||
void hev_task_system_wakeup_task (HevTask *task);
|
||||
void hev_task_system_run_new_task (HevTask *task);
|
||||
void hev_task_system_kill_current_task (void);
|
||||
|
||||
void hev_task_system_wakeup_task_with_context (HevTaskSystemContext *ctx,
|
||||
HevTask *task);
|
||||
|
||||
HevTaskSystemContext *hev_task_system_get_context (void);
|
||||
|
||||
#endif /* __HEV_TASK_SYSTEM_PRIVATE_H__ */
|
||||
+281
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-system-schedule.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2017 - 2025 everyone.
|
||||
Description :
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
/* Disable signal stack check in longjmp */
|
||||
#ifdef _FORTIFY_SOURCE
|
||||
#undef _FORTIFY_SOURCE
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "hev-task-system.h"
|
||||
#include "hev-task-system-private.h"
|
||||
#include "kern/task/hev-task-private.h"
|
||||
#include "kern/task/hev-task-executer.h"
|
||||
#include "kern/io/hev-task-io-reactor.h"
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
|
||||
static inline void
|
||||
hev_task_system_get_clock_time (struct timespec *ts)
|
||||
{
|
||||
#if CONFIG_SCHED_CLOCK != CLOCK_NONE
|
||||
if (-1 == clock_gettime (CONFIG_SCHED_CLOCK, ts))
|
||||
abort ();
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_task_system_update_sched_key (HevTaskSystemContext *ctx)
|
||||
{
|
||||
HevTask *curr_task = ctx->current_task;
|
||||
uint64_t runtime = 1;
|
||||
|
||||
#if CONFIG_SCHED_CLOCK != CLOCK_NONE
|
||||
struct timespec curr_time;
|
||||
time_t sec;
|
||||
long nsec;
|
||||
|
||||
hev_task_system_get_clock_time (&curr_time);
|
||||
|
||||
sec = curr_time.tv_sec - ctx->sched_time.tv_sec;
|
||||
nsec = curr_time.tv_nsec - ctx->sched_time.tv_nsec;
|
||||
if (nsec < 0) {
|
||||
sec--;
|
||||
nsec += 1000000000L;
|
||||
}
|
||||
|
||||
runtime += (uint64_t)sec * 1000000000UL + nsec;
|
||||
#endif
|
||||
|
||||
curr_task->sched_key += runtime * curr_task->priority;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_task_system_update_sched_time (HevTaskSystemContext *ctx)
|
||||
{
|
||||
hev_task_system_get_clock_time (&ctx->sched_time);
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
hev_task_system_get_min_sched_key (HevTaskSystemContext *ctx)
|
||||
{
|
||||
HevRBTreeNode *sched_node;
|
||||
|
||||
sched_node = hev_rbtree_cached_first (&ctx->running_tasks);
|
||||
if (sched_node) {
|
||||
HevTask *task = container_of (sched_node, HevTask, sched_node);
|
||||
return task->sched_key;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_hev_task_system_insert_task (HevRBTreeCached *tree, HevTask *task)
|
||||
{
|
||||
HevRBTreeNode **new = &tree->base.root, *parent = NULL;
|
||||
int leftmost = 1;
|
||||
|
||||
while (*new) {
|
||||
HevTask *this = container_of (*new, HevTask, sched_node);
|
||||
|
||||
parent = *new;
|
||||
if (task->sched_key < this->sched_key) {
|
||||
new = &((*new)->left);
|
||||
} else {
|
||||
new = &((*new)->right);
|
||||
leftmost = 0;
|
||||
}
|
||||
}
|
||||
|
||||
hev_rbtree_node_link (&task->sched_node, parent, new);
|
||||
hev_rbtree_cached_insert_color (tree, &task->sched_node, leftmost);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_task_system_insert_task (HevTaskSystemContext *ctx, HevTask *task)
|
||||
{
|
||||
task->state = HEV_TASK_RUNNING;
|
||||
task->priority = task->next_priority;
|
||||
|
||||
_hev_task_system_insert_task (&ctx->running_tasks, task);
|
||||
|
||||
ctx->running_task_count++;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_task_system_reinsert_current_task (HevTaskSystemContext *ctx)
|
||||
{
|
||||
HevTask *task = ctx->current_task;
|
||||
|
||||
task->priority = task->next_priority;
|
||||
|
||||
hev_rbtree_cached_erase (&ctx->running_tasks, &task->sched_node);
|
||||
_hev_task_system_insert_task (&ctx->running_tasks, task);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_task_system_remove_current_task (HevTaskSystemContext *ctx,
|
||||
HevTaskState state)
|
||||
{
|
||||
HevTask *task = ctx->current_task;
|
||||
|
||||
task->state = state;
|
||||
|
||||
hev_rbtree_cached_erase (&ctx->running_tasks, &task->sched_node);
|
||||
|
||||
ctx->running_task_count--;
|
||||
|
||||
if (HEV_TASK_STOPPED == state) {
|
||||
ctx->total_task_count--;
|
||||
hev_task_unref (task);
|
||||
} else {
|
||||
task->sched_key = task->next_priority;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
hev_task_system_wakeup_task_with_context (HevTaskSystemContext *ctx,
|
||||
HevTask *task)
|
||||
{
|
||||
/* skip to wake up this task that is already in running */
|
||||
if (task->state == HEV_TASK_RUNNING)
|
||||
return;
|
||||
|
||||
if (task->state == HEV_TASK_STOPPED)
|
||||
abort ();
|
||||
|
||||
task->sched_key += hev_task_system_get_min_sched_key (ctx);
|
||||
|
||||
hev_task_system_insert_task (ctx, task);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_task_system_io_poll (HevTaskSystemContext *ctx, int timeout)
|
||||
{
|
||||
int i, count;
|
||||
HevTaskIOReactorWaitEvent events[1024];
|
||||
|
||||
if (timeout < 0)
|
||||
timeout = hev_task_timer_get_timeout (ctx->timer);
|
||||
|
||||
count = hev_task_io_reactor_wait (ctx->reactor, events, 1024, timeout);
|
||||
for (i = 0; i < count; i++) {
|
||||
HevTaskSchedEntity *sched_entity;
|
||||
|
||||
sched_entity = hev_task_io_reactor_wait_event_get_data (&events[i]);
|
||||
hev_task_system_wakeup_task_with_context (ctx, sched_entity->task);
|
||||
}
|
||||
|
||||
hev_task_timer_wake (ctx->timer);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_task_system_pick_current_task (HevTaskSystemContext *ctx)
|
||||
{
|
||||
HevRBTreeNode *sched_node;
|
||||
|
||||
if (ctx->running_task_count < ctx->total_task_count) {
|
||||
if (ctx->running_task_count) {
|
||||
hev_task_system_io_poll (ctx, 0);
|
||||
} else {
|
||||
do {
|
||||
hev_task_system_io_poll (ctx, -1);
|
||||
} while (!ctx->running_task_count);
|
||||
}
|
||||
}
|
||||
|
||||
sched_node = hev_rbtree_cached_first (&ctx->running_tasks);
|
||||
ctx->current_task = container_of (sched_node, HevTask, sched_node);
|
||||
}
|
||||
|
||||
void
|
||||
hev_task_system_schedule (HevTaskYieldType type)
|
||||
{
|
||||
HevTaskSystemContext *ctx = hev_task_system_get_context ();
|
||||
|
||||
if (ctx->current_task) {
|
||||
/*
|
||||
* NOTE: in task context
|
||||
* save current task context
|
||||
*/
|
||||
if (_setjmp (ctx->current_task->context))
|
||||
return; /* resume to task context */
|
||||
|
||||
/* resume to kernel context */
|
||||
_longjmp (ctx->kernel_context, type);
|
||||
}
|
||||
|
||||
/* NOTE: in kernel context */
|
||||
if (type == HEV_TASK_RUN_SCHEDULER) {
|
||||
switch (_setjmp (ctx->kernel_context)) {
|
||||
case HEV_TASK_SCHED_SWITCH:
|
||||
hev_task_system_update_sched_key (ctx);
|
||||
hev_task_system_reinsert_current_task (ctx);
|
||||
break;
|
||||
case HEV_TASK_SCHED_WAITIO:
|
||||
hev_task_system_update_sched_key (ctx);
|
||||
hev_task_system_remove_current_task (ctx, HEV_TASK_WAITING);
|
||||
break;
|
||||
case HEV_TASK_SCHED_REMOVE:
|
||||
hev_task_system_remove_current_task (ctx, HEV_TASK_STOPPED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* All tasks exited, Bye! */
|
||||
if (ctx->total_task_count == 0) {
|
||||
ctx->current_task = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* pick a task */
|
||||
hev_task_system_pick_current_task (ctx);
|
||||
|
||||
/* update schedule time */
|
||||
hev_task_system_update_sched_time (ctx);
|
||||
|
||||
/* switch to task */
|
||||
_longjmp (ctx->current_task->context, 1);
|
||||
}
|
||||
|
||||
void
|
||||
hev_task_system_wakeup_task (HevTask *task)
|
||||
{
|
||||
HevTaskSystemContext *ctx;
|
||||
|
||||
ctx = hev_task_system_get_context ();
|
||||
hev_task_system_wakeup_task_with_context (ctx, task);
|
||||
}
|
||||
|
||||
void
|
||||
hev_task_system_run_new_task (HevTask *task)
|
||||
{
|
||||
HevTaskSystemContext *ctx = hev_task_system_get_context ();
|
||||
|
||||
hev_task_execute (task, hev_task_executer);
|
||||
|
||||
if (ctx->current_task)
|
||||
task->sched_key += hev_task_system_get_min_sched_key (ctx);
|
||||
|
||||
hev_task_system_insert_task (ctx, task);
|
||||
ctx->total_task_count++;
|
||||
}
|
||||
|
||||
void
|
||||
hev_task_system_kill_current_task (void)
|
||||
{
|
||||
HevTaskSystemContext *ctx = hev_task_system_get_context ();
|
||||
|
||||
/*
|
||||
* NOTE: remove current task in kernel context, because current
|
||||
* task stack may be freed.
|
||||
*/
|
||||
_longjmp (ctx->kernel_context, HEV_TASK_SCHED_REMOVE);
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-system.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2017 - 2025 everyone.
|
||||
Description :
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
#include "lib/misc/hev-task-stack-detector.h"
|
||||
#include "mem/api/hev-memory-allocator-api.h"
|
||||
#include "mem/slice/hev-memory-allocator-slice.h"
|
||||
|
||||
#include "hev-task-system-private.h"
|
||||
|
||||
#include "hev-task-system.h"
|
||||
|
||||
static pthread_key_t key;
|
||||
static pthread_once_t key_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
static void
|
||||
pthread_key_creator (void)
|
||||
{
|
||||
pthread_key_create (&key, NULL);
|
||||
}
|
||||
|
||||
HevTaskSystemContext *
|
||||
hev_task_system_get_context (void)
|
||||
{
|
||||
return pthread_getspecific (key);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hev_task_system_set_context (HevTaskSystemContext *context)
|
||||
{
|
||||
return pthread_setspecific (key, context);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_system_init (void)
|
||||
{
|
||||
HevMemoryAllocator *allocator = NULL;
|
||||
HevTaskSystemContext *context;
|
||||
|
||||
#ifdef ENABLE_MEMALLOC_SLICE
|
||||
allocator = hev_memory_allocator_slice_new ();
|
||||
#endif
|
||||
allocator = hev_memory_allocator_set_default (allocator);
|
||||
if (allocator)
|
||||
hev_memory_allocator_unref (allocator);
|
||||
|
||||
pthread_once (&key_once, pthread_key_creator);
|
||||
|
||||
if (hev_task_system_get_context ())
|
||||
goto exit;
|
||||
|
||||
context = hev_malloc0 (sizeof (HevTaskSystemContext));
|
||||
if (!context)
|
||||
goto exit;
|
||||
|
||||
if (hev_task_system_set_context (context) < 0)
|
||||
goto free_context;
|
||||
|
||||
context->reactor = hev_task_io_reactor_new ();
|
||||
if (!context->reactor)
|
||||
goto rest_context;
|
||||
|
||||
context->timer = hev_task_timer_new (context);
|
||||
if (!context->timer)
|
||||
goto free_reactor;
|
||||
|
||||
context->stack_detector = hev_task_stack_detector_new ();
|
||||
if (!context->stack_detector)
|
||||
goto free_timer;
|
||||
|
||||
return 0;
|
||||
|
||||
free_timer:
|
||||
hev_task_timer_destroy (context->timer);
|
||||
free_reactor:
|
||||
hev_task_io_reactor_destroy (context->reactor);
|
||||
rest_context:
|
||||
hev_task_system_set_context (NULL);
|
||||
free_context:
|
||||
hev_free (context);
|
||||
exit:
|
||||
return -1;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL void
|
||||
hev_task_system_fini (void)
|
||||
{
|
||||
HevMemoryAllocator *allocator;
|
||||
HevTaskSystemContext *context = hev_task_system_get_context ();
|
||||
|
||||
if (context->dns_proxy)
|
||||
hev_task_dns_proxy_destroy (context->dns_proxy);
|
||||
hev_task_stack_detector_destroy (context->stack_detector);
|
||||
hev_task_timer_destroy (context->timer);
|
||||
hev_task_io_reactor_destroy (context->reactor);
|
||||
hev_free (context);
|
||||
hev_task_system_set_context (NULL);
|
||||
|
||||
allocator = hev_memory_allocator_set_default (NULL);
|
||||
if (allocator)
|
||||
hev_memory_allocator_unref (allocator);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL void
|
||||
hev_task_system_run (void)
|
||||
{
|
||||
hev_task_system_schedule (HEV_TASK_RUN_SCHEDULER);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-system.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 - 2024 everyone.
|
||||
Description :
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_SYSTEM_H__
|
||||
#define __HEV_TASK_SYSTEM_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HEV_TASK_SYSTEM_MAJOR_VERSION (5)
|
||||
#define HEV_TASK_SYSTEM_MINOR_VERSION (10)
|
||||
#define HEV_TASK_SYSTEM_MICRO_VERSION (1)
|
||||
|
||||
/**
|
||||
* hev_task_system_init:
|
||||
*
|
||||
* Initialize the task system.
|
||||
*
|
||||
* Returns: When successful, returns zero. When an error occurs, returns -1.
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
int hev_task_system_init (void);
|
||||
|
||||
/**
|
||||
* hev_task_system_fini:
|
||||
*
|
||||
* Finalize the task system.
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
void hev_task_system_fini (void);
|
||||
|
||||
/**
|
||||
* hev_task_system_run:
|
||||
*
|
||||
* Run the task system.
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
void hev_task_system_run (void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_TASK_SYSTEM_H__ */
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-io-reactor-epoll.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2018 - 2025 everyone.
|
||||
Description : I/O Reactor EPoll
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mem/api/hev-memory-allocator-api.h"
|
||||
|
||||
#include "kern/io/hev-task-io-reactor.h"
|
||||
|
||||
HevTaskIOReactor *
|
||||
hev_task_io_reactor_new (void)
|
||||
{
|
||||
HevTaskIOReactor *self;
|
||||
int flags;
|
||||
|
||||
self = hev_malloc0 (sizeof (HevTaskIOReactor));
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
self->fd = epoll_create (128);
|
||||
if (self->fd < 0) {
|
||||
hev_free (self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
flags = fcntl (self->fd, F_GETFD);
|
||||
if (flags < 0) {
|
||||
hev_free (self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
flags |= FD_CLOEXEC;
|
||||
if (fcntl (self->fd, F_SETFD, flags) < 0) {
|
||||
hev_free (self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
hev_task_io_reactor_destroy (HevTaskIOReactor *self)
|
||||
{
|
||||
close (self->fd);
|
||||
hev_free (self);
|
||||
}
|
||||
|
||||
int
|
||||
hev_task_io_reactor_setup (HevTaskIOReactor *self,
|
||||
HevTaskIOReactorSetupEvent *events, int count)
|
||||
{
|
||||
int i, res = 0;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
HevTaskIOReactorSetupEvent *ev = &events[i];
|
||||
res |= epoll_ctl (self->fd, ev->op, ev->fd, &ev->event);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* defined(__linux__) */
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-io-reactor-epoll.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2018 - 2022 everyone.
|
||||
Description : I/O Reactor EPoll
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_IO_REACTOR_EPOLL_H__
|
||||
#define __HEV_TASK_IO_REACTOR_EPOLL_H__
|
||||
|
||||
#include <poll.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#define HEV_TASK_IO_REACTOR_EVENT_GEN_MAX (1)
|
||||
|
||||
typedef struct _HevTaskIOReactorSetupEvent HevTaskIOReactorSetupEvent;
|
||||
typedef struct epoll_event HevTaskIOReactorWaitEvent;
|
||||
|
||||
enum _HevTaskIOReactorEvents
|
||||
{
|
||||
HEV_TASK_IO_REACTOR_EV_RO = EPOLLIN,
|
||||
HEV_TASK_IO_REACTOR_EV_WO = EPOLLOUT,
|
||||
HEV_TASK_IO_REACTOR_EV_ER = EPOLLERR,
|
||||
};
|
||||
|
||||
enum _HevTaskIOReactorOperation
|
||||
{
|
||||
HEV_TASK_IO_REACTOR_OP_ADD = EPOLL_CTL_ADD,
|
||||
HEV_TASK_IO_REACTOR_OP_MOD = EPOLL_CTL_MOD,
|
||||
HEV_TASK_IO_REACTOR_OP_DEL = EPOLL_CTL_DEL,
|
||||
};
|
||||
|
||||
struct _HevTaskIOReactorSetupEvent
|
||||
{
|
||||
HevTaskIOReactorOperation op;
|
||||
|
||||
int fd;
|
||||
struct epoll_event event;
|
||||
};
|
||||
|
||||
static inline int
|
||||
hev_task_io_reactor_wait (HevTaskIOReactor *self,
|
||||
HevTaskIOReactorWaitEvent *events, int count,
|
||||
int timeout)
|
||||
{
|
||||
return epoll_wait (self->fd, events, count, timeout);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_task_io_reactor_setup_event_set (HevTaskIOReactorSetupEvent *event, int fd,
|
||||
HevTaskIOReactorOperation op,
|
||||
unsigned int events, void *data)
|
||||
{
|
||||
event->op = op;
|
||||
event->fd = fd;
|
||||
event->event.events = events | EPOLLET;
|
||||
event->event.data.ptr = data;
|
||||
}
|
||||
|
||||
static inline int
|
||||
hev_task_io_reactor_setup_event_fd_gen (HevTaskIOReactorSetupEvent *events,
|
||||
int fd, HevTaskIOReactorOperation op,
|
||||
unsigned int poll_events, void *data)
|
||||
{
|
||||
HevTaskIOReactorEvents reactor_events = 0;
|
||||
|
||||
if (poll_events & POLLIN)
|
||||
reactor_events |= HEV_TASK_IO_REACTOR_EV_RO;
|
||||
if (poll_events & POLLOUT)
|
||||
reactor_events |= HEV_TASK_IO_REACTOR_EV_WO;
|
||||
if (poll_events & POLLERR)
|
||||
reactor_events |= HEV_TASK_IO_REACTOR_EV_ER;
|
||||
|
||||
hev_task_io_reactor_setup_event_set (events, fd, op, reactor_events, data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
hev_task_io_reactor_setup_event_whandle_gen (HevTaskIOReactorSetupEvent *events,
|
||||
void *handle,
|
||||
HevTaskIOReactorOperation op,
|
||||
void *data)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
hev_task_io_reactor_wait_event_get_events (HevTaskIOReactorWaitEvent *event)
|
||||
{
|
||||
return event->events;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
hev_task_io_reactor_wait_event_get_data (HevTaskIOReactorWaitEvent *event)
|
||||
{
|
||||
return event->data.ptr;
|
||||
}
|
||||
|
||||
#endif /* __HEV_TASK_IO_REACTOR_EPOLL_H__ */
|
||||
@@ -0,0 +1,344 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-io-reactor-iocp.c
|
||||
Author : hev <r@hev.cc>
|
||||
Copyright : Copyright (c) 2025 hev
|
||||
Description : I/O Reactor IOCP
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#if defined(__MSYS__)
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
#include "mem/api/hev-memory-allocator-api.h"
|
||||
|
||||
#include "kern/io/hev-task-io-reactor.h"
|
||||
|
||||
typedef struct _HevTaskIOReactorIOCPNode HevTaskIOReactorIOCPNode;
|
||||
|
||||
struct _HevTaskIOReactorIOCPNode
|
||||
{
|
||||
HevRBTreeNode base;
|
||||
|
||||
int ref_count;
|
||||
int events;
|
||||
|
||||
long handle;
|
||||
void *data;
|
||||
|
||||
void *ihandle;
|
||||
void *ehandle;
|
||||
void *whandle;
|
||||
};
|
||||
|
||||
static HevTaskIOReactorIOCPNode *
|
||||
hev_task_io_reactor_iocp_node_new (void)
|
||||
{
|
||||
HevTaskIOReactorIOCPNode *node;
|
||||
atomic_int *rcp;
|
||||
|
||||
node = calloc (1, sizeof (HevTaskIOReactorIOCPNode));
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
rcp = (atomic_int *)&node->ref_count;
|
||||
atomic_store_explicit (rcp, 1, memory_order_relaxed);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static void
|
||||
hev_task_io_reactor_iocp_node_ref (HevTaskIOReactorIOCPNode *node)
|
||||
{
|
||||
atomic_int *rcp = (atomic_int *)&node->ref_count;
|
||||
|
||||
atomic_fetch_add_explicit (rcp, 1, memory_order_relaxed);
|
||||
}
|
||||
|
||||
static void
|
||||
hev_task_io_reactor_iocp_node_unref (HevTaskIOReactorIOCPNode *node)
|
||||
{
|
||||
atomic_int *rcp = (atomic_int *)&node->ref_count;
|
||||
int rc;
|
||||
|
||||
rc = atomic_fetch_sub_explicit (rcp, 1, memory_order_relaxed);
|
||||
if (rc > 1)
|
||||
return;
|
||||
|
||||
assert (rc >= 1);
|
||||
free (node);
|
||||
}
|
||||
|
||||
static int
|
||||
hev_task_io_reactor_iocp_insert (HevTaskIOReactorIOCP *self,
|
||||
HevTaskIOReactorIOCPNode *node)
|
||||
{
|
||||
HevRBTreeNode **new = &self->tree.root, *parent = NULL;
|
||||
|
||||
while (*new) {
|
||||
HevTaskIOReactorIOCPNode *this;
|
||||
|
||||
this = container_of (*new, HevTaskIOReactorIOCPNode, base);
|
||||
parent = *new;
|
||||
|
||||
if (this->handle < node->handle)
|
||||
new = &((*new)->left);
|
||||
else if (this->handle > node->handle)
|
||||
new = &((*new)->right);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
hev_rbtree_node_link (&node->base, parent, new);
|
||||
hev_rbtree_insert_color (&self->tree, &node->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static HevTaskIOReactorIOCPNode *
|
||||
hev_task_io_reactor_iocp_lookup (HevTaskIOReactorIOCP *self, long handle)
|
||||
{
|
||||
HevRBTreeNode *node = self->tree.root;
|
||||
|
||||
while (node) {
|
||||
HevTaskIOReactorIOCPNode *this;
|
||||
|
||||
this = container_of (node, HevTaskIOReactorIOCPNode, base);
|
||||
|
||||
if (this->handle < handle)
|
||||
node = node->left;
|
||||
else if (this->handle > handle)
|
||||
node = node->right;
|
||||
else
|
||||
return this;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static VOID CALLBACK
|
||||
hev_task_io_reactor_iocp_handler (void *data, BOOLEAN fired)
|
||||
{
|
||||
HevTaskIOReactorIOCPNode *node = data;
|
||||
int res;
|
||||
|
||||
if (fired)
|
||||
return;
|
||||
|
||||
if (node->handle != (long)node->ehandle) {
|
||||
WSANETWORKEVENTS events;
|
||||
|
||||
res = WSAEnumNetworkEvents (node->handle, node->ehandle, &events);
|
||||
if (res || !events.lNetworkEvents)
|
||||
return;
|
||||
node->events = events.lNetworkEvents;
|
||||
}
|
||||
|
||||
hev_task_io_reactor_iocp_node_ref (node);
|
||||
res = PostQueuedCompletionStatus (node->ihandle, 1, 0, (LPOVERLAPPED)node);
|
||||
if (!res)
|
||||
hev_task_io_reactor_iocp_node_unref (node);
|
||||
}
|
||||
|
||||
static int
|
||||
hev_task_io_reactor_iocp_add (HevTaskIOReactorIOCP *self,
|
||||
HevTaskIOReactorSetupEvent *event)
|
||||
{
|
||||
HevTaskIOReactorIOCPNode *node;
|
||||
int res;
|
||||
|
||||
node = hev_task_io_reactor_iocp_lookup (self, event->handle);
|
||||
if (node)
|
||||
goto exit;
|
||||
|
||||
node = hev_task_io_reactor_iocp_node_new ();
|
||||
if (!node)
|
||||
goto exit;
|
||||
|
||||
if (event->events) {
|
||||
long events;
|
||||
|
||||
node->ehandle = CreateEventA (NULL, FALSE, FALSE, NULL);
|
||||
if (!node->ehandle)
|
||||
goto free_node;
|
||||
|
||||
events = event->events | HEV_TASK_IO_REACTOR_EV_ER;
|
||||
res = WSAEventSelect (event->handle, node->ehandle, events);
|
||||
if (res)
|
||||
goto free_event;
|
||||
} else {
|
||||
node->ehandle = (void *)event->handle;
|
||||
}
|
||||
|
||||
node->data = event->data;
|
||||
node->handle = event->handle;
|
||||
node->ihandle = self->base.handle;
|
||||
|
||||
res = RegisterWaitForSingleObject (&node->whandle, node->ehandle,
|
||||
hev_task_io_reactor_iocp_handler, node,
|
||||
INFINITE, WT_EXECUTEINPERSISTENTTHREAD);
|
||||
if (!res)
|
||||
goto free_event;
|
||||
|
||||
hev_task_io_reactor_iocp_insert (self, node);
|
||||
|
||||
return 0;
|
||||
|
||||
free_event:
|
||||
if (event->handle != (long)node->ehandle)
|
||||
WSACloseEvent (node->ehandle);
|
||||
free_node:
|
||||
hev_task_io_reactor_iocp_node_unref (node);
|
||||
exit:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_task_io_reactor_iocp_mod (HevTaskIOReactorIOCP *self,
|
||||
HevTaskIOReactorSetupEvent *event)
|
||||
{
|
||||
HevTaskIOReactorIOCPNode *node;
|
||||
|
||||
node = hev_task_io_reactor_iocp_lookup (self, event->handle);
|
||||
if (!node)
|
||||
return -1;
|
||||
|
||||
if (node->handle != (long)node->ehandle && event->events) {
|
||||
long events = event->events | HEV_TASK_IO_REACTOR_EV_ER;
|
||||
int res = WSAEventSelect (node->handle, node->ehandle, events);
|
||||
if (res)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_task_io_reactor_iocp_del (HevTaskIOReactorIOCP *self,
|
||||
HevTaskIOReactorSetupEvent *event)
|
||||
{
|
||||
HevTaskIOReactorIOCPNode *node;
|
||||
int res;
|
||||
|
||||
node = hev_task_io_reactor_iocp_lookup (self, event->handle);
|
||||
if (!node)
|
||||
return -1;
|
||||
|
||||
res = UnregisterWaitEx (node->whandle, INVALID_HANDLE_VALUE);
|
||||
if (node->handle != (long)node->ehandle)
|
||||
res &= WSACloseEvent (node->ehandle);
|
||||
if (!res)
|
||||
return -1;
|
||||
|
||||
node->ehandle = NULL;
|
||||
node->whandle = NULL;
|
||||
hev_rbtree_erase (&self->tree, &node->base);
|
||||
hev_task_io_reactor_iocp_node_unref (node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
HevTaskIOReactor *
|
||||
hev_task_io_reactor_new (void)
|
||||
{
|
||||
HevTaskIOReactorIOCP *self;
|
||||
HANDLE handle;
|
||||
|
||||
self = hev_malloc0 (sizeof (HevTaskIOReactorIOCP));
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
handle = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL, 0, 0);
|
||||
if (!handle) {
|
||||
hev_free (self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_init (&self->mutex, NULL);
|
||||
self->base.handle = handle;
|
||||
|
||||
return &self->base;
|
||||
}
|
||||
|
||||
void
|
||||
hev_task_io_reactor_destroy (HevTaskIOReactor *_self)
|
||||
{
|
||||
HevTaskIOReactorIOCP *self = (HevTaskIOReactorIOCP *)_self;
|
||||
|
||||
CloseHandle (_self->handle);
|
||||
pthread_mutex_destroy (&self->mutex);
|
||||
hev_free (self);
|
||||
}
|
||||
|
||||
int
|
||||
hev_task_io_reactor_setup (HevTaskIOReactor *_self,
|
||||
HevTaskIOReactorSetupEvent *events, int count)
|
||||
{
|
||||
HevTaskIOReactorIOCP *self = (HevTaskIOReactorIOCP *)_self;
|
||||
int res = -1;
|
||||
|
||||
assert (count <= HEV_TASK_IO_REACTOR_EVENT_GEN_MAX);
|
||||
|
||||
if (!events || count <= 0)
|
||||
return res;
|
||||
|
||||
pthread_mutex_lock (&self->mutex);
|
||||
|
||||
switch (events->op) {
|
||||
case HEV_TASK_IO_REACTOR_OP_ADD:
|
||||
res = hev_task_io_reactor_iocp_add (self, events);
|
||||
break;
|
||||
case HEV_TASK_IO_REACTOR_OP_MOD:
|
||||
res = hev_task_io_reactor_iocp_mod (self, events);
|
||||
break;
|
||||
case HEV_TASK_IO_REACTOR_OP_DEL:
|
||||
res = hev_task_io_reactor_iocp_del (self, events);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock (&self->mutex);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
hev_task_io_reactor_wait (HevTaskIOReactor *self,
|
||||
HevTaskIOReactorWaitEvent *events, int count,
|
||||
int timeout)
|
||||
{
|
||||
HevTaskIOReactorIOCPNode *node;
|
||||
OVERLAPPED *overlap = NULL;
|
||||
ULONG_PTR key = 0;
|
||||
DWORD bytes = 0;
|
||||
int res;
|
||||
|
||||
if (count <= 0)
|
||||
return -1;
|
||||
|
||||
retry:
|
||||
res = GetQueuedCompletionStatus (self->handle, &bytes, &key, &overlap,
|
||||
timeout);
|
||||
if (!res) {
|
||||
if (GetLastError () == WAIT_TIMEOUT)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
node = (HevTaskIOReactorIOCPNode *)overlap;
|
||||
events->events = node->events;
|
||||
events->data = node->data;
|
||||
res = node->ehandle && node->whandle;
|
||||
hev_task_io_reactor_iocp_node_unref (node);
|
||||
|
||||
if (!res)
|
||||
goto retry;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* defined(__MSYS__) */
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-io-reactor-iocp.h
|
||||
Author : hev <r@hev.cc>
|
||||
Copyright : Copyright (c) 2025 hev
|
||||
Description : I/O Reactor IOCP
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_IO_REACTOR_IOCP_H__
|
||||
#define __HEV_TASK_IO_REACTOR_IOCP_H__
|
||||
|
||||
#include <io.h>
|
||||
#include <poll.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "lib/rbtree/hev-rbtree.h"
|
||||
#include "lib/misc/hev-windows-api.h"
|
||||
|
||||
#define HEV_TASK_IO_REACTOR_EVENT_GEN_MAX (1)
|
||||
|
||||
typedef struct _HevTaskIOReactorIOCP HevTaskIOReactorIOCP;
|
||||
typedef struct _HevTaskIOReactorSetupEvent HevTaskIOReactorSetupEvent;
|
||||
typedef struct _HevTaskIOReactorWaitEvent HevTaskIOReactorWaitEvent;
|
||||
|
||||
struct _HevTaskIOReactorIOCP
|
||||
{
|
||||
HevTaskIOReactor base;
|
||||
|
||||
HevRBTree tree;
|
||||
pthread_mutex_t mutex;
|
||||
};
|
||||
|
||||
enum _HevTaskIOReactorEvents
|
||||
{
|
||||
HEV_TASK_IO_REACTOR_EV_RO = FD_READ | FD_ACCEPT,
|
||||
HEV_TASK_IO_REACTOR_EV_WO = FD_WRITE | FD_CONNECT,
|
||||
HEV_TASK_IO_REACTOR_EV_ER = FD_CLOSE,
|
||||
};
|
||||
|
||||
enum _HevTaskIOReactorOperation
|
||||
{
|
||||
HEV_TASK_IO_REACTOR_OP_ADD,
|
||||
HEV_TASK_IO_REACTOR_OP_MOD,
|
||||
HEV_TASK_IO_REACTOR_OP_DEL,
|
||||
};
|
||||
|
||||
struct _HevTaskIOReactorSetupEvent
|
||||
{
|
||||
HevTaskIOReactorOperation op;
|
||||
|
||||
long handle;
|
||||
int events;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct _HevTaskIOReactorWaitEvent
|
||||
{
|
||||
int events;
|
||||
void *data;
|
||||
};
|
||||
|
||||
int hev_task_io_reactor_wait (HevTaskIOReactor *self,
|
||||
HevTaskIOReactorWaitEvent *events, int count,
|
||||
int timeout);
|
||||
|
||||
static inline void
|
||||
hev_task_io_reactor_setup_event_set (HevTaskIOReactorSetupEvent *event,
|
||||
long handle, HevTaskIOReactorOperation op,
|
||||
unsigned int events, void *data)
|
||||
{
|
||||
event->op = op;
|
||||
event->handle = handle;
|
||||
event->events = events;
|
||||
event->data = data;
|
||||
}
|
||||
|
||||
static inline int
|
||||
hev_task_io_reactor_setup_event_fd_gen (HevTaskIOReactorSetupEvent *events,
|
||||
long fd, HevTaskIOReactorOperation op,
|
||||
unsigned int poll_events, void *data)
|
||||
{
|
||||
HevTaskIOReactorEvents reactor_events = 0;
|
||||
|
||||
if (poll_events & POLLIN)
|
||||
reactor_events |= HEV_TASK_IO_REACTOR_EV_RO;
|
||||
if (poll_events & POLLOUT)
|
||||
reactor_events |= HEV_TASK_IO_REACTOR_EV_WO;
|
||||
if (poll_events & POLLERR)
|
||||
reactor_events |= HEV_TASK_IO_REACTOR_EV_ER;
|
||||
|
||||
hev_task_io_reactor_setup_event_set (events, get_osfhandle (fd), op,
|
||||
reactor_events, data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
hev_task_io_reactor_setup_event_whandle_gen (HevTaskIOReactorSetupEvent *events,
|
||||
void *handle,
|
||||
HevTaskIOReactorOperation op,
|
||||
void *data)
|
||||
{
|
||||
hev_task_io_reactor_setup_event_set (events, (long)handle, op, 0, data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
hev_task_io_reactor_wait_event_get_events (HevTaskIOReactorWaitEvent *event)
|
||||
{
|
||||
unsigned int events = 0;
|
||||
|
||||
if (event->events & HEV_TASK_IO_REACTOR_EV_RO)
|
||||
events |= POLLIN;
|
||||
if (event->events & HEV_TASK_IO_REACTOR_EV_WO)
|
||||
events |= POLLOUT;
|
||||
if (event->events & HEV_TASK_IO_REACTOR_EV_ER)
|
||||
events |= POLLERR;
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
hev_task_io_reactor_wait_event_get_data (HevTaskIOReactorWaitEvent *event)
|
||||
{
|
||||
return event->data;
|
||||
}
|
||||
|
||||
#endif /* __HEV_TASK_IO_REACTOR_IOCP_H__ */
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-io-reactor-kqueue.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2018 - 2025 everyone.
|
||||
Description : I/O Reactor KQueue
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#if !defined(__linux__) && !defined(__MSYS__)
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mem/api/hev-memory-allocator-api.h"
|
||||
|
||||
#include "kern/io/hev-task-io-reactor.h"
|
||||
|
||||
HevTaskIOReactor *
|
||||
hev_task_io_reactor_new (void)
|
||||
{
|
||||
HevTaskIOReactor *self;
|
||||
int flags;
|
||||
|
||||
self = hev_malloc0 (sizeof (HevTaskIOReactor));
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
self->fd = kqueue ();
|
||||
if (self->fd < 0) {
|
||||
hev_free (self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
flags = fcntl (self->fd, F_GETFD);
|
||||
if (flags < 0) {
|
||||
hev_free (self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
flags |= FD_CLOEXEC;
|
||||
if (fcntl (self->fd, F_SETFD, flags) < 0) {
|
||||
hev_free (self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
hev_task_io_reactor_destroy (HevTaskIOReactor *self)
|
||||
{
|
||||
close (self->fd);
|
||||
hev_free (self);
|
||||
}
|
||||
|
||||
int
|
||||
hev_task_io_reactor_setup (HevTaskIOReactor *self,
|
||||
HevTaskIOReactorSetupEvent *events, int count)
|
||||
{
|
||||
int i, res = -1;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (!(events[i].flags & EV_DELETE)) {
|
||||
res = kevent (self->fd, &events[i], count - i, NULL, 0, NULL);
|
||||
break;
|
||||
}
|
||||
res &= kevent (self->fd, &events[i], 1, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* !defined(__linux__) && !defined(__MSYS__) */
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-io-reactor-kqueue.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2018 - 2025 everyone.
|
||||
Description : I/O Reactor KQueue
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_IO_REACTOR_KQUEUE_H__
|
||||
#define __HEV_TASK_IO_REACTOR_KQUEUE_H__
|
||||
|
||||
#include <poll.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifndef EVFILT_EXCEPT
|
||||
#define EVFILT_EXCEPT (0)
|
||||
#endif
|
||||
|
||||
#define HEV_TASK_IO_REACTOR_EVENT_GEN_MAX (6)
|
||||
|
||||
typedef struct kevent HevTaskIOReactorSetupEvent;
|
||||
typedef struct kevent HevTaskIOReactorWaitEvent;
|
||||
|
||||
enum _HevTaskIOReactorEvents
|
||||
{
|
||||
HEV_TASK_IO_REACTOR_EV_RO = EVFILT_READ,
|
||||
HEV_TASK_IO_REACTOR_EV_WO = EVFILT_WRITE,
|
||||
HEV_TASK_IO_REACTOR_EV_ER = EVFILT_EXCEPT,
|
||||
};
|
||||
|
||||
enum _HevTaskIOReactorOperation
|
||||
{
|
||||
HEV_TASK_IO_REACTOR_OP_ADD,
|
||||
HEV_TASK_IO_REACTOR_OP_MOD,
|
||||
HEV_TASK_IO_REACTOR_OP_DEL,
|
||||
};
|
||||
|
||||
static inline int
|
||||
hev_task_io_reactor_wait (HevTaskIOReactor *self,
|
||||
HevTaskIOReactorWaitEvent *events, int count,
|
||||
int timeout)
|
||||
{
|
||||
struct timespec *tsp = NULL;
|
||||
struct timespec ts;
|
||||
|
||||
if (timeout >= 0) {
|
||||
ts.tv_sec = timeout / 1000;
|
||||
ts.tv_nsec = (timeout % 1000) * 1000000;
|
||||
tsp = &ts;
|
||||
}
|
||||
|
||||
return kevent (self->fd, NULL, 0, events, count, tsp);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_task_io_reactor_setup_event_set (HevTaskIOReactorSetupEvent *event, int fd,
|
||||
HevTaskIOReactorOperation op,
|
||||
unsigned int events, void *data)
|
||||
{
|
||||
int action;
|
||||
|
||||
switch (op) {
|
||||
case HEV_TASK_IO_REACTOR_OP_ADD:
|
||||
case HEV_TASK_IO_REACTOR_OP_MOD:
|
||||
action = EV_ADD;
|
||||
break;
|
||||
case HEV_TASK_IO_REACTOR_OP_DEL:
|
||||
action = EV_DELETE;
|
||||
}
|
||||
|
||||
EV_SET (event, fd, events, action | EV_CLEAR, 0, 0, data);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hev_task_io_reactor_setup_event_fd_gen (HevTaskIOReactorSetupEvent *events,
|
||||
int fd, HevTaskIOReactorOperation op,
|
||||
unsigned int poll_events, void *data)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
if (op > HEV_TASK_IO_REACTOR_OP_ADD) {
|
||||
if (!(poll_events & POLLIN))
|
||||
hev_task_io_reactor_setup_event_set (&events[count++], fd,
|
||||
HEV_TASK_IO_REACTOR_OP_DEL,
|
||||
HEV_TASK_IO_REACTOR_EV_RO,
|
||||
data);
|
||||
if (!(poll_events & POLLOUT))
|
||||
hev_task_io_reactor_setup_event_set (&events[count++], fd,
|
||||
HEV_TASK_IO_REACTOR_OP_DEL,
|
||||
HEV_TASK_IO_REACTOR_EV_WO,
|
||||
data);
|
||||
if (!(poll_events & POLLERR))
|
||||
hev_task_io_reactor_setup_event_set (&events[count++], fd,
|
||||
HEV_TASK_IO_REACTOR_OP_DEL,
|
||||
HEV_TASK_IO_REACTOR_EV_ER,
|
||||
data);
|
||||
if (op == HEV_TASK_IO_REACTOR_OP_DEL)
|
||||
return count;
|
||||
}
|
||||
|
||||
if (poll_events & POLLIN)
|
||||
hev_task_io_reactor_setup_event_set (&events[count++], fd, op,
|
||||
HEV_TASK_IO_REACTOR_EV_RO, data);
|
||||
if (poll_events & POLLOUT)
|
||||
hev_task_io_reactor_setup_event_set (&events[count++], fd, op,
|
||||
HEV_TASK_IO_REACTOR_EV_WO, data);
|
||||
if (poll_events & POLLERR)
|
||||
hev_task_io_reactor_setup_event_set (&events[count++], fd, op,
|
||||
HEV_TASK_IO_REACTOR_EV_ER, data);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static inline int
|
||||
hev_task_io_reactor_setup_event_whandle_gen (HevTaskIOReactorSetupEvent *events,
|
||||
void *handle,
|
||||
HevTaskIOReactorOperation op,
|
||||
void *data)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
hev_task_io_reactor_wait_event_get_events (HevTaskIOReactorWaitEvent *event)
|
||||
{
|
||||
switch (event->filter) {
|
||||
case HEV_TASK_IO_REACTOR_EV_RO:
|
||||
return POLLIN;
|
||||
case HEV_TASK_IO_REACTOR_EV_WO:
|
||||
return POLLOUT;
|
||||
default:
|
||||
return POLLERR;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void *
|
||||
hev_task_io_reactor_wait_event_get_data (HevTaskIOReactorWaitEvent *event)
|
||||
{
|
||||
return event->udata;
|
||||
}
|
||||
|
||||
#endif /* __HEV_TASK_IO_REACTOR_KQUEUE_H__ */
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-io-reactor.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2018 - 2025 everyone.
|
||||
Description : I/O Reactor
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_IO_REACTOR_H__
|
||||
#define __HEV_TASK_IO_REACTOR_H__
|
||||
|
||||
typedef struct _HevTaskIOReactor HevTaskIOReactor;
|
||||
typedef enum _HevTaskIOReactorEvents HevTaskIOReactorEvents;
|
||||
typedef enum _HevTaskIOReactorOperation HevTaskIOReactorOperation;
|
||||
|
||||
struct _HevTaskIOReactor
|
||||
{
|
||||
union
|
||||
{
|
||||
int fd;
|
||||
void *handle;
|
||||
};
|
||||
};
|
||||
|
||||
#if defined(__MSYS__)
|
||||
#include "kern/io/hev-task-io-reactor-iocp.h"
|
||||
#elif defined(__linux__)
|
||||
#include "kern/io/hev-task-io-reactor-epoll.h"
|
||||
#else
|
||||
#include "kern/io/hev-task-io-reactor-kqueue.h"
|
||||
#endif
|
||||
|
||||
HevTaskIOReactor *hev_task_io_reactor_new (void);
|
||||
void hev_task_io_reactor_destroy (HevTaskIOReactor *self);
|
||||
|
||||
int hev_task_io_reactor_setup (HevTaskIOReactor *self,
|
||||
HevTaskIOReactorSetupEvent *events, int count);
|
||||
|
||||
#endif /* __HEV_TASK_IO_REACTOR_H__ */
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-channel-private.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 everyone.
|
||||
Description : Channel
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_CHANNEL_PRIVATE_H__
|
||||
#define __HEV_TASK_CHANNEL_PRIVATE_H__
|
||||
|
||||
#include "lib/list/hev-list.h"
|
||||
#include "kern/task/hev-task.h"
|
||||
|
||||
#include "hev-task-channel-select.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef union _HevTaskChannelData HevTaskChannelData;
|
||||
typedef struct _HevTaskChannelBuffer HevTaskChannelBuffer;
|
||||
|
||||
union _HevTaskChannelData
|
||||
{
|
||||
char b[0];
|
||||
short h[0];
|
||||
int w[0];
|
||||
long long d[0];
|
||||
};
|
||||
|
||||
struct _HevTaskChannelBuffer
|
||||
{
|
||||
size_t size;
|
||||
HevTaskChannelData *data;
|
||||
};
|
||||
|
||||
struct _HevTaskChannel
|
||||
{
|
||||
HevTaskChannel *peer;
|
||||
|
||||
struct
|
||||
{
|
||||
HevListNode node;
|
||||
int used;
|
||||
} read;
|
||||
struct
|
||||
{
|
||||
HevListNode node;
|
||||
int used;
|
||||
} write;
|
||||
HevListNode chan_node;
|
||||
|
||||
HevTask *task;
|
||||
HevTaskChannelSelect *select;
|
||||
|
||||
unsigned int rd_idx;
|
||||
unsigned int wr_idx;
|
||||
unsigned int max_size;
|
||||
unsigned int use_count;
|
||||
unsigned int max_count;
|
||||
unsigned int ref_count;
|
||||
|
||||
HevTaskChannelBuffer buffers[0];
|
||||
};
|
||||
|
||||
static inline int
|
||||
hev_task_channel_is_active (HevTaskChannel *self)
|
||||
{
|
||||
return READ_ONCE (self->peer) != NULL;
|
||||
}
|
||||
|
||||
static inline int
|
||||
hev_task_channel_is_readable (HevTaskChannel *self)
|
||||
{
|
||||
return READ_ONCE (self->use_count) != 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
hev_task_channel_is_writable (HevTaskChannel *peer)
|
||||
{
|
||||
return READ_ONCE (peer->use_count) < READ_ONCE (peer->max_count);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hev_task_channel_is_select_writable (HevTaskChannel *peer)
|
||||
{
|
||||
return READ_ONCE (peer->use_count) < (READ_ONCE (peer->max_count) - 1);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_TASK_CHANNEL_PRIVATE_H__ */
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-channel-select-private.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 everyone.
|
||||
Description : Channel Selector
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_CHANNEL_SELECT_PRIVATE_H__
|
||||
#define __HEV_TASK_CHANNEL_SELECT_PRIVATE_H__
|
||||
|
||||
#include "lib/list/hev-list.h"
|
||||
#include "kern/task/hev-task.h"
|
||||
|
||||
#include "hev-task-channel.h"
|
||||
#include "hev-task-channel-private.h"
|
||||
|
||||
#include "hev-task-channel-select.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct _HevTaskChannelSelect
|
||||
{
|
||||
HevTask *task;
|
||||
HevList chan_list;
|
||||
HevList read_list;
|
||||
HevList write_list;
|
||||
};
|
||||
|
||||
static inline void
|
||||
hev_task_channel_select_add_read (HevTaskChannelSelect *self,
|
||||
HevTaskChannel *chan)
|
||||
{
|
||||
if (chan->read.used)
|
||||
return;
|
||||
|
||||
chan->read.used = 1;
|
||||
hev_list_add_tail (&self->read_list, &chan->read.node);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_task_channel_select_del_read (HevTaskChannelSelect *self,
|
||||
HevTaskChannel *chan)
|
||||
{
|
||||
if (!chan->read.used)
|
||||
return;
|
||||
|
||||
chan->read.used = 0;
|
||||
hev_list_del (&self->read_list, &chan->read.node);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_task_channel_select_add_write (HevTaskChannelSelect *self,
|
||||
HevTaskChannel *chan)
|
||||
{
|
||||
if (chan->write.used)
|
||||
return;
|
||||
|
||||
chan->write.used = 1;
|
||||
hev_list_add_tail (&self->write_list, &chan->write.node);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_task_channel_select_del_write (HevTaskChannelSelect *self,
|
||||
HevTaskChannel *chan)
|
||||
{
|
||||
if (!chan->write.used)
|
||||
return;
|
||||
|
||||
chan->write.used = 0;
|
||||
hev_list_del (&self->write_list, &chan->write.node);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_TASK_CHANNEL_SELECT_PRIVATE_H__ */
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-channel-select.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 everyone.
|
||||
Description : Channel Selector
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
#include "mem/api/hev-memory-allocator-api.h"
|
||||
|
||||
#include "hev-task-channel-select.h"
|
||||
#include "hev-task-channel-select-private.h"
|
||||
|
||||
EXPORT_SYMBOL HevTaskChannelSelect *
|
||||
hev_task_channel_select_new (void)
|
||||
{
|
||||
HevTaskChannelSelect *self;
|
||||
|
||||
self = hev_malloc0 (sizeof (HevTaskChannelSelect));
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL void
|
||||
hev_task_channel_select_destroy (HevTaskChannelSelect *self)
|
||||
{
|
||||
hev_free (self);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL void
|
||||
hev_task_channel_select_add (HevTaskChannelSelect *self, HevTaskChannel *chan)
|
||||
{
|
||||
chan->select = self;
|
||||
chan->task = hev_task_self ();
|
||||
|
||||
hev_list_add_tail (&self->chan_list, &chan->chan_node);
|
||||
if (hev_task_channel_is_readable (chan))
|
||||
hev_task_channel_select_add_read (self, chan);
|
||||
if (chan->peer && hev_task_channel_is_select_writable (chan->peer))
|
||||
hev_task_channel_select_add_write (self, chan);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL void
|
||||
hev_task_channel_select_del (HevTaskChannelSelect *self, HevTaskChannel *chan)
|
||||
{
|
||||
hev_task_channel_select_del_read (self, chan);
|
||||
hev_task_channel_select_del_write (self, chan);
|
||||
hev_list_del (&self->chan_list, &chan->chan_node);
|
||||
|
||||
chan->task = NULL;
|
||||
chan->select = NULL;
|
||||
}
|
||||
|
||||
static HevListNode *
|
||||
hev_task_channel_select (HevTaskChannelSelect *self, HevList *list, int timeout)
|
||||
{
|
||||
HevListNode *node;
|
||||
unsigned int milliseconds = timeout;
|
||||
|
||||
if (!hev_list_first (&self->chan_list))
|
||||
return NULL;
|
||||
|
||||
while (!(node = hev_list_first (list)) && milliseconds) {
|
||||
barrier ();
|
||||
if (timeout < 0)
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
else
|
||||
milliseconds = hev_task_sleep (milliseconds);
|
||||
barrier ();
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL HevTaskChannel *
|
||||
hev_task_channel_select_read (HevTaskChannelSelect *self, int timeout)
|
||||
{
|
||||
HevListNode *node;
|
||||
|
||||
node = hev_task_channel_select (self, &self->read_list, timeout);
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
return container_of (node, HevTaskChannel, read.node);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL HevTaskChannel *
|
||||
hev_task_channel_select_write (HevTaskChannelSelect *self, int timeout)
|
||||
{
|
||||
HevListNode *node;
|
||||
|
||||
node = hev_task_channel_select (self, &self->write_list, timeout);
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
return container_of (node, HevTaskChannel, write.node);
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-channel-select.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 everyone.
|
||||
Description : Channel Selector
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_CHANNEL_SELECT_H__
|
||||
#define __HEV_TASK_CHANNEL_SELECT_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "hev-task-channel.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct _HevTaskChannelSelect HevTaskChannelSelect;
|
||||
|
||||
/**
|
||||
* hev_task_channel_select_new:
|
||||
*
|
||||
* Creates A task channel selector.
|
||||
*
|
||||
* Returns: A #HevTaskChannelSelect
|
||||
*
|
||||
* Since: 4.6.9
|
||||
*/
|
||||
HevTaskChannelSelect *hev_task_channel_select_new (void);
|
||||
|
||||
/**
|
||||
* hev_task_channel_select_destroy:
|
||||
* @self: A #HevTaskChannelSelect
|
||||
*
|
||||
* Destroy the task channel selector.
|
||||
*
|
||||
* Since: 4.6.9
|
||||
*/
|
||||
void hev_task_channel_select_destroy (HevTaskChannelSelect *self);
|
||||
|
||||
/**
|
||||
* hev_task_channel_select_add:
|
||||
* @self: A #HevTaskChannelSelect
|
||||
* @chan: A #HevTaskChannel
|
||||
*
|
||||
* Add the task channel @chan to selector @self.
|
||||
*
|
||||
* Since: 4.6.9
|
||||
*/
|
||||
void hev_task_channel_select_add (HevTaskChannelSelect *self,
|
||||
HevTaskChannel *chan);
|
||||
|
||||
/**
|
||||
* hev_task_channel_select_del:
|
||||
* @self: A #HevTaskChannelSelect
|
||||
* @chan: A #HevTaskChannel
|
||||
*
|
||||
* Remove the task channel @chan to selector @self.
|
||||
*
|
||||
* Since: 4.6.9
|
||||
*/
|
||||
void hev_task_channel_select_del (HevTaskChannelSelect *self,
|
||||
HevTaskChannel *chan);
|
||||
|
||||
/**
|
||||
* hev_task_channel_select_read:
|
||||
* @self: A #HevTaskChannelSelect
|
||||
* @timeout: (milliseconds): wait timeout
|
||||
*
|
||||
* The select read function shall attempt to select a readable channel.
|
||||
* The function will wait until at least one channel is ready or timeout.
|
||||
*
|
||||
* Returns: A #HevTaskChannel
|
||||
*
|
||||
* Since: 4.6.9
|
||||
*/
|
||||
HevTaskChannel *hev_task_channel_select_read (HevTaskChannelSelect *self,
|
||||
int timeout);
|
||||
|
||||
/**
|
||||
* hev_task_channel_select_write:
|
||||
* @self: A #HevTaskChannelSelect
|
||||
* @timeout: (milliseconds): wait timeout
|
||||
*
|
||||
* The select write function shall attempt to select a writable channel.
|
||||
* The function will wait until at least one channel is ready or timeout.
|
||||
*
|
||||
* Returns: A #HevTaskChannel
|
||||
*
|
||||
* Since: 5.1.0
|
||||
*/
|
||||
HevTaskChannel *hev_task_channel_select_write (HevTaskChannelSelect *self,
|
||||
int timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_TASK_CHANNEL_SELECT_H__ */
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-channel.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 everyone.
|
||||
Description : Channel
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include "kern/task/hev-task.h"
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
#include "mem/api/hev-memory-allocator-api.h"
|
||||
|
||||
#include "hev-task-channel-select-private.h"
|
||||
|
||||
#include "hev-task-channel.h"
|
||||
#include "hev-task-channel-private.h"
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_channel_new (HevTaskChannel **chan1, HevTaskChannel **chan2)
|
||||
{
|
||||
return hev_task_channel_new_with_buffers (chan1, chan2, 0, 0);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_channel_new_with_buffers (HevTaskChannel **chan1,
|
||||
HevTaskChannel **chan2, unsigned int size,
|
||||
unsigned int buffers)
|
||||
{
|
||||
HevTaskChannel *c1, *c2;
|
||||
unsigned int buffers_size;
|
||||
unsigned int data_size = 0;
|
||||
|
||||
buffers += 1;
|
||||
if (buffers > 1)
|
||||
data_size = size * buffers;
|
||||
buffers_size = sizeof (HevTaskChannelBuffer) * buffers;
|
||||
|
||||
c1 = hev_malloc (sizeof (HevTaskChannel) + buffers_size + data_size);
|
||||
if (!c1)
|
||||
goto err0;
|
||||
|
||||
c2 = hev_malloc (sizeof (HevTaskChannel) + buffers_size + data_size);
|
||||
if (!c2)
|
||||
goto err1;
|
||||
|
||||
__builtin_bzero (c1, sizeof (HevTaskChannel));
|
||||
c1->peer = c2;
|
||||
c1->max_size = size;
|
||||
c1->max_count = buffers;
|
||||
c1->ref_count = 1;
|
||||
|
||||
__builtin_bzero (c2, sizeof (HevTaskChannel));
|
||||
c2->peer = c1;
|
||||
c2->max_size = size;
|
||||
c2->max_count = buffers;
|
||||
c2->ref_count = 1;
|
||||
|
||||
if (buffers > 1) {
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < buffers; i++) {
|
||||
c1->buffers[i].data = (void *)c1->buffers + buffers_size + size * i;
|
||||
c2->buffers[i].data = (void *)c2->buffers + buffers_size + size * i;
|
||||
}
|
||||
}
|
||||
|
||||
*chan1 = c1;
|
||||
*chan2 = c2;
|
||||
|
||||
return 0;
|
||||
|
||||
hev_free (c2);
|
||||
err1:
|
||||
hev_free (c1);
|
||||
err0:
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
hev_task_channel_ref (HevTaskChannel *self)
|
||||
{
|
||||
self->ref_count++;
|
||||
}
|
||||
|
||||
static void
|
||||
hev_task_channel_unref (HevTaskChannel *self)
|
||||
{
|
||||
self->ref_count--;
|
||||
if (self->ref_count)
|
||||
return;
|
||||
|
||||
hev_free (self);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL void
|
||||
hev_task_channel_destroy (HevTaskChannel *self)
|
||||
{
|
||||
if (self->peer) {
|
||||
self->peer->peer = NULL;
|
||||
if (self->peer->task)
|
||||
hev_task_wakeup (self->peer->task);
|
||||
}
|
||||
if (self->task)
|
||||
hev_task_wakeup (self->task);
|
||||
|
||||
hev_task_channel_unref (self);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
hev_task_channel_data_copy (void *dst, const void *src, size_t size)
|
||||
{
|
||||
HevTaskChannelData *d = dst;
|
||||
const HevTaskChannelData *s = src;
|
||||
|
||||
switch (size) {
|
||||
case 0:
|
||||
break;
|
||||
case sizeof (char):
|
||||
d->b[0] = s->b[0];
|
||||
break;
|
||||
case sizeof (short):
|
||||
d->h[0] = s->h[0];
|
||||
break;
|
||||
case sizeof (int):
|
||||
d->w[0] = s->w[0];
|
||||
break;
|
||||
case sizeof (long long):
|
||||
d->d[0] = s->d[0];
|
||||
break;
|
||||
default:
|
||||
__builtin_memcpy (dst, src, size);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL ssize_t
|
||||
hev_task_channel_read (HevTaskChannel *self, void *buffer, size_t count)
|
||||
{
|
||||
HevTaskChannelBuffer *cbuf;
|
||||
ssize_t size = -1;
|
||||
|
||||
/* wait on empty */
|
||||
while (!hev_task_channel_is_readable (self)) {
|
||||
/* check is peer alive because cond wait may yield */
|
||||
if (!hev_task_channel_is_active (self))
|
||||
goto out;
|
||||
|
||||
WRITE_ONCE (self->task, hev_task_self ());
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
}
|
||||
|
||||
barrier ();
|
||||
cbuf = &self->buffers[self->rd_idx];
|
||||
self->rd_idx = (self->rd_idx + 1) % self->max_count;
|
||||
|
||||
size = count;
|
||||
if (cbuf->size < count)
|
||||
size = cbuf->size;
|
||||
size = hev_task_channel_data_copy (buffer, cbuf->data, size);
|
||||
|
||||
if (self->use_count == self->max_count) {
|
||||
HevTaskChannel *peer = self->peer;
|
||||
|
||||
if (peer) {
|
||||
if (peer->select)
|
||||
hev_task_channel_select_add_write (peer->select, peer);
|
||||
if (peer->task)
|
||||
hev_task_wakeup (peer->task);
|
||||
}
|
||||
}
|
||||
|
||||
self->use_count--;
|
||||
if (self->select && !hev_task_channel_is_readable (self))
|
||||
hev_task_channel_select_del_read (self->select, self);
|
||||
|
||||
out:
|
||||
return size;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL ssize_t
|
||||
hev_task_channel_write (HevTaskChannel *self, const void *buffer, size_t count)
|
||||
{
|
||||
HevTaskChannel *peer = self->peer;
|
||||
HevTaskChannelBuffer *cbuf;
|
||||
ssize_t size = -1;
|
||||
|
||||
if (!peer)
|
||||
goto out0;
|
||||
|
||||
hev_task_channel_ref (peer);
|
||||
|
||||
/* wait on full */
|
||||
while (!hev_task_channel_is_writable (peer)) {
|
||||
/* check is peer alive because cond wait may yield */
|
||||
if (!hev_task_channel_is_active (self))
|
||||
goto out1;
|
||||
|
||||
WRITE_ONCE (self->task, hev_task_self ());
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
}
|
||||
|
||||
barrier ();
|
||||
cbuf = &peer->buffers[peer->wr_idx];
|
||||
peer->wr_idx = (peer->wr_idx + 1) % peer->max_count;
|
||||
|
||||
size = count;
|
||||
if (peer->max_count == 1) {
|
||||
cbuf->data = (HevTaskChannelData *)buffer;
|
||||
} else {
|
||||
if (size > self->max_size)
|
||||
size = self->max_size;
|
||||
size = hev_task_channel_data_copy (cbuf->data, buffer, size);
|
||||
}
|
||||
cbuf->size = size;
|
||||
|
||||
if (peer->use_count == 0) {
|
||||
if (peer->select)
|
||||
hev_task_channel_select_add_read (peer->select, peer);
|
||||
if (peer->task)
|
||||
hev_task_wakeup (peer->task);
|
||||
}
|
||||
|
||||
peer->use_count++;
|
||||
if (self->select && !hev_task_channel_is_select_writable (peer))
|
||||
hev_task_channel_select_del_write (self->select, self);
|
||||
|
||||
/* sync */
|
||||
while (!hev_task_channel_is_writable (peer)) {
|
||||
/* check is peer alive because cond wait may yield */
|
||||
if (!hev_task_channel_is_active (self)) {
|
||||
size = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
WRITE_ONCE (self->task, hev_task_self ());
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
}
|
||||
|
||||
barrier ();
|
||||
out1:
|
||||
hev_task_channel_unref (peer);
|
||||
out0:
|
||||
|
||||
return size;
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-channel.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 everyone.
|
||||
Description : Channel
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_CHANNEL_H__
|
||||
#define __HEV_TASK_CHANNEL_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct _HevTaskChannel HevTaskChannel;
|
||||
|
||||
/**
|
||||
* hev_task_channel_new:
|
||||
* @chan1: (out): a #HevTaskChannel
|
||||
* @chan2: (out): a #HevTaskChannel
|
||||
*
|
||||
* Creates a pair of connected task channel.
|
||||
* The channels are synchronous, both sides of the channel will wait until the
|
||||
* other side is ready.
|
||||
*
|
||||
* Returns: When successful, returns zero. When an error occurs, returns -1.
|
||||
*
|
||||
* Since: 4.5
|
||||
*/
|
||||
int hev_task_channel_new (HevTaskChannel **chan1, HevTaskChannel **chan2);
|
||||
|
||||
/**
|
||||
* hev_task_channel_new_with_buffers:
|
||||
* @chan1: (out): a #HevTaskChannel
|
||||
* @chan2: (out): a #HevTaskChannel
|
||||
* @size: buffer size
|
||||
* @buffers: buffers capacity
|
||||
*
|
||||
* Creates a pair of connected task channel with a capacity of @buffers.
|
||||
* The channels are asynchronous, sending or receiving a data will not wait
|
||||
* unless the channel is already full.
|
||||
*
|
||||
* Returns: When successful, returns zero. When an error occurs, returns -1.
|
||||
*
|
||||
* Since: 5.1.0
|
||||
*/
|
||||
int hev_task_channel_new_with_buffers (HevTaskChannel **chan1,
|
||||
HevTaskChannel **chan2,
|
||||
unsigned int size, unsigned int buffers);
|
||||
|
||||
/**
|
||||
* hev_task_channel_destroy:
|
||||
* @self: a #HevTaskChannel
|
||||
*
|
||||
* Destroy the task channel.
|
||||
*
|
||||
* Since: 4.5
|
||||
*/
|
||||
void hev_task_channel_destroy (HevTaskChannel *self);
|
||||
|
||||
/**
|
||||
* hev_task_channel_read:
|
||||
* @self: a #HevTaskChannel
|
||||
* @buffer: (array length=count): a buffer to read data into
|
||||
* @count: the number of bytes that will be read
|
||||
*
|
||||
* The read function shall attempt to read @count bytes from the channel into
|
||||
* @buffer. Just as datagram which the data transfer on task channel.
|
||||
*
|
||||
* Returns: the number of bytes actually read
|
||||
*
|
||||
* Since: 4.5
|
||||
*/
|
||||
ssize_t hev_task_channel_read (HevTaskChannel *self, void *buffer,
|
||||
size_t count);
|
||||
|
||||
/**
|
||||
* hev_task_channel_write:
|
||||
* @self: a #HevTaskChannel
|
||||
* @buffer: (array length=count): a buffer to write data from
|
||||
* @count: the number of bytes that will be write
|
||||
*
|
||||
* The write function shall attempt to write @count bytes to the channel from
|
||||
* @buffer. Just as datagram which the data transfer on task channel.
|
||||
*
|
||||
* Returns: the number of bytes actually write
|
||||
*
|
||||
* Since: 4.5
|
||||
*/
|
||||
ssize_t hev_task_channel_write (HevTaskChannel *self, const void *buffer,
|
||||
size_t count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_TASK_CHANNEL_H__ */
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-cond.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 everyone.
|
||||
Description : Condition
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "kern/task/hev-task.h"
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
|
||||
#include "hev-task-cond.h"
|
||||
|
||||
struct _HevTaskCondNode
|
||||
{
|
||||
HevTaskCondNode *prev;
|
||||
HevTaskCondNode *next;
|
||||
|
||||
HevTask *task;
|
||||
};
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_cond_init (HevTaskCond *self)
|
||||
{
|
||||
self->waiters = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_cond_wait (HevTaskCond *self, HevTaskMutex *mutex)
|
||||
{
|
||||
HevTaskCondNode node;
|
||||
|
||||
node.prev = NULL;
|
||||
node.next = self->waiters;
|
||||
node.task = hev_task_self ();
|
||||
|
||||
if (self->waiters)
|
||||
self->waiters->prev = &node;
|
||||
self->waiters = &node;
|
||||
|
||||
hev_task_mutex_unlock (mutex);
|
||||
do {
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
} while (READ_ONCE (node.task));
|
||||
hev_task_mutex_lock (mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_cond_timedwait (HevTaskCond *self, HevTaskMutex *mutex,
|
||||
unsigned int milliseconds)
|
||||
{
|
||||
HevTaskCondNode node;
|
||||
|
||||
node.prev = NULL;
|
||||
node.next = self->waiters;
|
||||
node.task = hev_task_self ();
|
||||
|
||||
if (self->waiters)
|
||||
self->waiters->prev = &node;
|
||||
self->waiters = &node;
|
||||
|
||||
hev_task_mutex_unlock (mutex);
|
||||
while (milliseconds && READ_ONCE (node.task))
|
||||
milliseconds = hev_task_sleep (milliseconds);
|
||||
hev_task_mutex_lock (mutex);
|
||||
|
||||
if (READ_ONCE (node.task)) {
|
||||
if (node.prev)
|
||||
node.prev->next = node.next;
|
||||
if (node.next)
|
||||
node.next->prev = node.prev;
|
||||
if (self->waiters == &node)
|
||||
self->waiters = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_cond_signal (HevTaskCond *self)
|
||||
{
|
||||
if (self->waiters) {
|
||||
hev_task_wakeup (self->waiters->task);
|
||||
|
||||
self->waiters->task = NULL;
|
||||
self->waiters = self->waiters->next;
|
||||
if (self->waiters)
|
||||
self->waiters->prev = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_cond_broadcast (HevTaskCond *self)
|
||||
{
|
||||
while (self->waiters) {
|
||||
hev_task_wakeup (self->waiters->task);
|
||||
|
||||
self->waiters->task = NULL;
|
||||
self->waiters = self->waiters->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-cond.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 everyone.
|
||||
Description : Condition
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_COND_H__
|
||||
#define __HEV_TASK_COND_H__
|
||||
|
||||
#include "hev-task-mutex.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct _HevTaskCond HevTaskCond;
|
||||
typedef struct _HevTaskCondNode HevTaskCondNode;
|
||||
|
||||
struct _HevTaskCond
|
||||
{
|
||||
HevTaskCondNode *waiters;
|
||||
};
|
||||
|
||||
/**
|
||||
* hev_task_cond_init:
|
||||
* @self: a #HevTaskCond
|
||||
*
|
||||
* Initialize the task condition.
|
||||
*
|
||||
* Returns: When successful, returns zero. When an error occurs, returns -1.
|
||||
*
|
||||
* Since: 4.4
|
||||
*/
|
||||
int hev_task_cond_init (HevTaskCond *self);
|
||||
|
||||
/**
|
||||
* hev_task_cond_wait:
|
||||
* @self: a #HevTaskCond
|
||||
* @mutex: a #HevTaskMutex
|
||||
*
|
||||
* Wait on the task condition.
|
||||
*
|
||||
* Returns: When successful, returns zero. When an error occurs, returns -1.
|
||||
*
|
||||
* Since: 4.4
|
||||
*/
|
||||
int hev_task_cond_wait (HevTaskCond *self, HevTaskMutex *mutex);
|
||||
|
||||
/**
|
||||
* hev_task_cond_wait:
|
||||
* @self: a #HevTaskCond
|
||||
* @mutex: a #HevTaskMutex
|
||||
* @milliseconds: wait time
|
||||
*
|
||||
* The timedwait function shall be equivalent to condition wait, except that an
|
||||
* error is returned if the time specified by @milliseconds passes.
|
||||
*
|
||||
* Returns: When successful, returns zero. When an error occurs, returns -1.
|
||||
*
|
||||
* Since: 4.4
|
||||
*/
|
||||
int hev_task_cond_timedwait (HevTaskCond *self, HevTaskMutex *mutex,
|
||||
unsigned int milliseconds);
|
||||
|
||||
/**
|
||||
* hev_task_cond_signal:
|
||||
* @self: a #HevTaskCond
|
||||
*
|
||||
* Wake one task that wait on condition.
|
||||
*
|
||||
* Returns: When successful, returns zero. When an error occurs, returns -1.
|
||||
*
|
||||
* Since: 4.4
|
||||
*/
|
||||
int hev_task_cond_signal (HevTaskCond *self);
|
||||
|
||||
/**
|
||||
* hev_task_cond_broadcast:
|
||||
* @self: a #HevTaskCond
|
||||
*
|
||||
* Wake all task that wait on condition.
|
||||
*
|
||||
* Returns: When successful, returns zero. When an error occurs, returns -1.
|
||||
*
|
||||
* Since: 4.4
|
||||
*/
|
||||
int hev_task_cond_broadcast (HevTaskCond *self);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_TASK_MUTEX_H__ */
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-mutex.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 everyone.
|
||||
Description : Mutex
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "kern/task/hev-task.h"
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
|
||||
#include "hev-task-mutex.h"
|
||||
|
||||
struct _HevTaskMutexNode
|
||||
{
|
||||
HevTaskMutexNode *next;
|
||||
|
||||
HevTask *task;
|
||||
};
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_mutex_init (HevTaskMutex *self)
|
||||
{
|
||||
self->locker = 0;
|
||||
self->waiters = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_mutex_lock (HevTaskMutex *self)
|
||||
{
|
||||
if (self->locker) {
|
||||
HevTaskMutexNode node;
|
||||
|
||||
node.next = self->waiters;
|
||||
node.task = hev_task_self ();
|
||||
self->waiters = &node;
|
||||
|
||||
do {
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
} while (READ_ONCE (self->locker) ||
|
||||
READ_ONCE (self->waiters) != &node);
|
||||
|
||||
self->waiters = node.next;
|
||||
}
|
||||
|
||||
barrier ();
|
||||
self->locker = 1;
|
||||
barrier ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_mutex_trylock (HevTaskMutex *self)
|
||||
{
|
||||
if (self->locker)
|
||||
return -1;
|
||||
|
||||
barrier ();
|
||||
self->locker = 1;
|
||||
barrier ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_mutex_unlock (HevTaskMutex *self)
|
||||
{
|
||||
barrier ();
|
||||
self->locker = 0;
|
||||
barrier ();
|
||||
|
||||
if (self->waiters)
|
||||
hev_task_wakeup (self->waiters->task);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-mutex.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 everyone.
|
||||
Description : Mutex
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_MUTEX_H__
|
||||
#define __HEV_TASK_MUTEX_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct _HevTaskMutex HevTaskMutex;
|
||||
typedef struct _HevTaskMutexNode HevTaskMutexNode;
|
||||
|
||||
struct _HevTaskMutex
|
||||
{
|
||||
unsigned int locker;
|
||||
|
||||
HevTaskMutexNode *waiters;
|
||||
};
|
||||
|
||||
/**
|
||||
* hev_task_mutex_init:
|
||||
* @self: a #HevTaskMutex
|
||||
*
|
||||
* Initialize the task mutex.
|
||||
*
|
||||
* Returns: When successful, returns zero. When an error occurs, returns -1.
|
||||
*
|
||||
* Since: 4.3
|
||||
*/
|
||||
int hev_task_mutex_init (HevTaskMutex *self);
|
||||
|
||||
/**
|
||||
* hev_task_mutex_lock:
|
||||
* @self: a #HevTaskMutex
|
||||
*
|
||||
* Lock the task mutex.
|
||||
*
|
||||
* Returns: When successful, returns zero. When an error occurs, returns -1.
|
||||
*
|
||||
* Since: 4.3
|
||||
*/
|
||||
int hev_task_mutex_lock (HevTaskMutex *self);
|
||||
|
||||
/**
|
||||
* hev_task_mutex_trylock:
|
||||
* @self: a #HevTaskMutex
|
||||
*
|
||||
* Try lock the task mutex.
|
||||
*
|
||||
* Returns: When successful, returns zero. When an error occurs, returns -1.
|
||||
*
|
||||
* Since: 4.3
|
||||
*/
|
||||
int hev_task_mutex_trylock (HevTaskMutex *self);
|
||||
|
||||
/**
|
||||
* hev_task_mutex_unlock:
|
||||
* @self: a #HevTaskMutex
|
||||
*
|
||||
* Unlock the task mutex.
|
||||
*
|
||||
* Returns: When successful, returns zero. When an error occurs, returns -1.
|
||||
*
|
||||
* Since: 4.3
|
||||
*/
|
||||
int hev_task_mutex_unlock (HevTaskMutex *self);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_TASK_MUTEX_H__ */
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-call.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2020 everyone.
|
||||
Description : Task call
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
#include "mem/api/hev-memory-allocator-api.h"
|
||||
|
||||
#include "hev-task-call.h"
|
||||
|
||||
extern void hev_task_execute (HevTaskCall *self, HevTaskCallEntry entry);
|
||||
|
||||
EXPORT_SYMBOL HevTaskCall *
|
||||
hev_task_call_new (int base_size, int stack_size)
|
||||
{
|
||||
HevTaskCall *self;
|
||||
|
||||
self = hev_malloc (base_size + stack_size);
|
||||
if (self) {
|
||||
uintptr_t stack_addr;
|
||||
stack_addr = (uintptr_t)((void *)self + base_size + stack_size);
|
||||
self->stack_top = (void *)ALIGN_DOWN (stack_addr, 16);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL void
|
||||
hev_task_call_destroy (HevTaskCall *self)
|
||||
{
|
||||
hev_free (self);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL void *
|
||||
hev_task_call_jump (HevTaskCall *self, HevTaskCallEntry entry)
|
||||
{
|
||||
hev_task_execute (self, entry);
|
||||
return self->retval;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-call.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2020 everyone.
|
||||
Description : Task call
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_CALL_H__
|
||||
#define __HEV_TASK_CALL_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct _HevTaskCall HevTaskCall;
|
||||
typedef void (*HevTaskCallEntry) (HevTaskCall *call);
|
||||
|
||||
struct _HevTaskCall
|
||||
{
|
||||
void *stack_top;
|
||||
void *retval;
|
||||
};
|
||||
|
||||
/**
|
||||
* hev_task_call_new:
|
||||
* @base_size: base size
|
||||
* @stack_size: stack size
|
||||
*
|
||||
* Creates a new task call.
|
||||
*
|
||||
* Returns: a new #HevTaskCall.
|
||||
*
|
||||
* Since: 4.8.0
|
||||
*/
|
||||
HevTaskCall *hev_task_call_new (int base_size, int stack_size);
|
||||
|
||||
/**
|
||||
* hev_task_call_destroy:
|
||||
* @self: a #HevTaskCall
|
||||
*
|
||||
* Destroy the task call.
|
||||
*
|
||||
* Since: 4.8.0
|
||||
*/
|
||||
void hev_task_call_destroy (HevTaskCall *self);
|
||||
|
||||
/**
|
||||
* hev_task_call_jump:
|
||||
* @self: a #HevTaskCall
|
||||
* @entry: task call entry
|
||||
*
|
||||
* Call @entry on new stack.
|
||||
*
|
||||
* Returns: value from @entry (see set_retval).
|
||||
*
|
||||
* Since: 4.8.0
|
||||
*/
|
||||
void *hev_task_call_jump (HevTaskCall *self, HevTaskCallEntry entry);
|
||||
|
||||
/**
|
||||
* hev_task_call_set_retval:
|
||||
* @self: a #HevTaskCall
|
||||
* @value: return value
|
||||
*
|
||||
* Set return value of task call.
|
||||
*
|
||||
* Since: 4.8.0
|
||||
*/
|
||||
static inline void
|
||||
hev_task_call_set_retval (HevTaskCall *self, void *value)
|
||||
{
|
||||
self->retval = value;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_TASK_CALL_H__ */
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-execute.S
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2017 everyone.
|
||||
Description :
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
# include "arch/x86/hev-task-execute-x86.s"
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
|
||||
# include "arch/x86/hev-task-execute-x86_64.s"
|
||||
|
||||
#elif defined(__mips__)
|
||||
|
||||
# if (_MIPS_SIM == _ABI64)
|
||||
# include "arch/mips/hev-task-execute-mips64.s"
|
||||
# else
|
||||
# include "arch/mips/hev-task-execute-mips32.s"
|
||||
# endif
|
||||
|
||||
#elif defined(__arm__)
|
||||
|
||||
# include "arch/arm/hev-task-execute-arm.s"
|
||||
|
||||
#elif defined(__aarch64__)
|
||||
|
||||
# include "arch/arm/hev-task-execute-aarch64.s"
|
||||
|
||||
#elif defined(__sw_64__)
|
||||
|
||||
# include "arch/sw64/hev-task-execute-sw64.s"
|
||||
|
||||
#elif defined(__riscv)
|
||||
|
||||
# if defined(_LP64)
|
||||
# include "arch/riscv/hev-task-execute-riscv64.s"
|
||||
# else
|
||||
# include "arch/riscv/hev-task-execute-riscv32.s"
|
||||
# endif
|
||||
|
||||
#elif defined(__loongarch__)
|
||||
|
||||
# if defined(_LP64)
|
||||
# include "arch/loong/hev-task-execute-la64.s"
|
||||
# else
|
||||
# include "arch/loong/hev-task-execute-la32.s"
|
||||
# endif
|
||||
|
||||
#elif defined(__powerpc64__)
|
||||
|
||||
# include "arch/ppc/hev-task-execute-ppc64.s"
|
||||
|
||||
#elif defined(__powerpc__)
|
||||
|
||||
# include "arch/ppc/hev-task-execute-ppc32.s"
|
||||
|
||||
#elif defined(__arc__)
|
||||
|
||||
# include "arch/arc/hev-task-execute-arc32.s"
|
||||
|
||||
#elif defined(__m68k__)
|
||||
|
||||
# include "arch/m68k/hev-task-execute-m68k.s"
|
||||
|
||||
#elif defined(__microblaze__)
|
||||
|
||||
# include "arch/microblaze/hev-task-execute-microblaze.s"
|
||||
|
||||
#elif defined(__s390x__)
|
||||
|
||||
# include "arch/s390/hev-task-execute-s390x.s"
|
||||
|
||||
#elif defined(__sh__)
|
||||
|
||||
# include "arch/sh/hev-task-execute-sh.s"
|
||||
|
||||
#elif defined(__or1k__)
|
||||
|
||||
# include "arch/openrisc/hev-task-execute-or1k.s"
|
||||
|
||||
#else
|
||||
|
||||
# error "Unsupported platform!"
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__ELF__) && defined(__linux__)
|
||||
/* An executable stack is *not* required for these functions. */
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
.previous
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-executer.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2017 everyone.
|
||||
Description :
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include "hev-task-executer.h"
|
||||
#include "kern/core/hev-task-system-private.h"
|
||||
|
||||
void
|
||||
hev_task_executer (HevTask *task)
|
||||
{
|
||||
if (_setjmp (task->context) == 0)
|
||||
return;
|
||||
|
||||
task->entry (task->data);
|
||||
|
||||
if (task->joiner)
|
||||
hev_task_wakeup (task->joiner);
|
||||
|
||||
hev_task_system_kill_current_task ();
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-executer.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2017 everyone.
|
||||
Description :
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_EXECUTER_H__
|
||||
#define __HEV_TASK_EXECUTER_H__
|
||||
|
||||
#include "hev-task-private.h"
|
||||
|
||||
extern void hev_task_executer (HevTask *task);
|
||||
|
||||
#endif /* __HEV_TASK_EXECUTER_H__ */
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-private.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2017 - 2020 everyone.
|
||||
Description :
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_PRIVATE_H__
|
||||
#define __HEV_TASK_PRIVATE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "hev-task.h"
|
||||
#include "hev-task-stack.h"
|
||||
#include "lib/list/hev-list.h"
|
||||
#include "lib/rbtree/hev-rbtree.h"
|
||||
|
||||
typedef struct _HevTaskSchedEntity HevTaskSchedEntity;
|
||||
|
||||
struct _HevTaskSchedEntity
|
||||
{
|
||||
HevTask *task;
|
||||
};
|
||||
|
||||
struct _HevTask
|
||||
{
|
||||
void *stack_bottom;
|
||||
HevTaskEntry entry;
|
||||
void *data;
|
||||
|
||||
uint64_t sched_key;
|
||||
HevRBTreeNode sched_node;
|
||||
HevTaskSchedEntity sched_entity;
|
||||
|
||||
HevTaskStack *stack;
|
||||
HevTask *joiner;
|
||||
|
||||
int ref_count;
|
||||
int priority;
|
||||
int next_priority;
|
||||
HevTaskState state;
|
||||
|
||||
jmp_buf context;
|
||||
|
||||
HevListNode list_node;
|
||||
};
|
||||
|
||||
extern void hev_task_execute (HevTask *self, void *executer);
|
||||
|
||||
#endif /* __HEV_TASK_PRIVATE_H__ */
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-stack-heap.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2020 everyone.
|
||||
Description :
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
#include "mem/api/hev-memory-allocator-api.h"
|
||||
|
||||
#include "hev-task-stack.h"
|
||||
|
||||
#if CONFIG_STACK_BACKEND == STACK_HEAP
|
||||
|
||||
#ifdef ENABLE_STACK_OVERFLOW_DETECTION
|
||||
#if CONFIG_STACK_OVERFLOW_DETECTION == 1
|
||||
#define STACK_OVERFLOW_DETECTION_SIZE (4)
|
||||
#elif CONFIG_STACK_OVERFLOW_DETECTION == 2
|
||||
#define STACK_OVERFLOW_DETECTION_SIZE (4096)
|
||||
#else
|
||||
#define STACK_OVERFLOW_DETECTION_SIZE (8192)
|
||||
#endif
|
||||
#define STACK_OVERFLOW_DETECTION_TAG (0xdeadbeefu)
|
||||
#else
|
||||
#define STACK_OVERFLOW_DETECTION_SIZE (0)
|
||||
#endif
|
||||
|
||||
struct _HevTaskStack
|
||||
{
|
||||
int size;
|
||||
};
|
||||
|
||||
static inline void
|
||||
hev_task_stack_detection_mark (HevTaskStack *self)
|
||||
{
|
||||
#ifdef ENABLE_STACK_OVERFLOW_DETECTION
|
||||
const unsigned int tag = STACK_OVERFLOW_DETECTION_TAG;
|
||||
const unsigned int tags = STACK_OVERFLOW_DETECTION_SIZE / sizeof (tag);
|
||||
unsigned int *tagp = (unsigned int *)(self + 1);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < tags; i++)
|
||||
tagp[i] = tag;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_task_stack_detection_check (HevTaskStack *self)
|
||||
{
|
||||
#ifdef ENABLE_STACK_OVERFLOW_DETECTION
|
||||
const unsigned int tag = STACK_OVERFLOW_DETECTION_TAG;
|
||||
const unsigned int tags = STACK_OVERFLOW_DETECTION_SIZE / sizeof (tag);
|
||||
unsigned int *tagp = (unsigned int *)(self + 1);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < tags; i++)
|
||||
assert (tagp[i] == tag);
|
||||
#endif
|
||||
}
|
||||
|
||||
HevTaskStack *
|
||||
hev_task_stack_new (int size)
|
||||
{
|
||||
HevTaskStack *self;
|
||||
|
||||
size += STACK_OVERFLOW_DETECTION_SIZE;
|
||||
self = hev_malloc (sizeof (HevTaskStack) + size);
|
||||
if (self)
|
||||
self->size = size;
|
||||
|
||||
hev_task_stack_detection_mark (self);
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
hev_task_stack_destroy (HevTaskStack *self)
|
||||
{
|
||||
hev_task_stack_detection_check (self);
|
||||
hev_free (self);
|
||||
}
|
||||
|
||||
void *
|
||||
hev_task_stack_get_base (HevTaskStack *self)
|
||||
{
|
||||
return (void *)(self + 1);
|
||||
}
|
||||
|
||||
void *
|
||||
hev_task_stack_get_bottom (HevTaskStack *self)
|
||||
{
|
||||
return (void *)ALIGN_DOWN ((intptr_t)self + self->size, 16);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_STACK_BACKEND == STACK_HEAP */
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-stack-mmap.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 - 2025 everyone.
|
||||
Description :
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
#include "mem/api/hev-memory-allocator-api.h"
|
||||
|
||||
#include "hev-task-stack.h"
|
||||
|
||||
#if CONFIG_STACK_BACKEND == STACK_MMAP
|
||||
|
||||
#ifndef MAP_STACK
|
||||
#define MAP_STACK (0)
|
||||
#endif
|
||||
|
||||
struct _HevTaskStack
|
||||
{
|
||||
int size;
|
||||
void *stack;
|
||||
};
|
||||
|
||||
HevTaskStack *
|
||||
hev_task_stack_new (int size)
|
||||
{
|
||||
HevTaskStack *self;
|
||||
static int page_size;
|
||||
|
||||
if (!page_size)
|
||||
page_size = getpagesize ();
|
||||
|
||||
size = ALIGN_UP (size, page_size);
|
||||
#ifdef ENABLE_STACK_OVERFLOW_DETECTION
|
||||
size += page_size;
|
||||
#endif
|
||||
|
||||
self = hev_malloc (sizeof (HevTaskStack));
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
self->stack = mmap (NULL, size, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);
|
||||
if (self->stack == MAP_FAILED) {
|
||||
hev_free (self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_STACK_OVERFLOW_DETECTION
|
||||
if (mprotect (self->stack, page_size, PROT_NONE) < 0) {
|
||||
munmap (self->stack, size);
|
||||
hev_free (self);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
self->size = size;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
hev_task_stack_destroy (HevTaskStack *self)
|
||||
{
|
||||
munmap (self->stack, self->size);
|
||||
hev_free (self);
|
||||
}
|
||||
|
||||
void *
|
||||
hev_task_stack_get_base (HevTaskStack *self)
|
||||
{
|
||||
return self->stack;
|
||||
}
|
||||
|
||||
void *
|
||||
hev_task_stack_get_bottom (HevTaskStack *self)
|
||||
{
|
||||
return self->stack + self->size;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_STACK_BACKEND == STACK_MMAP */
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-stack.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2020 everyone.
|
||||
Description :
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_STACK_H__
|
||||
#define __HEV_TASK_STACK_H__
|
||||
|
||||
#define STACK_HEAP (0)
|
||||
#define STACK_MMAP (1)
|
||||
|
||||
typedef struct _HevTaskStack HevTaskStack;
|
||||
|
||||
HevTaskStack *hev_task_stack_new (int size);
|
||||
void hev_task_stack_destroy (HevTaskStack *self);
|
||||
|
||||
void *hev_task_stack_get_base (HevTaskStack *self);
|
||||
void *hev_task_stack_get_bottom (HevTaskStack *self);
|
||||
|
||||
#endif /* __HEV_TASK_STACK_H__ */
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2017 - 2025 everyone.
|
||||
Description :
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
#include "kern/core/hev-task-system-private.h"
|
||||
#include "mem/api/hev-memory-allocator-api.h"
|
||||
|
||||
#include "hev-task-private.h"
|
||||
|
||||
#include "hev-task.h"
|
||||
|
||||
#define HEV_TASK_STACK_SIZE (64 * 1024)
|
||||
|
||||
EXPORT_SYMBOL HevTask *
|
||||
hev_task_new (int stack_size)
|
||||
{
|
||||
HevTask *self;
|
||||
|
||||
self = hev_malloc0 (sizeof (HevTask));
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
self->ref_count = 1;
|
||||
self->next_priority = HEV_TASK_PRIORITY_DEFAULT;
|
||||
|
||||
if (stack_size < 0)
|
||||
stack_size = HEV_TASK_STACK_SIZE;
|
||||
|
||||
self->stack = hev_task_stack_new (stack_size);
|
||||
if (!self->stack) {
|
||||
hev_free (self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->stack_bottom = hev_task_stack_get_bottom (self->stack);
|
||||
self->sched_entity.task = self;
|
||||
|
||||
hev_list_add_tail (&hev_task_system_get_context ()->all_tasks,
|
||||
&self->list_node);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL HevTask *
|
||||
hev_task_ref (HevTask *self)
|
||||
{
|
||||
self->ref_count++;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL void
|
||||
hev_task_unref (HevTask *self)
|
||||
{
|
||||
self->ref_count--;
|
||||
if (self->ref_count)
|
||||
return;
|
||||
|
||||
hev_list_del (&hev_task_system_get_context ()->all_tasks, &self->list_node);
|
||||
|
||||
hev_task_stack_destroy (self->stack);
|
||||
hev_free (self);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL HevTask *
|
||||
hev_task_self (void)
|
||||
{
|
||||
return hev_task_system_get_context ()->current_task;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL HevTaskState
|
||||
hev_task_get_state (HevTask *self)
|
||||
{
|
||||
return self->state;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL void
|
||||
hev_task_set_priority (HevTask *self, int priority)
|
||||
{
|
||||
if (priority < HEV_TASK_PRIORITY_MIN)
|
||||
priority = HEV_TASK_PRIORITY_MIN;
|
||||
else if (priority > HEV_TASK_PRIORITY_MAX)
|
||||
priority = HEV_TASK_PRIORITY_MAX;
|
||||
|
||||
self->next_priority = priority;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_get_priority (HevTask *self)
|
||||
{
|
||||
return self->next_priority;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_add_fd (HevTask *self, int fd, unsigned int events)
|
||||
{
|
||||
HevTaskIOReactor *reactor;
|
||||
HevTaskIOReactorSetupEvent revents[HEV_TASK_IO_REACTOR_EVENT_GEN_MAX];
|
||||
int count;
|
||||
|
||||
reactor = hev_task_system_get_context ()->reactor;
|
||||
count = hev_task_io_reactor_setup_event_fd_gen (
|
||||
revents, fd, HEV_TASK_IO_REACTOR_OP_ADD, events, &self->sched_entity);
|
||||
return hev_task_io_reactor_setup (reactor, revents, count);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_mod_fd (HevTask *self, int fd, unsigned int events)
|
||||
{
|
||||
HevTaskIOReactor *reactor;
|
||||
HevTaskIOReactorSetupEvent revents[HEV_TASK_IO_REACTOR_EVENT_GEN_MAX];
|
||||
int count;
|
||||
|
||||
reactor = hev_task_system_get_context ()->reactor;
|
||||
count = hev_task_io_reactor_setup_event_fd_gen (
|
||||
revents, fd, HEV_TASK_IO_REACTOR_OP_MOD, events, &self->sched_entity);
|
||||
return hev_task_io_reactor_setup (reactor, revents, count);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_del_fd (HevTask *self, int fd)
|
||||
{
|
||||
HevTaskIOReactor *reactor;
|
||||
HevTaskIOReactorSetupEvent revents[HEV_TASK_IO_REACTOR_EVENT_GEN_MAX];
|
||||
int count;
|
||||
|
||||
reactor = hev_task_system_get_context ()->reactor;
|
||||
count = hev_task_io_reactor_setup_event_fd_gen (
|
||||
revents, fd, HEV_TASK_IO_REACTOR_OP_DEL, 0, NULL);
|
||||
return hev_task_io_reactor_setup (reactor, revents, count);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_add_whandle (HevTask *self, void *handle)
|
||||
{
|
||||
HevTaskIOReactor *reactor;
|
||||
HevTaskIOReactorSetupEvent revents[HEV_TASK_IO_REACTOR_EVENT_GEN_MAX];
|
||||
int count;
|
||||
|
||||
reactor = hev_task_system_get_context ()->reactor;
|
||||
count = hev_task_io_reactor_setup_event_whandle_gen (
|
||||
revents, handle, HEV_TASK_IO_REACTOR_OP_ADD, &self->sched_entity);
|
||||
if (count < 0)
|
||||
return -1;
|
||||
return hev_task_io_reactor_setup (reactor, revents, count);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_del_whandle (HevTask *self, void *handle)
|
||||
{
|
||||
HevTaskIOReactor *reactor;
|
||||
HevTaskIOReactorSetupEvent revents[HEV_TASK_IO_REACTOR_EVENT_GEN_MAX];
|
||||
int count;
|
||||
|
||||
reactor = hev_task_system_get_context ()->reactor;
|
||||
count = hev_task_io_reactor_setup_event_whandle_gen (
|
||||
revents, handle, HEV_TASK_IO_REACTOR_OP_DEL, NULL);
|
||||
if (count < 0)
|
||||
return -1;
|
||||
return hev_task_io_reactor_setup (reactor, revents, count);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL void
|
||||
hev_task_wakeup (HevTask *task)
|
||||
{
|
||||
hev_task_system_wakeup_task (task);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL void
|
||||
hev_task_yield (HevTaskYieldType type)
|
||||
{
|
||||
hev_task_system_schedule (type);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL unsigned int
|
||||
hev_task_sleep (unsigned int milliseconds)
|
||||
{
|
||||
HevTaskSystemContext *ctx;
|
||||
|
||||
if (milliseconds == 0)
|
||||
return 0;
|
||||
|
||||
ctx = hev_task_system_get_context ();
|
||||
return hev_task_timer_wait (ctx->timer, milliseconds, ctx->current_task);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL void
|
||||
hev_task_run (HevTask *self, HevTaskEntry entry, void *data)
|
||||
{
|
||||
/* Skip to run task that already running */
|
||||
if (self->state != HEV_TASK_STOPPED)
|
||||
return;
|
||||
|
||||
self->entry = entry;
|
||||
self->data = data;
|
||||
self->priority = self->next_priority;
|
||||
self->sched_key = self->next_priority;
|
||||
|
||||
hev_task_system_run_new_task (self);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL void
|
||||
hev_task_exit (void)
|
||||
{
|
||||
hev_task_system_kill_current_task ();
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL int
|
||||
hev_task_join (HevTask *task)
|
||||
{
|
||||
if (task->joiner)
|
||||
return -1;
|
||||
|
||||
task->joiner = hev_task_self ();
|
||||
|
||||
for (;;) {
|
||||
if (hev_task_get_state (task) == HEV_TASK_STOPPED)
|
||||
break;
|
||||
|
||||
hev_task_wakeup (task);
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL void *
|
||||
hev_task_get_data (HevTask *self)
|
||||
{
|
||||
return self->data;
|
||||
}
|
||||
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2017 - 2025 everyone.
|
||||
Description :
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_H__
|
||||
#define __HEV_TASK_H__
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HEV_TASK_PRIORITY_MIN (0)
|
||||
#define HEV_TASK_PRIORITY_MAX (15)
|
||||
|
||||
#define HEV_TASK_PRIORITY_HIGH HEV_TASK_PRIORITY_MIN
|
||||
#define HEV_TASK_PRIORITY_LOW HEV_TASK_PRIORITY_MAX
|
||||
|
||||
#define HEV_TASK_PRIORITY_DEFAULT (8)
|
||||
#define HEV_TASK_PRIORITY_REALTIME (0)
|
||||
|
||||
typedef struct _HevTask HevTask;
|
||||
typedef void (*HevTaskEntry) (void *data);
|
||||
|
||||
/**
|
||||
* HevTaskState:
|
||||
* @HEV_TASK_STOPPED: The task is not in any task system.
|
||||
* @HEV_TASK_RUNNING: The task is in a task system's running tree.
|
||||
* @HEV_TASK_WAITING: The task is in a task system's waiting poll.
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
HEV_TASK_STOPPED,
|
||||
HEV_TASK_RUNNING,
|
||||
HEV_TASK_WAITING,
|
||||
} HevTaskState;
|
||||
|
||||
/**
|
||||
* HevTaskYieldType:
|
||||
* @HEV_TASK_YIELD: Move task to yield waiting state.
|
||||
* @HEV_TASK_WAITIO: Move task to I/O waiting state.
|
||||
* @HEV_TASK_YIELD_COUNT: Maximum yield type count.
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
HEV_TASK_YIELD = 1,
|
||||
HEV_TASK_WAITIO,
|
||||
HEV_TASK_YIELD_COUNT,
|
||||
} HevTaskYieldType;
|
||||
|
||||
/**
|
||||
* hev_task_new:
|
||||
* @stack_size: stack size for task
|
||||
*
|
||||
* Creates a new task. If @stack_size = -1, the default stack size
|
||||
* will be used.
|
||||
*
|
||||
* Returns: a new #HevTask.
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
HevTask *hev_task_new (int stack_size);
|
||||
|
||||
/**
|
||||
* hev_task_ref:
|
||||
* @self: a #HevTask
|
||||
*
|
||||
* Increases the reference count of the @self by one.
|
||||
*
|
||||
* Returns: a #HevTask
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
HevTask *hev_task_ref (HevTask *self);
|
||||
|
||||
/**
|
||||
* hev_task_unref:
|
||||
* @self: a #HevTask
|
||||
*
|
||||
* Decreases the reference count of @self. When its reference count
|
||||
* drops to 0, the object is finalized (i.e. its memory is freed).
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
void hev_task_unref (HevTask *self);
|
||||
|
||||
/**
|
||||
* hev_task_self:
|
||||
*
|
||||
* Get the current task.
|
||||
*
|
||||
* Returns: a #HevTask
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
HevTask *hev_task_self (void);
|
||||
|
||||
/**
|
||||
* hev_task_get_state:
|
||||
* @self: a #HevTask
|
||||
*
|
||||
* Get the state of a task.
|
||||
*
|
||||
* Returns: a #HevTaskState
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
HevTaskState hev_task_get_state (HevTask *self);
|
||||
|
||||
/**
|
||||
* hev_task_set_priority:
|
||||
* @self: a #HevTask
|
||||
* @priority: priority
|
||||
*
|
||||
* Set the priority of a task. The value range of priority are [0-1],
|
||||
* with smaller values representing higher priorities.
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
void hev_task_set_priority (HevTask *self, int priority);
|
||||
|
||||
/**
|
||||
* hev_task_get_priority:
|
||||
* @self: a #HevTask
|
||||
*
|
||||
* Get the priority of a task.
|
||||
*
|
||||
* Returns: current priority of task
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
int hev_task_get_priority (HevTask *self);
|
||||
|
||||
/**
|
||||
* hev_task_add_fd:
|
||||
* @self: a #HevTask
|
||||
* @fd: a file descriptor
|
||||
* @events: a poll events. (e.g. POLLIN, POLLOUT)
|
||||
*
|
||||
* Add a file descriptor to I/O reactor of task system. The task system will
|
||||
* wake up the task when I/O events ready.
|
||||
*
|
||||
* Returns: When successful, returns zero. When an error occurs, returns -1.
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
int hev_task_add_fd (HevTask *self, int fd, unsigned int events);
|
||||
|
||||
/**
|
||||
* hev_task_mod_fd:
|
||||
* @self: a #HevTask
|
||||
* @fd: a file descriptor
|
||||
* @events: a poll events.
|
||||
*
|
||||
* Modify events of a file descriptor that added into I/O reactor of task
|
||||
* system.
|
||||
*
|
||||
* Returns: When successful, returns zero. When an error occurs, returns -1.
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
int hev_task_mod_fd (HevTask *self, int fd, unsigned int events);
|
||||
|
||||
/**
|
||||
* hev_task_del_fd:
|
||||
* @self: a #HevTask
|
||||
* @fd: a file descriptor
|
||||
*
|
||||
* Remove a file descriptor from I/O reactor of task system.
|
||||
*
|
||||
* Returns: When successful, returns zero. When an error occurs, returns -1.
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
int hev_task_del_fd (HevTask *self, int fd);
|
||||
|
||||
/**
|
||||
* hev_task_add_whandle:
|
||||
* @self: a #HevTask
|
||||
* @handle: a waitable handle
|
||||
*
|
||||
* Add a waitable handle to I/O reactor of task system. The task system will
|
||||
* wake up the task when signaled.
|
||||
*
|
||||
* Returns: When successful, returns zero. When an error occurs, returns -1.
|
||||
*
|
||||
* Since: 5.8
|
||||
*/
|
||||
int hev_task_add_whandle (HevTask *self, void *handle);
|
||||
|
||||
/**
|
||||
* hev_task_del_whandle:
|
||||
* @self: a #HevTask
|
||||
* @handle: a waitable handle
|
||||
*
|
||||
* Remove a waitable handle from I/O reactor of task system.
|
||||
*
|
||||
* Returns: When successful, returns zero. When an error occurs, returns -1.
|
||||
*
|
||||
* Since: 5.8
|
||||
*/
|
||||
int hev_task_del_whandle (HevTask *self, void *handle);
|
||||
|
||||
/**
|
||||
* hev_task_wakeup:
|
||||
* @self: a #HevTask
|
||||
*
|
||||
* Wake up a task. Don't switch tasks immediately.
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
void hev_task_wakeup (HevTask *task);
|
||||
|
||||
/**
|
||||
* hev_task_yield:
|
||||
* @type: type of #HevTaskYieldType
|
||||
*
|
||||
* Save current task context, pick a new task and switch to.
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
void hev_task_yield (HevTaskYieldType type);
|
||||
|
||||
/**
|
||||
* hev_task_sleep:
|
||||
* @milliseconds: time to sleep
|
||||
*
|
||||
* Like yield. The task will be waked up by two condition:
|
||||
* 1. Timer. time has elapsed.
|
||||
* 2. I/O events. The task will be waked up by file descriptors events.
|
||||
*
|
||||
* Returns: Zero if the requested time has elapsed, or
|
||||
* the number of milliseconds left to sleep.
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
unsigned int hev_task_sleep (unsigned int milliseconds);
|
||||
|
||||
/**
|
||||
* hev_task_usleep:
|
||||
* @microseconds: time to sleep
|
||||
*
|
||||
* Like yield. The task will be waked up by two condition:
|
||||
* 1. Timer. time has elapsed.
|
||||
* 2. I/O events. The task will be waked up by file descriptors events.
|
||||
*
|
||||
* Returns: Zero if the requested time has elapsed, or
|
||||
* the number of microseconds left to sleep.
|
||||
*
|
||||
* Deprecated: 5.4.0
|
||||
*/
|
||||
unsigned int hev_task_usleep (unsigned int microseconds);
|
||||
|
||||
/**
|
||||
* hev_task_run:
|
||||
* @self (transfer full): a #HevTask
|
||||
* @entry: A #HevTaskEntry
|
||||
* @data (nullable): a user data to passed to @entry
|
||||
*
|
||||
* Set the entry and data to the task, and add to running tree of task system.
|
||||
* The task will be really run after task system run or current task yield.
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
void hev_task_run (HevTask *self, HevTaskEntry entry, void *data);
|
||||
|
||||
/**
|
||||
* hev_task_exit:
|
||||
*
|
||||
* The function terminates the calling process immediately.
|
||||
*
|
||||
* Since: 1.4
|
||||
*/
|
||||
void hev_task_exit (void);
|
||||
|
||||
/**
|
||||
* hev_task_join:
|
||||
* @task: a #HevTask
|
||||
*
|
||||
* Join with a terminated task.
|
||||
*
|
||||
* Returns: When successful, returns zero. When an error occurs, returns -1.
|
||||
*
|
||||
* Since: 5.2.6
|
||||
*/
|
||||
int hev_task_join (HevTask *task);
|
||||
|
||||
/**
|
||||
* hev_task_get_data:
|
||||
* @self: a #HevTask
|
||||
*
|
||||
* Get the user data of a task that set by run.
|
||||
*
|
||||
* Returns: current data of task.
|
||||
*
|
||||
* Since: 3.3.4
|
||||
*/
|
||||
void *hev_task_get_data (HevTask *self);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_TASK_H__ */
|
||||
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-timer.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2018 - 2025 everyone.
|
||||
Description : Timer
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "hev-task-timer.h"
|
||||
#include "kern/core/hev-task-system-private.h"
|
||||
#include "mem/api/hev-memory-allocator-api.h"
|
||||
#include "lib/misc/hev-compiler.h"
|
||||
|
||||
typedef struct _HevTaskTimerNode HevTaskTimerNode;
|
||||
|
||||
struct _HevTaskTimer
|
||||
{
|
||||
HevRBTreeCached sort_tree;
|
||||
HevTaskSystemContext *ctx;
|
||||
};
|
||||
|
||||
struct _HevTaskTimerNode
|
||||
{
|
||||
HevRBTreeNode base;
|
||||
|
||||
struct timespec expire;
|
||||
HevTask *task;
|
||||
};
|
||||
|
||||
static inline int
|
||||
hev_task_timer_cmp (const struct timespec *a, const struct timespec *b)
|
||||
{
|
||||
if (a->tv_sec < b->tv_sec)
|
||||
return -1;
|
||||
if (a->tv_sec > b->tv_sec)
|
||||
return 1;
|
||||
|
||||
if (a->tv_nsec < b->tv_nsec)
|
||||
return -1;
|
||||
if (a->tv_nsec > b->tv_nsec)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
hev_task_timer_node_cmp (HevTaskTimerNode *a, HevTaskTimerNode *b)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = hev_task_timer_cmp (&a->expire, &b->expire);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
if (a < b)
|
||||
return -1;
|
||||
if (a > b)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_task_timer_get_curr (struct timespec *curr)
|
||||
{
|
||||
if (clock_gettime (CLOCK_MONOTONIC, curr) < 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_task_timer_get_expire (struct timespec *expire, unsigned int milliseconds)
|
||||
{
|
||||
expire->tv_sec += milliseconds / 1000;
|
||||
expire->tv_nsec += (milliseconds % 1000) * 1000000;
|
||||
if (expire->tv_nsec > 1000000000L) {
|
||||
expire->tv_sec++;
|
||||
expire->tv_nsec -= 1000000000L;
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
hev_task_timer_get_time (const struct timespec *curr,
|
||||
const struct timespec *expire)
|
||||
{
|
||||
time_t sec;
|
||||
long nsec;
|
||||
|
||||
sec = expire->tv_sec - curr->tv_sec;
|
||||
nsec = expire->tv_nsec - curr->tv_nsec;
|
||||
if (nsec < 0) {
|
||||
sec--;
|
||||
nsec += 1000000000L;
|
||||
}
|
||||
|
||||
if (sec < 0)
|
||||
return 0;
|
||||
|
||||
return (sec * 1000) + ((nsec + 999999) / 1000000);
|
||||
}
|
||||
|
||||
HevTaskTimer *
|
||||
hev_task_timer_new (void *ctx)
|
||||
{
|
||||
HevTaskTimer *self;
|
||||
|
||||
self = hev_malloc0 (sizeof (HevTaskTimer));
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
self->ctx = ctx;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
hev_task_timer_destroy (HevTaskTimer *self)
|
||||
{
|
||||
hev_free (self);
|
||||
}
|
||||
|
||||
int
|
||||
hev_task_timer_get_timeout (HevTaskTimer *self)
|
||||
{
|
||||
HevTaskTimerNode *this;
|
||||
HevRBTreeNode *node;
|
||||
struct timespec curr;
|
||||
|
||||
node = hev_rbtree_cached_first (&self->sort_tree);
|
||||
if (!node)
|
||||
return -1;
|
||||
|
||||
hev_task_timer_get_curr (&curr);
|
||||
this = container_of (node, HevTaskTimerNode, base);
|
||||
return hev_task_timer_get_time (&curr, &this->expire);
|
||||
}
|
||||
|
||||
static void
|
||||
hev_task_timer_wakeup (HevTaskTimer *self, const struct timespec *curr)
|
||||
{
|
||||
HevTaskTimerNode *this;
|
||||
HevRBTreeNode *node;
|
||||
|
||||
node = hev_rbtree_cached_first (&self->sort_tree);
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
this = container_of (node, HevTaskTimerNode, base);
|
||||
if (hev_task_timer_cmp (curr, &this->expire) < 0)
|
||||
return;
|
||||
|
||||
hev_task_system_wakeup_task_with_context (self->ctx, this->task);
|
||||
}
|
||||
|
||||
void
|
||||
hev_task_timer_wake (HevTaskTimer *self)
|
||||
{
|
||||
HevRBTreeNode *node;
|
||||
struct timespec curr;
|
||||
|
||||
node = hev_rbtree_cached_first (&self->sort_tree);
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
hev_task_timer_get_curr (&curr);
|
||||
hev_task_timer_wakeup (self, &curr);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
hev_task_timer_wait (HevTaskTimer *self, unsigned int milliseconds,
|
||||
HevTask *task)
|
||||
{
|
||||
HevTaskTimerNode curr_node, *node = &curr_node;
|
||||
HevRBTreeNode **new = &self->sort_tree.base.root, *parent = NULL;
|
||||
struct timespec curr;
|
||||
int leftmost = 1;
|
||||
|
||||
/* get expire time */
|
||||
hev_task_timer_get_curr (&node->expire);
|
||||
hev_task_timer_get_expire (&node->expire, milliseconds);
|
||||
node->task = task;
|
||||
|
||||
/* insert to sort tree */
|
||||
while (*new) {
|
||||
HevTaskTimerNode *this = container_of (*new, HevTaskTimerNode, base);
|
||||
int result = hev_task_timer_node_cmp (node, this);
|
||||
|
||||
parent = *new;
|
||||
if (result < 0) {
|
||||
new = &((*new)->left);
|
||||
} else {
|
||||
new = &((*new)->right);
|
||||
leftmost = 0;
|
||||
}
|
||||
}
|
||||
hev_rbtree_node_link (&node->base, parent, new);
|
||||
hev_rbtree_cached_insert_color (&self->sort_tree, &node->base, leftmost);
|
||||
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
|
||||
/* check current is first */
|
||||
if (&node->base == hev_rbtree_cached_first (&self->sort_tree))
|
||||
leftmost = 1;
|
||||
|
||||
/* remove from sort tree */
|
||||
hev_rbtree_cached_erase (&self->sort_tree, &node->base);
|
||||
|
||||
hev_task_timer_get_curr (&curr);
|
||||
if (leftmost)
|
||||
hev_task_timer_wakeup (self, &curr);
|
||||
|
||||
/* get remaining milliseconds */
|
||||
return hev_task_timer_get_time (&curr, &curr_node.expire);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-task-timer.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2018 - 2025 everyone.
|
||||
Description : Timer
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_TASK_TIMER_H__
|
||||
#define __HEV_TASK_TIMER_H__
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "kern/task/hev-task.h"
|
||||
#include "lib/rbtree/hev-rbtree-cached.h"
|
||||
|
||||
typedef struct _HevTaskTimer HevTaskTimer;
|
||||
|
||||
HevTaskTimer *hev_task_timer_new (void *ctx);
|
||||
void hev_task_timer_destroy (HevTaskTimer *self);
|
||||
|
||||
int hev_task_timer_get_timeout (HevTaskTimer *self);
|
||||
void hev_task_timer_wake (HevTaskTimer *self);
|
||||
|
||||
unsigned int hev_task_timer_wait (HevTaskTimer *self, unsigned int milliseconds,
|
||||
HevTask *task);
|
||||
|
||||
#endif /* __HEV_TASK_TIMER_H__ */
|
||||
Reference in New Issue
Block a user