[英]How to port signal() to sigaction()?
由於最近發現了與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版本,但是我';; 仍然必須用sigaction()
替換所有signal()
,所以我可能只覆蓋了它們兩者以使事情建立起來...
僅供參考-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;
}
所以問題是這樣的:在保留當前功能的同時,用sigaction()
替換signal()
調用的最快/最簡單//最快的方法是什么?
編輯:我試圖擺脫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
帶回到bsd_signal
中的libc來解決。 但是,在處於不穩定狀態的libc處於beta狀態時,它目前缺少rand()函數,只是等待它可能無法解決問題。 但是在最壞的情況下,我想我只需要等待它,然后在發布后重試即可。
但就目前而言,我要使用的庫的預構建版本具有文本重定位功能,並且被運行較新API / android系統版本的手機所拒絕。
EDIT2:我也知道signal()
通常可以在后台使用sigaction()
signal()
來工作,但是也許我不會遇到與bsd_signal相關的構建錯誤...因為我懷疑這是沒有使用它。 顯然,它使用的是bsd_signal,它可能不是同一底層的東西:/
根據您問題中發布的信息,我看到以下幾點:
您已經預編譯了二進制文件,這些二進制文件是為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()
,例如,您可以使用此功能的實現添加額外的源文件。 您可以使用仿生的實現作為參考。 另請注意,此功能應標記為隱藏: __attribute__ ((visibility ("hidden")))
。 需libc.so
以防止將其放入DSO動態符號表,這可能會使動態鏈接器在具有libc.so
已經公開的功能的舊平台上造成libc.so
。
另外,先前通過類似的static
包裝器導出的另一個libc函數也可能需要類似的操作。
請注意,建議的兩個解決方案中沒有一個需要修改依賴項的代碼。
我試圖擺脫signal()的原因是這些構建錯誤[...]
您提供的代碼顯示了有問題的函數調用signal()
,而鏈接器錯誤表明它們正在直接調用bsd_signal()
)。 如果所提供的代碼與所提供的錯誤消息一起出現,則僅意味着存在一個范圍內的宏或內聯函數,其擴展包括對bsd_signal()
的調用。 大概將該宏命名為signal()
,以代替對實際signal()
函數的調用。
如果那是您的宏/內聯函數,那么您應該可以將其修復為調用sigaction()
(請參見下文)。 另一方面,如果它是系統的宏/內聯函數,則系統的頭文件不對應於其C庫。 在這種情況下,在執行其他任何操作之前,必須建立一個一致的構建環境。
所以問題是這樣的:在保留當前功能的同時,用
sigaction()
替換signal()
調用的最快/最簡單//最快的方法是什么?
為了回答這個問題,必須首先確定/確定當前功能是或應該是什么。 POSIX允許使用signal()
的語義將信號的處置方式設置為SIG_DFL
或SIG_IGN
以外的其他方式來改變。 具體來說,如果您為給定信號設置了自定義處理程序,則在接收到信號時,該信號的處置可能會或可能不會重置為其默認值。 另外,關於在處理程序的執行期間是否阻塞正在處理的信號的行為也有所不同。 解決該問題是引入sigaction()
的主要目的之一。
根據鏈接器錯誤,假設您習慣了BSD行為,即
oldsig = signal( SIGILL, sigill_handler );
將會
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;
}
如果需要不同的語義(例如,模擬SysV signal()
語義),則可以使用new_action
的sa_flags
成員來描述細節。 如果要在處理程序運行時屏蔽其他任何信號,則需要使用sa_mask
成員進行指示。 無論如何,您都可能會考慮是否需要保留標志或掩碼以及前一個處理程序。
您可以替換為呼叫signal()
定義自己的宏(不內聯函數) signal()
包括所有需要的系統頭后。 如果對signal()
調用分散在多個文件中,那么大概您想將這樣的宏定義放在本地頭文件中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.