QNX-HAM机制研究笔记

HAM(High Availability Manager)是QNX Neutrino操作系统中的一个重要组件,用于实现系统的高可用性和故障恢复。它作为一个自我监控的进程,能够检测和管理其他进程的异常情况,如进程死亡或失去心跳。当HAM检测到问题时,它可以执行预定义的动作,如重启进程或执行脚本。HAM通过Guardian进程确保自身的高可用性,即使HAM本身出现问题,Guardian也能接管并恢复状态。HAM支持多种条件和动作,允许开发者自定义监控和恢复策略。通过示例代码展示了如何使用HAM来监控和重启进程。

背景

高可用需求,在系统故障时减小故障的影响,尽量保证系统正常运行。

内容

是什么

HAM(High Availability Manager)是一个“智能看门狗”——一个高弹性的管理进程,它可以在系统服务或进程失败或不再响应时监视您的系统并执行多级恢复。作为一个自我监控的管理者,HAM对内部故障具有弹性。不管出于什么原因,如果HAM本身被异常地停止,它可以通过移交给一个称为“监护人”的镜像进程,立即并完全地重建自己的状态。
简单说,可以用守护机制做进程保活的。

术语

术语描述
entry实体,可理解为进程
condition条件,类似进程死亡这种时候
action动作,类似重新启动等具体行为

功能介绍

进程自我监控
进程可以自已选择监测的开始和结束时间,选择相关的触发条件和执行动作,类似“当我挂掉时,做什么事情”。
例:由于APP不是常驻内存,在执行一些可能CRASH的代码时,可请求HAM,当我出现异常,重启我。

监控外部应用
进程可以监控外部进程的状态,类似“当B挂掉了,做什么事情”。
例:Audio守护进程监控到Audio进程挂掉后,重启Audio。

监控全局
系统中一种虚拟进程,可以监控所有被监控的进程,类似“当任意进程挂掉,做什么事情”。
例:注册行为,在任意进程挂掉后,写日志。

QNX Neutrino架构的三个关键因素直接促成了内在 HA:

  • 微内核,单个内核逻辑更少,部分重启不太影响全局
  • POSIX 进程模型,单独的内存地址,可创建动态进程
  • 消息传递,标准消息传递,有利于任务解耦、任务简化和服务分发。

原理: HAM启动时会有一个Guardian进程,并且将状态数据保存在共享内存,若HAM进程挂掉,则Guardian进程会取代HAM进程。

是谁启动的进程

  • QNX启动HAM进程,HAM管理需要监控的进程。
  • 可以直接执行ham以启动ham进程。
  • 不需要使用ham时可通过hamctrl -stop 停止ham,也可以调用ham_stop()

可以接收哪些状态

ConditionDescription
CONDDEATH进程中止。
CONDABNORMALDEATH进程异常中止。
CONDDETACH断开HAM。
CONDATTACH连接上HAM。
CONDHBEATMISSEDHIGH进程失去心跳达最大次数。
CONDHBEATMISSEDLOW进程失去心跳达最小次数。
CONDRESTART进程重新启动。
CONDRAISE
CONDSTATE进程状态发生变化。
CONDANY任何condition改变。

可执行哪些动作

ActionDescription
ham_action_restart()重启。
ham_action_execute()执行一段脚本。
ham_action_notify_pulse()发送PULSE事件。
ham_action_notify_signal()发送系统信号事件。
ham_action_notify_pulse_node()
ham_action_notify_signal_node()
ham_action_waitfor()等待。
ham_action_heartbeat_healthy()
ham_action_log()输出日志。

怎么用

译自QXN 官方demo

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <thread>
#include <chrono>
#include <iostream>
#include <process.h>
#ifdef QNX
#include <ha/ham.h>
#endid

