由于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,它可能是也可能不是相同的基础:/
答案 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_IGN
或sigaction()
以外的任何其他值。具体来说,如果为给定信号设置自定义处理程序,则在收到信号时,该信号的处置可能会也可能不会重置为其默认值。另外,行为根据在处理程序的执行期间是否阻止正在处理的信号而变化。解决该问题是引入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()
的调用分布在多个文件中,那么您可能希望将这样的宏定义放在本地头文件中。