如何将signal()移植到sigaction()?

时间:2016-09-28 14:35:16

标签: android c android-ndk porting libx264

由于NDK12和NDK13b2最近发现的问题,我正在考虑移植' libx264使用signal()(和ndk12中缺少bsd_signal())来改为使用sigaction()。

问题是,我不太确定使用sigaction()替换signal()调用的简单和最快的方法是什么。

就我所知,它主要以x264-snapshot / common / cpu.c的形式用于以下方式:

使用以下信号处理程序:

static void sigill_handler( int sig )
{
    if( !canjump )
    {
        signal( sig, SIG_DFL );
        raise( sig );
    }

    canjump = 0;
    siglongjmp( jmpbuf, 1 );
}

这是有问题的x264_cpu_detect功能...目前,我猜我只需要解决ARM版本,但是我不想...仍然必须用signal()替换sigaction()的所有出现,所以我可能只是覆盖它们两个来构建东西......

仅供参考 - NDK13 beta2仍然存在"不稳定" libc和构建在这部分没有失败,而是在其他地方首次调用rand()函数...所以我运气不好并且替换signal()调用可能是比等待正式的NDK13版本更好。我这样做是为了摆脱文本重定位,这样我就可以在API 24(Android N)上运行库(和doubango)

调用signal()的函数中有问题的部分:

#elif SYS_LINUX

uint32_t x264_cpu_detect( void )
{
    static void (*oldsig)( int );

    oldsig = signal( SIGILL, sigill_handler );
    if( sigsetjmp( jmpbuf, 1 ) )
    {
        signal( SIGILL, oldsig );
        return 0;
    }

    canjump = 1;
    asm volatile( "mtspr 256, %0\n\t"
                  "vand 0, 0, 0\n\t"
                  :
                  : "r"(-1) );
    canjump = 0;

    signal( SIGILL, oldsig );

    return X264_CPU_ALTIVEC;
}
#endif

#elif ARCH_ARM

void x264_cpu_neon_test( void );
int x264_cpu_fast_neon_mrc_test( void );

uint32_t x264_cpu_detect( void )
{
    int flags = 0;
#if HAVE_ARMV6
    flags |= X264_CPU_ARMV6;

    // don't do this hack if compiled with -mfpu=neon
#if !HAVE_NEON
    static void (* oldsig)( int );
    oldsig = signal( SIGILL, sigill_handler );
    if( sigsetjmp( jmpbuf, 1 ) )
    {
        signal( SIGILL, oldsig );
        return flags;
    }

    canjump = 1;
    x264_cpu_neon_test();
    canjump = 0;
    signal( SIGILL, oldsig );
#endif

    flags |= X264_CPU_NEON;

    // fast neon -> arm (Cortex-A9) detection relies on user access to the
    // cycle counter; this assumes ARMv7 performance counters.
    // NEON requires at least ARMv7, ARMv8 may require changes here, but
    // hopefully this hacky detection method will have been replaced by then.
    // Note that there is potential for a race condition if another program or
    // x264 instance disables or reinits the counters while x264 is using them,
    // which may result in incorrect detection and the counters stuck enabled.
    // right now Apple does not seem to support performance counters for this test
#ifndef __MACH__
    flags |= x264_cpu_fast_neon_mrc_test() ? X264_CPU_FAST_NEON_MRC : 0;
#endif
    // TODO: write dual issue test? currently it's A8 (dual issue) vs. A9 (fast      mrc)
#endif
    return flags;
}

#else

uint32_t x264_cpu_detect( void )
{
    return 0;
}

所以问题是这样的:在保留当前功能的同时,用signal()替换sigaction()次呼叫的最快/最简单的最快方法是什么?

编辑: 我试图摆脱signal()的原因是这些构建错误:

/home/devshark/SCRATCH/doubango/thirdparties/android/armv5te/lib/dist/libx264.a(cpu.o):cpu.c:function sigill_handler: error: undefined reference to 'bsd_signal'

/home/devshark/SCRATCH/doubango/thirdparties/android/armv5te/lib/dist/libx264.a(cpu.o):cpu.c:function x264_cpu_detect: error: undefined reference to 'bsd_signal'
/home/devshark/SCRATCH/doubango/thirdparties/android/armv5te/lib/dist/libx264.a(cpu.o):cpu.c:function x264_cpu_detect: error: undefined reference to 'bsd_signal'

/home/devshark/SCRATCH/doubango/thirdparties/android/armv5te/lib/dist/libx264.a(cpu.o):cpu.c:function x264_cpu_detect: error: undefined reference to 'bsd_signal'