int main(int argc, char** argv)
{
#ifdef QNX
    printf("HAM Prepar~\n");
    int status;
    char* inetdpath;
    ham_entity_t* ehdl;
    ham_condition_t* chdl;
    ham_action_t* ahdl;
    int inetdpid;
	// 新启一个进程
    inetdpath = strdup("/usr/bin/picherdemo/helloworld -D");
	// 连接HAM
    ham_connect(0);
	// 将进程交给HAM监控
    ehdl = ham_attach("inetd", ND_LOCAL_NODE, inetdpid, inetdpath, 0);
    if (ehdl != NULL)
    {
		//添加条件,当进程“death”时
        chdl = ham_condition(ehdl, CONDDEATH, "death", HREARMAFTERRESTART);
        if (chdl != NULL) {
			//添加动作,重启进程
            ahdl = ham_action_restart(chdl, "restart", inetdpath,
                HREARMAFTERRESTART);
            if (ahdl == NULL)
                printf("add action failed\n");
        }
        else
            printf("add condition failed\n");
    }
    else
        printf("add entity failed\n");
	//关闭与HAM的连接
    ham_disconnect(0);
#endif // QNX
    while (true) {
        printf("Process id: %d\n ", getpid());
        std::cout << "Thread id:\n"<< std::this_thread::get_id();
        std::this_thread::sleep_for(std::chrono::seconds(5));
    }

	return 0;
}

小结

HAM机制是QNX原生机制,通过监控进程状态做到进程的重启。

参考

QNX-Hight Available Framework Guide
posix 线程
QNX 系统 HAM 应用分析及实现

