@@ -0,0 +1,6 @@
|
||||
# Copyright (2025) Beijing Volcano Engine Technology Ltd.
|
||||
# SPDX-License-Identifier: Apache License 2.0
|
||||
|
||||
|
||||
set(FRAMEWORK_SRCS ${CMAKE_CURRENT_LIST_DIR}/src/aios.c)
|
||||
set(FRAMEWORK_INC ${CMAKE_CURRENT_LIST_DIR}/inc)
|
||||
@@ -0,0 +1,5 @@
|
||||
# framework
|
||||
|
||||
## brief introduction
|
||||
|
||||
This directory is designed to facilitate communication between different business modules (functional modules). The main communication method is subscribing to (sub) and publishing (pub) events, and the externally provided interface files are located in the `inc` directory.
|
||||
@@ -0,0 +1,5 @@
|
||||
# framework
|
||||
|
||||
## 目录简介
|
||||
|
||||
本目录是为了方便不用业务模块(功能模块)相互间进行通信使用的,主要的方式是sub和pub event事件,对外提供的接口文件在inc。
|
||||
@@ -0,0 +1,125 @@
|
||||
// Copyright (2025) Beijing Volcano Engine Technology Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#ifndef AIOS_H_
|
||||
#define AIOS_H_
|
||||
|
||||
/* include ------------------------------------------------------------------ */
|
||||
#include "aios_config.h"
|
||||
#include "volc_list.h"
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* default configuration ---------------------------------------------------- */
|
||||
|
||||
#ifndef AIOS_MAX_ACTORS
|
||||
#define AIOS_MAX_ACTORS 8 // 默认最多8个Actor
|
||||
#endif
|
||||
|
||||
#ifndef AIOS_USE_ASSERT
|
||||
#define AIOS_USE_ASSERT 1 // 默认打开断言
|
||||
#endif
|
||||
|
||||
|
||||
#include "aios_def.h"
|
||||
|
||||
/* data struct -------------------------------------------------------------- */
|
||||
|
||||
// 状态返回值的定义
|
||||
typedef enum aios_ret {
|
||||
AIOS_Ret_Null = 0, // 无效值
|
||||
AIOS_Ret_Handled, // 已处理,不产生跳转
|
||||
AIOS_Ret_NotHandled, // 未处理,不产生跳转
|
||||
AIOS_Ret_Tran, // 跳转
|
||||
} aios_ret_t;
|
||||
|
||||
// 事件类
|
||||
struct aios_event;
|
||||
typedef void (*aios_event_free_handler)(const void *data);
|
||||
typedef struct aios_event {
|
||||
volc_list_head_t node;
|
||||
uint32_t sub; // 订阅者
|
||||
aios_event_id_t id; // 事件主题
|
||||
void *data; // 事件数据
|
||||
aios_event_free_handler free_handler; // 事件数据释放函数
|
||||
} aios_event_t;
|
||||
|
||||
// 数据结构 - 行为树相关 --------------------------------------------------------
|
||||
// 状态函数句柄的定义
|
||||
struct aios_session;
|
||||
typedef aios_ret_t (* aios_state_handler)(struct aios_session *const me, aios_event_t const * const e);
|
||||
|
||||
// 状态机类
|
||||
typedef struct aios_session {
|
||||
uint32_t priority : 5; // 优先级,0-31,数值越大优先级越高
|
||||
uint32_t enabled : 1; // 是否使能
|
||||
uint32_t reserve : 1; // 保留位
|
||||
volatile aios_state_handler state;
|
||||
} aios_session_t;
|
||||
|
||||
// api -------------------------------------------------------------------------
|
||||
// 对框架进行初始化,在各状态机初始化之前调用。
|
||||
void aios_init(int event_size);
|
||||
// 启动框架,放在main函数的末尾。
|
||||
void aios_run(void);
|
||||
// 停止框架的运行(不常用)
|
||||
// 停止框架后,框架会在执行完当前状态机的当前事件后,清空各状态机事件队列,清空事件池,
|
||||
// 不再执行任何功能,直至框架被再次启动。
|
||||
void aios_stop(void);
|
||||
|
||||
// 关于状态机 -----------------------------------------------
|
||||
// 状态机初始化函数
|
||||
void aios_session_init( aios_session_t * const me,
|
||||
uint8_t priority,
|
||||
void const * const parameter);
|
||||
void aios_session_start(aios_session_t * const me, aios_state_handler state_init);
|
||||
|
||||
aios_ret_t aios_tran(aios_session_t * const me, aios_state_handler state);
|
||||
|
||||
#define AIOS_TRAN(target) aios_tran((aios_session_t * )me, (aios_state_handler)target)
|
||||
#define AIOS_STATE_CAST(state) ((aios_state_handler)(state))
|
||||
|
||||
// 关于事件 -------------------------------------------------
|
||||
// 事件订阅
|
||||
void aios_event_sub(aios_session_t * const me, aios_event_id_t id);
|
||||
// 事件取消订阅
|
||||
void aios_event_unsub(aios_session_t * const me, aios_event_id_t id);
|
||||
// 事件订阅宏定义
|
||||
#define AIOS_EVENT_SUB(_evt) aios_event_sub(&(me->super), _evt)
|
||||
// 事件取消订阅宏定义
|
||||
#define AIOS_EVENT_UNSUB(_evt) aios_event_unsub(&(me->super), _evt)
|
||||
|
||||
// 发布事件(携带数据)
|
||||
int aios_event_pub(aios_event_id_t id, void *data, aios_event_free_handler free_handler);
|
||||
|
||||
// 发布周期性或延时事件
|
||||
void* aios_event_time_pub(aios_event_id_t id, uint32_t timeout_ms, uint32_t period_ms);
|
||||
|
||||
// 取消延时事件或者周期事件的发布
|
||||
void aios_event_time_cancel(void** timer);
|
||||
|
||||
/* port --------------------------------------------------------------------- */
|
||||
// void* aios_malloc(uint32_t size);
|
||||
// void aios_free(void* ptr);
|
||||
// void* aios_mutex_create(void);
|
||||
// void aios_mutex_lock(void* mutex);
|
||||
// void aios_mutex_unlock(void* mutex);
|
||||
// void aios_mutex_destroy(void** mutex);
|
||||
void aios_port_assert(uint32_t error_id);
|
||||
|
||||
/* hook --------------------------------------------------------------------- */
|
||||
|
||||
// 结束AIOS Nano的运行的时候,所调用的回调函数。
|
||||
void aios_hook_stop(void);
|
||||
|
||||
// 启动AIOS Nano的时候,所调用的回调函数
|
||||
void aios_hook_start(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright (2025) Beijing Volcano Engine Technology Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#ifndef AIOS_CONFIG_H__
|
||||
#define AIOS_CONFIG_H__
|
||||
|
||||
/* AIOS General Configuration --------------------------------------- */
|
||||
#define AIOS_MCU_TYPE 32
|
||||
#define AIOS_MAX_ACTORS 4
|
||||
#define AIOS_TEST_PLATFORM 64
|
||||
#define AIOS_USE_MAGIC 0
|
||||
|
||||
/* Assert Configuration ----------------------------------------------------- */
|
||||
#define AIOS_USE_ASSERT 1
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (2025) Beijing Volcano Engine Technology Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#ifndef AIOS_DEF_H__
|
||||
#define AIOS_DEF_H__
|
||||
|
||||
#include "aios_config.h"
|
||||
|
||||
#define AIOS_MAX_SLEEP_MS (1000 * 10)
|
||||
|
||||
typedef enum aios_event_id {
|
||||
// 系统事件
|
||||
Event_Null = 0,
|
||||
Event_Enter,
|
||||
Event_Exit,
|
||||
// 用户事件
|
||||
Event_User,
|
||||
} aios_event_id_t;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_SRC_HEAP_H_
|
||||
#define UV_SRC_HEAP_H_
|
||||
|
||||
#include <stddef.h> /* NULL */
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# define HEAP_EXPORT(declaration) __attribute__((unused)) static declaration
|
||||
#else
|
||||
# define HEAP_EXPORT(declaration) static declaration
|
||||
#endif
|
||||
|
||||
struct heap_node {
|
||||
struct heap_node* left;
|
||||
struct heap_node* right;
|
||||
struct heap_node* parent;
|
||||
};
|
||||
|
||||
/* A binary min heap. The usual properties hold: the root is the lowest
|
||||
* element in the set, the height of the tree is at most log2(nodes) and
|
||||
* it's always a complete binary tree.
|
||||
*
|
||||
* The heap function try hard to detect corrupted tree nodes at the cost
|
||||
* of a minor reduction in performance. Compile with -DNDEBUG to disable.
|
||||
*/
|
||||
struct heap {
|
||||
struct heap_node* min;
|
||||
unsigned int nelts;
|
||||
};
|
||||
|
||||
/* Return non-zero if a < b. */
|
||||
typedef int (*heap_compare_fn)(const struct heap_node* a,
|
||||
const struct heap_node* b);
|
||||
|
||||
/* Public functions. */
|
||||
HEAP_EXPORT(void heap_init(struct heap* heap));
|
||||
HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap));
|
||||
HEAP_EXPORT(void heap_insert(struct heap* heap,
|
||||
struct heap_node* newnode,
|
||||
heap_compare_fn less_than));
|
||||
HEAP_EXPORT(void heap_remove(struct heap* heap,
|
||||
struct heap_node* node,
|
||||
heap_compare_fn less_than));
|
||||
HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than));
|
||||
|
||||
/* Implementation follows. */
|
||||
|
||||
HEAP_EXPORT(void heap_init(struct heap* heap)) {
|
||||
heap->min = NULL;
|
||||
heap->nelts = 0;
|
||||
}
|
||||
|
||||
HEAP_EXPORT(void heap_node_init(struct heap_node* hnode)) {
|
||||
hnode->left = 0;
|
||||
hnode->parent = 0;
|
||||
hnode->right = 0;
|
||||
}
|
||||
|
||||
HEAP_EXPORT(int heap_node_is_empty(struct heap_node* hnode)) {
|
||||
return (hnode->left == 0 && hnode->parent == 0 && hnode->right == 0);
|
||||
}
|
||||
|
||||
HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap)) {
|
||||
return heap->min;
|
||||
}
|
||||
|
||||
/* Swap parent with child. Child moves closer to the root, parent moves away. */
|
||||
static void heap_node_swap(struct heap* heap,
|
||||
struct heap_node* parent,
|
||||
struct heap_node* child) {
|
||||
struct heap_node* sibling;
|
||||
struct heap_node t;
|
||||
|
||||
t = *parent;
|
||||
*parent = *child;
|
||||
*child = t;
|
||||
|
||||
parent->parent = child;
|
||||
if (child->left == child) {
|
||||
child->left = parent;
|
||||
sibling = child->right;
|
||||
} else {
|
||||
child->right = parent;
|
||||
sibling = child->left;
|
||||
}
|
||||
if (sibling != NULL)
|
||||
sibling->parent = child;
|
||||
|
||||
if (parent->left != NULL)
|
||||
parent->left->parent = parent;
|
||||
if (parent->right != NULL)
|
||||
parent->right->parent = parent;
|
||||
|
||||
if (child->parent == NULL)
|
||||
heap->min = child;
|
||||
else if (child->parent->left == parent)
|
||||
child->parent->left = child;
|
||||
else
|
||||
child->parent->right = child;
|
||||
}
|
||||
|
||||
HEAP_EXPORT(void heap_insert(struct heap* heap,
|
||||
struct heap_node* newnode,
|
||||
heap_compare_fn less_than)) {
|
||||
struct heap_node** parent;
|
||||
struct heap_node** child;
|
||||
unsigned int path;
|
||||
unsigned int n;
|
||||
unsigned int k;
|
||||
|
||||
newnode->left = NULL;
|
||||
newnode->right = NULL;
|
||||
newnode->parent = NULL;
|
||||
|
||||
/* Calculate the path from the root to the insertion point. This is a min
|
||||
* heap so we always insert at the left-most free node of the bottom row.
|
||||
*/
|
||||
path = 0;
|
||||
for (k = 0, n = 1 + heap->nelts; n >= 2; k += 1, n /= 2)
|
||||
path = (path << 1) | (n & 1);
|
||||
|
||||
/* Now traverse the heap using the path we calculated in the previous step. */
|
||||
parent = child = &heap->min;
|
||||
while (k > 0) {
|
||||
parent = child;
|
||||
if (path & 1)
|
||||
child = &(*child)->right;
|
||||
else
|
||||
child = &(*child)->left;
|
||||
path >>= 1;
|
||||
k -= 1;
|
||||
}
|
||||
|
||||
/* Insert the new node. */
|
||||
newnode->parent = *parent;
|
||||
*child = newnode;
|
||||
heap->nelts += 1;
|
||||
|
||||
/* Walk up the tree and check at each node if the heap property holds.
|
||||
* It's a min heap so parent < child must be true.
|
||||
*/
|
||||
while (newnode->parent != NULL && less_than(newnode, newnode->parent))
|
||||
heap_node_swap(heap, newnode->parent, newnode);
|
||||
}
|
||||
|
||||
HEAP_EXPORT(void heap_remove(struct heap* heap,
|
||||
struct heap_node* node,
|
||||
heap_compare_fn less_than)) {
|
||||
struct heap_node* smallest;
|
||||
struct heap_node** max;
|
||||
struct heap_node* child;
|
||||
unsigned int path;
|
||||
unsigned int k;
|
||||
unsigned int n;
|
||||
|
||||
if (heap->nelts == 0)
|
||||
return;
|
||||
|
||||
/* Calculate the path from the min (the root) to the max, the left-most node
|
||||
* of the bottom row.
|
||||
*/
|
||||
path = 0;
|
||||
for (k = 0, n = heap->nelts; n >= 2; k += 1, n /= 2)
|
||||
path = (path << 1) | (n & 1);
|
||||
|
||||
/* Now traverse the heap using the path we calculated in the previous step. */
|
||||
max = &heap->min;
|
||||
while (k > 0) {
|
||||
if (path & 1)
|
||||
max = &(*max)->right;
|
||||
else
|
||||
max = &(*max)->left;
|
||||
path >>= 1;
|
||||
k -= 1;
|
||||
}
|
||||
|
||||
heap->nelts -= 1;
|
||||
|
||||
/* Unlink the max node. */
|
||||
child = *max;
|
||||
*max = NULL;
|
||||
|
||||
if (child == node) {
|
||||
/* We're removing either the max or the last node in the tree. */
|
||||
if (child == heap->min) {
|
||||
heap->min = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Replace the to be deleted node with the max node. */
|
||||
child->left = node->left;
|
||||
child->right = node->right;
|
||||
child->parent = node->parent;
|
||||
|
||||
if (child->left != NULL) {
|
||||
child->left->parent = child;
|
||||
}
|
||||
|
||||
if (child->right != NULL) {
|
||||
child->right->parent = child;
|
||||
}
|
||||
|
||||
if (node->parent == NULL) {
|
||||
heap->min = child;
|
||||
} else if (node->parent->left == node) {
|
||||
node->parent->left = child;
|
||||
} else {
|
||||
node->parent->right = child;
|
||||
}
|
||||
|
||||
/* Walk down the subtree and check at each node if the heap property holds.
|
||||
* It's a min heap so parent < child must be true. If the parent is bigger,
|
||||
* swap it with the smallest child.
|
||||
*/
|
||||
for (;;) {
|
||||
smallest = child;
|
||||
if (child->left != NULL && less_than(child->left, smallest))
|
||||
smallest = child->left;
|
||||
if (child->right != NULL && less_than(child->right, smallest))
|
||||
smallest = child->right;
|
||||
if (smallest == child)
|
||||
break;
|
||||
heap_node_swap(heap, child, smallest);
|
||||
}
|
||||
|
||||
/* Walk up the subtree and check that each parent is less than the node
|
||||
* this is required, because `max` node is not guaranteed to be the
|
||||
* actual maximum in tree
|
||||
*/
|
||||
while (child->parent != NULL && less_than(child, child->parent))
|
||||
heap_node_swap(heap, child->parent, child);
|
||||
}
|
||||
|
||||
HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than)) {
|
||||
heap_remove(heap, heap->min, less_than);
|
||||
}
|
||||
|
||||
#undef HEAP_EXPORT
|
||||
|
||||
#endif /* UV_SRC_HEAP_H_ */
|
||||
@@ -0,0 +1,79 @@
|
||||
// Copyright (2025) Beijing Volcano Engine Technology Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#ifndef __CONV_AI_SRC_UTIL_VOLC_LIST_H__
|
||||
#define __CONV_AI_SRC_UTIL_VOLC_LIST_H__
|
||||
|
||||
// #include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef struct volc_list_head_t
|
||||
{
|
||||
struct volc_list_head_t *next, *prev;
|
||||
} volc_list_head_t;
|
||||
|
||||
#define __LIST_ADD(entry, before, after) \
|
||||
{ \
|
||||
volc_list_head_t *new_ = (entry), *prev = (before), *next = (after); \
|
||||
(next)->prev = (new_); \
|
||||
(new_)->next = (next); \
|
||||
(new_)->prev = (prev); \
|
||||
(prev)->next = (new_); \
|
||||
}
|
||||
#define volc_list_init(entry) \
|
||||
do \
|
||||
{ \
|
||||
(entry)->next = (entry); \
|
||||
(entry)->prev = (entry); \
|
||||
} while (0)
|
||||
#define volc_list_add(entry, base) \
|
||||
do \
|
||||
{ \
|
||||
__LIST_ADD((entry), (base), (base)->next); \
|
||||
} while (0)
|
||||
#define volc_list_add_after(entry, base) \
|
||||
do \
|
||||
{ \
|
||||
__LIST_ADD((entry), (base), (base)->next); \
|
||||
} while (0)
|
||||
#define volc_list_add_before(entry, base) \
|
||||
do \
|
||||
{ \
|
||||
__LIST_ADD((entry), (base)->prev, (base)); \
|
||||
} while (0)
|
||||
#define volc_list_add_head(entry, head) volc_list_add_after(entry, head)
|
||||
#define volc_list_add_tail(entry, head) volc_list_add_before(entry, head)
|
||||
#define volc_list_del(entry) \
|
||||
do \
|
||||
{ \
|
||||
(entry)->prev->next = (entry)->next; \
|
||||
(entry)->next->prev = (entry)->prev; \
|
||||
(entry)->next = (entry)->prev = (entry); \
|
||||
} while (0)
|
||||
#define volc_list_empty(head) ((head)->next == (head))
|
||||
#define volc_list_get_head(head) (volc_list_empty(head) ? (volc_list_head_t *)NULL : (head)->next)
|
||||
#define volc_list_get_tail(head) (volc_list_empty(head) ? (volc_list_head_t *)NULL : (head)->prev)
|
||||
#define volc_list_is_head(entry, head) ((entry)->prev == head)
|
||||
#define volc_list_is_tail(entry, head) ((entry)->next == head)
|
||||
#define volc_list_entry(ptr, type, member) ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))
|
||||
#define volc_list_for_each(h, head) for (h = (head)->next; h != (head); h = h->next)
|
||||
#define volc_list_for_each_safe(h, n, head) for (h = (head)->next, n = h->next; h != (head); h = n, n = h->next)
|
||||
#define volc_list_for_each_entry(p, head, type, member) \
|
||||
for (p = volc_list_entry((head)->next, type, member); &p->member != (head); \
|
||||
p = volc_list_entry(p->member.next, type, member))
|
||||
#define volc_list_for_each_entry_safe(p, t, head, type, member) \
|
||||
for (p = volc_list_entry((head)->next, type, member), t = volc_list_entry(p->member.next, type, member); \
|
||||
&p->member != (head); p = t, t = volc_list_entry(t->member.next, type, member))
|
||||
#define volc_list_get_head_entry(head, type, member) \
|
||||
(volc_list_empty(head) ? (type *)NULL : volc_list_entry(((head)->next), type, member))
|
||||
#define volc_list_get_tail_entry(head, type, member) \
|
||||
(volc_list_empty(head) ? (type *)NULL : volc_list_entry(((head)->prev), type, member))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* #define __CONV_AI_SRC_UTIL_VOLC_LIST_H__ */
|
||||
@@ -0,0 +1,646 @@
|
||||
// Copyright (2025) Beijing Volcano Engine Technology Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// include ---------------------------------------------------------------------
|
||||
#include "../inc/aios.h"
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include "heap-inl.h"
|
||||
|
||||
//socket
|
||||
#include <sys/socket.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
// time
|
||||
#include <sys/time.h>
|
||||
#include "volc_osal.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* assert ------------------------------------------------------------------- */
|
||||
#if (AIOS_USE_ASSERT != 0)
|
||||
#define AIOS_ASSERT(test_) do { if (!(test_)) { \
|
||||
aios_hook_stop(); \
|
||||
aios_port_assert(__LINE__); \
|
||||
} } while (0)
|
||||
#else
|
||||
#define AIOS_ASSERT(test_) ((void)0)
|
||||
#endif
|
||||
|
||||
// aios define ------------------------------------------------------------------
|
||||
|
||||
// **aios** ---------------------------------------------------------------------
|
||||
enum {
|
||||
EosRun_OK = 0,
|
||||
EosRun_NotEnabled,
|
||||
EosRun_NoEvent,
|
||||
EosRun_NoActor,
|
||||
EosRun_NoActorSub,
|
||||
|
||||
// Timer
|
||||
EosTimer_Empty,
|
||||
EosTimer_NotTimeout,
|
||||
EosTimer_ChangeToEmpty,
|
||||
|
||||
EosRunErr_NotInitEnd = -1,
|
||||
EosRunErr_ActorNotSub = -2,
|
||||
EosRunErr_MallocFail = -3,
|
||||
EosRunErr_SubTableNull = -4,
|
||||
EosRunErr_InvalidEventData = -5,
|
||||
EosRunErr_HeapMemoryNotEnough = -6,
|
||||
EosRunErr_TimerRepeated = -7,
|
||||
};
|
||||
|
||||
typedef struct timer_item {
|
||||
struct heap_node node;
|
||||
aios_event_id_t id;
|
||||
int64_t timeout_ms;
|
||||
uint32_t period_ms;
|
||||
} aios_timer_t;
|
||||
|
||||
typedef struct aios_tag {
|
||||
uint32_t *sub_table; // event sub table
|
||||
|
||||
uint32_t session_exist;
|
||||
uint32_t session_enabled;
|
||||
aios_session_t * sessions[AIOS_MAX_ACTORS];
|
||||
|
||||
uint32_t sub_general;
|
||||
void* event_mutex;
|
||||
volc_list_head_t event_list;
|
||||
|
||||
uint32_t time;
|
||||
void* timer_mutex;
|
||||
struct heap timer_heap;
|
||||
int fd[2];
|
||||
|
||||
uint8_t enabled : 1;
|
||||
uint8_t running : 1;
|
||||
uint8_t init_end : 1;
|
||||
uint8_t reserved : 5;
|
||||
} aios_t;
|
||||
|
||||
static aios_t aios;
|
||||
|
||||
// data ------------------------------------------------------------------------
|
||||
static const aios_event_t aios_event_table[Event_User] = {
|
||||
{{ 0 }, 0, Event_Null, 0, NULL},
|
||||
{{ 0 }, 0, Event_Enter, 0, NULL},
|
||||
{{ 0 }, 0, Event_Exit, 0, NULL},
|
||||
};
|
||||
|
||||
// macro -----------------------------------------------------------------------
|
||||
#define HSM_TRIG_(state_, topic_) \
|
||||
((*(state_))(me, &aios_event_table[topic_]))
|
||||
|
||||
// static function -------------------------------------------------------------
|
||||
static void aios_session_dispath(aios_session_t * const me, aios_event_t const * const e);
|
||||
|
||||
#ifndef VOLC_OFFSET
|
||||
#define VOLC_OFFSET(type, member) ((size_t) &((type *)0)->member)
|
||||
#endif
|
||||
|
||||
#ifndef VOLC_CONTAINER_OF
|
||||
#define VOLC_CONTAINER_OF(ptr, type, member) \
|
||||
((type *)((char *)(ptr) - VOLC_OFFSET(type, member)))
|
||||
#endif
|
||||
|
||||
static int __heap_node_less(const struct heap_node* a, const struct heap_node* b) {
|
||||
aios_timer_t* item_a = VOLC_CONTAINER_OF(a, aios_timer_t, node);
|
||||
aios_timer_t* item_b = VOLC_CONTAINER_OF(b, aios_timer_t, node);
|
||||
if (item_a->timeout_ms < item_b->timeout_ms) {
|
||||
return 1;
|
||||
}
|
||||
if (item_a->timeout_ms > item_b->timeout_ms) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return item_a->id > item_b->id;
|
||||
}
|
||||
|
||||
static int __set_block_mode(int sockfd, int block) {
|
||||
int flags = fcntl(sockfd, F_GETFL);
|
||||
if (flags < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (block) {
|
||||
if ((flags & O_NONBLOCK) != 0) {
|
||||
flags ^= O_NONBLOCK;
|
||||
}
|
||||
} else {
|
||||
flags |= O_NONBLOCK;
|
||||
}
|
||||
if (fcntl(sockfd, F_SETFL, flags) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __pipe(int fds[2]) {
|
||||
int ret = 0;
|
||||
fds[0] = -1;
|
||||
fds[1] = -1;
|
||||
int err = 0,opt = 0,write_fd = -1,read_fd = -1;
|
||||
read_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
|
||||
if (read_fd < 0) {
|
||||
ret = -1;
|
||||
goto err_out_label;
|
||||
}
|
||||
|
||||
struct sockaddr_in servaddr;
|
||||
uint32_t addr_len = sizeof(servaddr);
|
||||
memset(&servaddr, 0, sizeof(servaddr));
|
||||
servaddr.sin_family = AF_INET;
|
||||
servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
servaddr.sin_port = 0;
|
||||
|
||||
if (bind(read_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {
|
||||
ret = -1;
|
||||
goto err_out_label;
|
||||
}
|
||||
|
||||
// get port bind by system
|
||||
if (getsockname(read_fd, (struct sockaddr*)&servaddr, &addr_len) < 0) {
|
||||
ret = -1;
|
||||
goto err_out_label;
|
||||
}
|
||||
|
||||
if(servaddr.sin_addr.s_addr == htonl(INADDR_ANY))
|
||||
servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
|
||||
write_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
|
||||
int conn_ret = connect(write_fd, (struct sockaddr*)&servaddr, addr_len);
|
||||
|
||||
__set_block_mode(write_fd, 0);
|
||||
__set_block_mode(read_fd, 0);
|
||||
|
||||
fds[0] = read_fd;
|
||||
fds[1] = write_fd;
|
||||
err_out_label:
|
||||
if(ret < 0) {
|
||||
if (read_fd > 0) {
|
||||
close(read_fd);
|
||||
}
|
||||
if (write_fd > 0) {
|
||||
close(write_fd);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __interruptable_init(void) {
|
||||
if (__pipe(aios.fd) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __interruptable_deinit(void) {
|
||||
close(aios.fd[0]);
|
||||
close(aios.fd[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __interruptable_sleep(int64_t sleep_ms) {
|
||||
int ret = 0;
|
||||
char buf[64] = { 0 };
|
||||
fd_set readfds = { 0 };
|
||||
struct timeval tv = { 0 };
|
||||
if (sleep_ms < 0) {
|
||||
sleep_ms = AIOS_MAX_SLEEP_MS;
|
||||
}
|
||||
tv.tv_sec = sleep_ms / 1000;
|
||||
tv.tv_usec = (sleep_ms % 1000) * 1000;
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(aios.fd[0], &readfds);
|
||||
ret = select(aios.fd[0] + 1, &readfds, NULL, NULL, &tv);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (FD_ISSET(aios.fd[0], &readfds)) {
|
||||
if ((ret = read(aios.fd[0], buf, sizeof(buf))) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __interruptable_break(void) {
|
||||
char c[1] = { 0x5A};
|
||||
return (write(aios.fd[1], c, sizeof(c)) ? 0 : -1);
|
||||
}
|
||||
|
||||
static int64_t aios_get_time(void)
|
||||
{
|
||||
struct timeval time_crt;
|
||||
gettimeofday(&time_crt, (void *)0);
|
||||
int64_t time_crt_ms = time_crt.tv_sec * 1000 + time_crt.tv_usec / 1000;
|
||||
|
||||
return time_crt_ms;
|
||||
}
|
||||
|
||||
void aios_init(int event_size)
|
||||
{
|
||||
aios.enabled = true;
|
||||
aios.running = false;
|
||||
aios.session_exist = 0;
|
||||
aios.session_enabled = 0;
|
||||
aios.sub_table = NULL;
|
||||
|
||||
heap_init(&aios.timer_heap);
|
||||
if (__interruptable_init() < 0) {
|
||||
printf("aios_init: __interruptable_init fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
aios.sub_general = 0;
|
||||
volc_list_init(&aios.event_list);
|
||||
aios.event_mutex = volc_osal_mutex_create();
|
||||
if (NULL == aios.event_mutex) {
|
||||
printf("aios_init: event_mutex create fail\n");
|
||||
return;
|
||||
}
|
||||
// printf("event: %p\n", aios.event_mutex);
|
||||
|
||||
aios.init_end = 1;
|
||||
aios.time = 0;
|
||||
aios.timer_mutex = volc_osal_mutex_create();
|
||||
if (NULL == aios.timer_mutex) {
|
||||
printf("aios_init: timer_mutex create fail\n");
|
||||
return;
|
||||
}
|
||||
// printf("timer: %p\n", aios.timer_mutex);
|
||||
|
||||
aios.sub_table = (uint32_t *)volc_osal_malloc(sizeof(uint32_t) * event_size);
|
||||
if (NULL == aios.sub_table) {
|
||||
printf("aios_init: sub_table create fail\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void aios_deinit(void)
|
||||
{
|
||||
volc_osal_mutex_destroy(&aios.event_mutex);
|
||||
volc_osal_mutex_destroy(&aios.timer_mutex);
|
||||
__interruptable_deinit();
|
||||
}
|
||||
|
||||
void aios_sub_init(uint32_t *flag_sub, aios_event_id_t topic_max)
|
||||
{
|
||||
aios.sub_table = flag_sub;
|
||||
for (int i = 0; i < topic_max; i ++) {
|
||||
aios.sub_table[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t aios_evttimer(void)
|
||||
{
|
||||
int64_t system_time = aios_get_time();
|
||||
volc_osal_mutex_lock(aios.timer_mutex);
|
||||
if (aios.timer_heap.nelts == 0) {
|
||||
volc_osal_mutex_unlock(aios.timer_mutex);
|
||||
return -1;
|
||||
}
|
||||
aios_timer_t* item = VOLC_CONTAINER_OF(heap_min(&aios.timer_heap), aios_timer_t, node);
|
||||
if (item->timeout_ms > system_time) {
|
||||
volc_osal_mutex_unlock(aios.timer_mutex);
|
||||
return item->timeout_ms - system_time;
|
||||
}
|
||||
while (item->timeout_ms <= system_time) {
|
||||
heap_remove(&aios.timer_heap, &item->node, __heap_node_less);
|
||||
aios_event_pub(item->id, NULL, NULL);
|
||||
if (item->period_ms == 0) {
|
||||
continue;
|
||||
}
|
||||
item->timeout_ms += item->period_ms;
|
||||
heap_insert(&aios.timer_heap, &item->node, __heap_node_less);
|
||||
item = VOLC_CONTAINER_OF(heap_min(&aios.timer_heap), aios_timer_t, node);
|
||||
}
|
||||
volc_osal_mutex_unlock(aios.timer_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *aios_event_get_block(uint8_t priority);
|
||||
void aios_event_gc(void *data);
|
||||
|
||||
int aios_once(void)
|
||||
{
|
||||
int64_t timeout_ms = -1;
|
||||
if (aios.init_end == 0) {
|
||||
return (int)EosRunErr_NotInitEnd;
|
||||
}
|
||||
|
||||
if (aios.sub_table == NULL) {
|
||||
return (int)EosRunErr_SubTableNull;
|
||||
}
|
||||
|
||||
if (aios.enabled == false) {
|
||||
return (int)EosRun_NotEnabled;
|
||||
}
|
||||
|
||||
// 检查是否有状态机的注册
|
||||
if (aios.session_exist == 0 || aios.session_enabled == 0) {
|
||||
return (int)EosRun_NoActor;
|
||||
}
|
||||
|
||||
timeout_ms = aios_evttimer();
|
||||
|
||||
if (volc_list_empty(&aios.event_list)) {
|
||||
__interruptable_sleep(timeout_ms);
|
||||
return (int)EosRun_NoEvent;
|
||||
}
|
||||
|
||||
// 寻找到优先级最高,且有事件需要处理的Actor
|
||||
aios_session_t *session = NULL;
|
||||
uint8_t priority = AIOS_MAX_ACTORS;
|
||||
for (int i = (int)(AIOS_MAX_ACTORS - 1); i >= 0; i --) {
|
||||
if ((aios.session_exist & (1 << i)) == 0)
|
||||
continue;
|
||||
if ((aios.sub_general & (1 << i)) == 0)
|
||||
continue;
|
||||
session = aios.sessions[i];
|
||||
priority = i;
|
||||
break;
|
||||
}
|
||||
// 如果没有找到,返回
|
||||
if (priority == AIOS_MAX_ACTORS) {
|
||||
__interruptable_sleep(AIOS_MAX_SLEEP_MS);
|
||||
return (int)EosRun_NoActorSub;
|
||||
}
|
||||
|
||||
// 寻找当前Actor的最老的事件
|
||||
volc_osal_mutex_lock(aios.event_mutex);
|
||||
aios_event_t * e = aios_event_get_block(priority);
|
||||
AIOS_ASSERT(e != NULL);
|
||||
|
||||
volc_osal_mutex_unlock(aios.event_mutex);
|
||||
|
||||
// 对事件进行执行
|
||||
if ((aios.sub_table[e->id] & (1 << session->priority)) != 0)
|
||||
{
|
||||
// 执行状态的转换
|
||||
aios_session_dispath(session, e);
|
||||
}
|
||||
else {
|
||||
__interruptable_sleep(AIOS_MAX_SLEEP_MS);
|
||||
return (int)EosRunErr_ActorNotSub;
|
||||
}
|
||||
// 销毁过期事件与其携带的参数
|
||||
volc_osal_mutex_lock(aios.event_mutex);
|
||||
aios_event_gc(e);
|
||||
volc_osal_mutex_unlock(aios.event_mutex);
|
||||
|
||||
volc_osal_mutex_lock(aios.timer_mutex);
|
||||
if (aios.timer_heap.nelts == 0) {
|
||||
volc_osal_mutex_unlock(aios.timer_mutex);
|
||||
// __interruptable_sleep(AIOS_MAX_SLEEP_MS);
|
||||
} else {
|
||||
aios_timer_t* item = VOLC_CONTAINER_OF(heap_min(&aios.timer_heap), aios_timer_t, node);
|
||||
volc_osal_mutex_unlock(aios.timer_mutex);
|
||||
int sleep_ms = item->timeout_ms - aios_get_time();
|
||||
__interruptable_sleep(sleep_ms);
|
||||
}
|
||||
return (int)EosRun_OK;
|
||||
}
|
||||
|
||||
void aios_run(void)
|
||||
{
|
||||
aios_hook_start();
|
||||
|
||||
AIOS_ASSERT(aios.enabled == true);
|
||||
AIOS_ASSERT(aios.sub_table != 0);
|
||||
|
||||
aios.running = true;
|
||||
|
||||
while (aios.enabled) {
|
||||
int ret = aios_once();
|
||||
AIOS_ASSERT(ret >= 0);
|
||||
|
||||
if (ret == EosRun_NotEnabled) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void aios_hook_start(void)
|
||||
{
|
||||
}
|
||||
|
||||
void aios_hook_stop(void)
|
||||
{
|
||||
}
|
||||
|
||||
void aios_port_assert(uint32_t error_id)
|
||||
{
|
||||
printf("------------------------------------\n");
|
||||
printf("ASSERT >>> Module: EventOS Nano, ErrorId: %d.\n", (int)error_id);
|
||||
printf("------------------------------------\n");
|
||||
|
||||
while (1) {
|
||||
usleep(100000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void aios_stop(void)
|
||||
{
|
||||
aios.enabled = false;
|
||||
// TODO: release resource
|
||||
aios_hook_stop();
|
||||
}
|
||||
|
||||
// state machine ---------------------------------------------------------------
|
||||
void aios_session_init( aios_session_t * const me,
|
||||
uint8_t priority,
|
||||
void const * const parameter)
|
||||
{
|
||||
// 框架需要先启动起来
|
||||
AIOS_ASSERT(aios.enabled == true);
|
||||
AIOS_ASSERT(aios.running == false);
|
||||
AIOS_ASSERT(aios.sub_table != NULL);
|
||||
// 参数检查
|
||||
AIOS_ASSERT(me != (aios_session_t *)0);
|
||||
AIOS_ASSERT(priority < AIOS_MAX_ACTORS);
|
||||
|
||||
// 防止二次启动
|
||||
if (me->enabled == true)
|
||||
return;
|
||||
|
||||
// 检查优先级的重复注册
|
||||
AIOS_ASSERT((aios.session_exist & (1 << priority)) == 0);
|
||||
|
||||
// 注册到框架里
|
||||
aios.session_exist |= (1 << priority);
|
||||
aios.sessions[priority] = me;
|
||||
// 状态机
|
||||
me->priority = priority;
|
||||
me->state = NULL;
|
||||
}
|
||||
|
||||
void aios_session_start(aios_session_t * const me, aios_state_handler state_init)
|
||||
{
|
||||
aios_state_handler t;
|
||||
|
||||
me->state = state_init;
|
||||
me->enabled = true;
|
||||
aios.session_enabled |= (1 << me->priority);
|
||||
|
||||
// 进入初始状态,执行TRAN动作。这也意味着,进入初始状态,必须无条件执行Tran动作。
|
||||
t = me->state;
|
||||
aios_ret_t ret = t(me, &aios_event_table[Event_Null]);
|
||||
AIOS_ASSERT(ret == AIOS_Ret_Tran);
|
||||
ret = me->state(me, &aios_event_table[Event_Enter]);
|
||||
AIOS_ASSERT(ret != AIOS_Ret_Tran);
|
||||
}
|
||||
|
||||
// event -----------------------------------------------------------------------
|
||||
int aios_event_pub(aios_event_id_t id, void *data, aios_event_free_handler free_handler)
|
||||
{
|
||||
if (aios.init_end == 0) {
|
||||
return EosRunErr_NotInitEnd;
|
||||
}
|
||||
|
||||
if (aios.sub_table == NULL) {
|
||||
return EosRunErr_SubTableNull;
|
||||
}
|
||||
|
||||
// 保证框架已经运行
|
||||
if (aios.enabled == 0) {
|
||||
return EosRun_NotEnabled;
|
||||
}
|
||||
|
||||
if (aios.session_exist == 0) {
|
||||
return EosRun_NoActor;
|
||||
}
|
||||
|
||||
// 没有状态机使能,返回
|
||||
if (aios.session_enabled == 0) {
|
||||
return EosRun_NotEnabled;
|
||||
}
|
||||
// 没有状态机订阅,返回
|
||||
if (aios.sub_table[id] == 0) {
|
||||
return EosRun_NoActorSub;
|
||||
}
|
||||
|
||||
// 申请事件空间
|
||||
aios_event_t *e = (aios_event_t *)volc_osal_malloc(sizeof(aios_event_t));
|
||||
if (e == NULL) {
|
||||
return EosRunErr_MallocFail;
|
||||
}
|
||||
e->id = id;
|
||||
e->sub = aios.sub_table[e->id];
|
||||
aios.sub_general |= e->sub;
|
||||
e->data = data;
|
||||
e->free_handler = free_handler;
|
||||
volc_osal_mutex_lock(aios.event_mutex);
|
||||
volc_list_add_tail(&e->node, &aios.event_list);
|
||||
volc_osal_mutex_unlock(aios.event_mutex);
|
||||
__interruptable_break();
|
||||
|
||||
return EosRun_OK;
|
||||
}
|
||||
|
||||
void aios_event_sub(aios_session_t * const me, aios_event_id_t id)
|
||||
{
|
||||
aios.sub_table[id] |= (1 << me->priority);
|
||||
}
|
||||
|
||||
void aios_event_unsub(aios_session_t * const me, aios_event_id_t id)
|
||||
{
|
||||
aios.sub_table[id] &= ~(1 << me->priority);
|
||||
}
|
||||
|
||||
void* aios_event_time_pub(aios_event_id_t id, uint32_t time_ms, uint32_t period_ms)
|
||||
{
|
||||
aios_timer_t* item = (aios_timer_t *)volc_osal_malloc(sizeof(aios_timer_t));
|
||||
AIOS_ASSERT(item != NULL);
|
||||
memset(item, 0, sizeof(aios_timer_t));
|
||||
item->id = id;
|
||||
item->timeout_ms = aios_get_time() + time_ms;
|
||||
item->period_ms = period_ms;
|
||||
volc_osal_mutex_lock(aios.timer_mutex);
|
||||
heap_insert(&aios.timer_heap, &item->node, __heap_node_less);
|
||||
volc_osal_mutex_unlock(aios.timer_mutex);
|
||||
return (void *)item;
|
||||
}
|
||||
|
||||
void aios_event_time_cancel(void** timer)
|
||||
{
|
||||
if (timer == NULL || NULL == *timer) {
|
||||
return;
|
||||
}
|
||||
aios_timer_t* item = (aios_timer_t *)*timer;
|
||||
volc_osal_mutex_lock(aios.timer_mutex);
|
||||
heap_remove(&aios.timer_heap, &item->node, __heap_node_less);
|
||||
volc_osal_mutex_unlock(aios.timer_mutex);
|
||||
volc_osal_free(item);
|
||||
*timer = NULL;
|
||||
}
|
||||
|
||||
// state tran ------------------------------------------------------------------
|
||||
aios_ret_t aios_tran(aios_session_t * const me, aios_state_handler state)
|
||||
{
|
||||
me->state = state;
|
||||
|
||||
return AIOS_Ret_Tran;
|
||||
}
|
||||
|
||||
// static function -------------------------------------------------------------
|
||||
static void aios_session_dispath(aios_session_t * const me, aios_event_t const * const e)
|
||||
{
|
||||
aios_ret_t r;
|
||||
|
||||
AIOS_ASSERT(e != (aios_event_t *)0);
|
||||
|
||||
aios_state_handler s = me->state;
|
||||
aios_state_handler t;
|
||||
|
||||
r = s(me, e);
|
||||
if (r == AIOS_Ret_Tran) {
|
||||
t = me->state;
|
||||
r = s(me, &aios_event_table[Event_Exit]);
|
||||
AIOS_ASSERT(r == AIOS_Ret_Handled || r == AIOS_Ret_NotHandled);
|
||||
r = t(me, &aios_event_table[Event_Enter]);
|
||||
AIOS_ASSERT(r == AIOS_Ret_Handled || r == AIOS_Ret_NotHandled);
|
||||
me->state = t;
|
||||
}
|
||||
else {
|
||||
me->state = s;
|
||||
}
|
||||
}
|
||||
|
||||
/* heap library ------------------------------------------------------------- */
|
||||
void aios_event_gc(void *data)
|
||||
{
|
||||
aios_event_t * e = (aios_event_t *)data;
|
||||
if (e->sub == 0) {
|
||||
volc_list_del(&e->node);
|
||||
if (e->free_handler != NULL) {
|
||||
e->free_handler(e->data);
|
||||
}
|
||||
volc_osal_free(e);
|
||||
}
|
||||
aios.sub_general = 0;
|
||||
volc_list_for_each_entry(e, &aios.event_list, aios_event_t, node) {
|
||||
aios.sub_general |= e->sub;
|
||||
}
|
||||
}
|
||||
|
||||
void *aios_event_get_block(uint8_t priority)
|
||||
{
|
||||
aios_event_t * e = NULL;
|
||||
volc_list_for_each_entry(e, &aios.event_list, aios_event_t, node) {
|
||||
if ((e->sub & (1 << priority)) == 0) {
|
||||
continue;
|
||||
}
|
||||
e->sub &=~ (1 << priority);
|
||||
break;
|
||||
}
|
||||
|
||||
return (void *)e;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user