我已经知道这是一个已知的NDK12问题,可以通过将bsd_signal带回NDK13中的libc来解决。但是,在其中' beta状态与它不稳定的libc - 它目前缺少rand()函数,只是等待它可能无法解决问题。但在最糟糕的情况下,我想我只需要等待它并在它发布后重试。

但是就目前而言,我想要使用的库的预构建版本具有文本重定位功能,并且被运行较新API /版本的Android操作系统的手机拒绝。

EDIT2: 我也知道signal() 通常通过使用sigaction()工作,但可能我不会得到与bsd_signal相关的构建错误...因为我怀疑这个人没有使用它。它显然使用bsd_signal,它可能是也可能不是相同的基础:/

2 个答案:

答案 0 :(得分:2)

根据您提问中的信息,我看到了下一点:

  • 你有预建的二进制文件,它是为android-19或更低版本构建的(因为它们引用了bsd_signal())。

  • 您想要为android-21或更高版本编译代码,并将其与旧的目标预构建项链接。

正如您所知,在android-21之前,很多libc的函数在标题中被声明为static。实际上它们都是围绕更多通用函数的薄包装器,这些函数由libc二进制文件公开。旧版本的NDK在<signal.h>中有下一个定义:

/* the default is bsd */
static __inline__ __sighandler_t signal(int s, __sighandler_t f)
{
    return bsd_signal(s,f);
}

那是bsd_signal()引用在你的二进制文件中的位置。你有两种选择来解决它。

  • 完全针对android-21或更高版本重新编译您的依赖项。但请注意,它们不会在较旧的平台上运行。

  • 在您的代码中提供bsd_signal(),例如您可以添加一个额外的源文件与此功能的实现。您可以使用bionic's implementation作为参考。另请注意,此功能应标记为隐藏:__attribute__ ((visibility ("hidden")))。这需要防止将其放入DSO动态符号表,这可能会混淆具有libc.so已公开的功能的旧平台上的动态链接器。

对于另外的libc函数,可能还需要类似的操作,这些函数以前是通过类似的static包装器导出的。

请注意,提议的两个解决方案中没有一个需要修改依赖项的代码。

答案 1 :(得分:2)

  

我试图摆脱signal()的原因是这些构建错误[...]

您提供的代码显示调用signal()的函数,而链接器错误表明它们正在调用bsd_signal()(直接)。如果显示的代码与提供的错误消息一起使用,那么这只能表示存在范围内的宏或内联函数,其扩展包括对bsd_signal()的调用。据推测,该宏名为signal(),以替代对真实signal()函数的调用。

如果那是你的宏/内联函数,那么你应该可以修改它来代替调用sigaction()(见下文)。另一方面,如果它是系统的宏/内联函数,则系统的头文件与其C库不对应。在这种情况下,在执行任何其他操作之前,必须建立一致的构建环境。

  

所以问题是这样的:在保留当前功能的同时,用signal()sigaction()调用替换signal()调用的最快/最简单的最快方法是什么?

为了回答这个问题,首先必须确定/判断当前功能 或者应该是什么。 POSIX允许使用SIG_DFL的语义将信号的处置设置为SIG_IGNsigaction()以外的任何其他值。具体来说,如果为给定信号设置自定义处理程序,则在收到信号时,该信号的处置可能会也可能不会重置为其默认值。另外,行为根据在处理程序的执行期间是否阻止正在处理的信号而变化。解决该问题是引入oldsig = signal( SIGILL, sigill_handler ); 的主要目的之一。

假设,基于链接器错误,BSD行为是您习惯得到的,

的模拟
struct sigaction old_action;
struct sigaction new_action = {
    .sa_handler = sigill_handler
};

int result = sigaction(SIGILL, &new_action, &old_action);
if (result) {
    // handle error ...
} else {
    oldsig = old_action.sa_handler;
}

将是

signal()

如果您需要不同的语义(例如,模拟SysV sa_flags语义),那么您将使用new_action的{​​{1}}成员来描述详细信息。如果要在处理程序运行时屏蔽任何其他信号,那么您可能希望使用sa_mask成员来指示。在任何情况下,您还可以考虑是否需要保留标志或掩码以及前一个处理程序。

在包含所有需要的系统标头后,您可以通过为signal()定义自己的宏(非内联函数)来替换它来调用signal()。如果您对signal()的调用分布在多个文件中,那么您可能希望将这样的宏定义放在本地头文件中。