你正在为 **QNX Neutrino 7.1.0** 系统在 **AArch64(ARM64)架构** 上进行交叉编译,并使用了 `./configure` 脚本配置一个项目(很可能是 `libunwind` 或其他底层库)。你的目标是正确地构建适用于 QNX 的二进制文件。 当前命令基本结构是对的,但有一些关键点需要**修正和优化**以确保成功交叉编译。下面我会详细解释如何修改并提供正确的参数建议。 --- ### ✅ 正确的 `configure` 命令写法(推荐版本) ```bash ./configure \ --host=aarch64-unknown-nto-qnx7.1.0 \ --build=x86_64-pc-linux-gnu \ --target=aarch64-unknown-nto-qnx7.1.0 \ --disable-tests \ CC="aarch64-unknown-nto-qnx7.1.0-gcc" \ CXX="aarch64-unknown-nto-qnx7.1.0-g++" \ AR="aarch64-unknown-nto-qnx7.1.0-ar" \ RANLIB="aarch64-unknown-nto-qnx7.1.0-ranlib" \ LD="aarch64-unknown-nto-qnx7.1.0-ld" \ STRIP="aarch64-unknown-nto-qnx7.1.0-strip" \ CFLAGS="-march=armv8-a -O3 -fPIC" \ CXXFLAGS="-march=armv8-a -O3 -fPIC" \ LDFLAGS="-lsocket -lexit" ``` --- ### 🔍 修改说明与问题分析 #### ❌ 问题 1:`AR`, `RANLIB`, `LD`, `STRIP` 工具命名错误 你在原命令中使用了: ```bash AR=aarch64-unknown-nto-qnx7.1.0-gcc-ar ``` 但实际上 QNX 提供的标准工具链前缀下,这些工具应该是独立的二进制文件,而不是通过 GCC 包装器调用。正确的名称是: | 错误写法 | 正确写法 | |--------|--------| | `gcc-ar` → `ar` | `aarch64-unknown-nto-qnx7.1.0-ar` | | `gcc-ranlib` → `ranlib` | `aarch64-unknown-nto-qnx7.1.0-ranlib` | > ⚠️ `gcc-ar` 是 GNU Binutils 中用于插件支持的包装器,在 QNX 工具链中通常不存在或不兼容。 ✅ 应改为: ```bash AR=aarch64-unknown-nto-qnx7.1.0-ar RANLIB=aarch64-unknown-nto-qnx7.1.0-ranlib ``` --- #### ✅ 添加 `--build` 和 `--target`(可选但推荐) 虽然 `--host` 是必须的,但在某些 Autotools 配置中,缺少 `--build` 可能导致检测失败。 - `--build`: 本地编译环境(通常是 `x86_64-pc-linux-gnu`) - `--host`: 目标运行平台(即你要交叉编译到的平台) - `--target`: 主要用于编译器工具链开发,一般可以省略,但如果构建的是工具链则需设置 示例: ```bash --build=x86_64-pc-linux-gnu \ --host=aarch64-unknown-nto-qnx7.1.0 \ ``` --- #### ✅ CFLAGS 补充 `-fPIC`(重要!) 如果你要生成共享库(`.so`),必须添加 `-fPIC`,否则链接会报错(relocation error)。 ```bash CFLAGS="-march=armv8-a -O3 -fPIC" CXXFLAGS="-march=armv8-a -O3 -fPIC" ``` --- #### ✅ LDFLAGS:QNX 特殊库依赖 QNX 的网络、线程等功能可能依赖额外库,如: - `-lsocket`:网络编程所需 - `-lexit`:某些系统调用需要 - `-lcpp` 或 `-lc++`:C++ 支持(如果启用 C++) 根据实际需求添加: ```bash LDFLAGS="-lsocket -lexit" ``` 如果是 C++ 项目: ```bash LDFLAGS="-lcpp -lsocket -lexit" ``` --- #### ✅ 使用 `CC=` 和 `CXX=` 显式指定编译器 这一步你已经做得很好,保持即可。 --- ### 🧪 验证工具链是否存在 请确认你的 PATH 中包含 QNX 工具链,或者使用完整路径测试某个工具: ```bash aarch64-unknown-nto-qnx7.1.0-gcc --version aarch64-unknown-nto-qnx7.1.0-ar --version ``` 如果没有该命令,请检查以下几点: 1. 是否已安装 QNX SDP 7.1? 2. 是否将 `$QNX_HOST/usr/bin` 加入了 `PATH`? ```bash export QNX_HOST=/path/to/qnx710/host/linux/x86_64 export PATH=$QNX_HOST/usr/bin:$PATH ``` --- ### 💡 其他建议 #### 如果 configure 报错 “cannot run C compiled programs” 这是常见的交叉编译问题,表示 configure 尝试运行一个编译后的程序(比如 test executable),但在目标平台上无法执行。 ✅ 解决方法:添加 `--disable-some-feature` 或手动告诉 config 某些结果: ```bash ac_cv_func_mmap_file=yes ``` 或者直接跳过运行测试: ```bash ./configure ... --build=x86_64-pc-linux-gnu --host=aarch64-unknown-nto-qnx7.1.0 \ ax_cv_cxx_compile_cxx11=yes \ ac_cv_func_mmap_fixed_mapped=yes \ am_cv_libtool_disable_static=yes ``` 具体变量可通过查看 `config.log` 找出失败项后绕过。 --- ### 🛠 示例:完整脚本(保存为 build.sh) ```bash #!/bin/bash export QNX_HOST=/opt/qnx710/host/linux/x86_64 export PATH=$QNX_HOST/usr/bin:$PATH ./configure \ --build=x86_64-pc-linux-gnu \ --host=aarch64-unknown-nto-qnx7.1.0 \ --disable-tests \ CC=aarch64-unknown-nto-qnx7.1.0-gcc \ CXX=aarch64-unknown-nto-qnx7.1.0-g++ \ AR=aarch64-unknown-nto-qnx7.1.0-ar \ RANLIB=aarch64-unknown-nto-qnx7.1.0-ranlib \ LD=aarch64-unknown-nto-qnx7.1.0-ld \ STRIP=aarch64-unknown-nto-qnx7.1.0-strip \ CFLAGS="-march=armv8-a -O3 -fPIC" \ CXXFLAGS="-march=armv8-a -O3 -fPIC" \ LDFLAGS="-lsocket -lexit" make clean && make -j$(nproc) ``` --- ### ✅ 成功标志 - `config.status` 生成成功 - `make` 编译通过 - 输出 `.a` 或 `.so` 文件可用 `file libxxx.so` 检查: ```bash file .libs/libunwind.so # 输出应类似: # libunwind.so: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值