2016-09-28 35 views
2

由於與NDK12和NDK13b2,我在想「移植」 libx264的使用信號()(和ndk12失蹤bsd_signal())的使用的sigaction(),而不是發現最近出現的問題。如何將signal()移植到sigaction()?

問題是,我不太清楚簡單的&什麼是用sigaction()來代替signal()調用的最快方法。使用以下信號處理程序

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

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

這是有問題的x264_cpu_detect功能

對於所有的i看到的,它主要用於X264快照/普通/ cpu.c以下面的方式...目前,我猜我只需要解決ARM版本,但我';;仍然必須替換所有signal()sigaction()發生,所以我可能只是涵蓋他們兩個,以獲得東西建設...

僅供參考 - NDK13 beta2仍然有「不穩定的」libc和構建不會失敗部分,而是第一次調用其他地方的rand()函數......所以我運氣不佳,取代signal()調用可能比僅僅等待官方NDK13版本更好。我這樣做是爲了擺脫文本重定位的,所以我可以在API 24(安卓N)

的功能有問題的部分調用signal()運行庫(和doubango):

#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回要解決NDK13中的libc。然而,在它處於測試狀態的libc不穩定的情況下 - 它目前缺少rand()函數,只是等待它可能無法實現。但在最糟糕的情況下,我想我只能等待它並在發佈後重試。

但由於它目前是,我想使用該庫的預建版本有文本的遷移,以及正在運行新的API /版本的Android操作系統的手機拒絕。

EDIT2: 我也知道signal()通常作品引擎蓋下使用sigaction(),但也許我不會bsd_signal相關的建立,錯誤...因爲我懷疑,這其中ISN」使用它。它使用bsd_signal明顯,這可能是也可能不是同一個基礎的東西:/

+0

'signal()'究竟有什麼問題?你爲什麼想擺脫它? – Sergio

+0

由於NDK12沒有定義'bsd_signal'符號並引發編輯中提到的構建錯誤。 TL; DR =因爲它會導致構建錯誤。 – Shark

+0

但是你不在示例代碼中使用'bsd_signal()',那麼它與你的問題有什麼關係? –

回答

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包裝導出。

請注意,建議的兩個解決方案中沒有一個需要修改您的依賴關係的代碼。

+0

從我讀過的內容來看,NDK的人們正在考慮在NDK 13中加入'bsd_signal()',但是我並不完全相信我可以依靠那條信息,因爲它們的libc目前不穩定並且有點破(因爲它缺少'rand()') – Shark

+0

但基本上,您的解決方案#2只需要我編寫一小段C代碼(從仿生複製/粘貼bsd_signal()實現),並將其包含在構建過​​程中而不更改x264的代碼?很好,聽起來很有希望(y) – Shark

+0

@Shark完全沒有。只需重新編譯所使用的所有不作爲NDK一部分的庫。 –

2

的原因,我試圖擺脫信號的()是這些編譯錯誤[...]

你目前的代碼顯示中值得注意的問題signal()的功能,而鏈接器錯誤表示他們正在呼叫bsd_signal()(直接)。如果提供的代碼與出現的錯誤消息一起出現,那麼這隻能表示存在範圍內的宏或內聯函數,其擴展包括對bsd_signal()的調用。據推測,該宏命名爲signal(),以取代對真實signal()函數的調用。

如果這是你的宏/內聯函數,那麼你應該可以修復它,以調用sigaction()來代替(見下文)。另一方面,如果它是系統的宏/內聯函數,那麼系統的頭文件不對應於它的C庫。在這種情況下,在做其他事情之前,建立一致的構建環境是非常重要的。

所以真正的問題是這樣的:什麼是最快/最簡單最快//同時保持目前的功能,以取代signal()電話與sigaction()的人呢?

爲了回答這個問題,必須首先確定/神聖當前有哪些功能,或者被認爲是。POSIX允許使用signal()的語義來設置信號對除SIG_DFLSIG_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()語義),那麼您將使用的sa_flags成員來描述細節。如果您希望在處理程序運行時屏蔽任何其他信號,那麼您會希望使用sa_mask成員來指示。無論如何,你也可以考慮是否需要保留標誌或掩碼以及前面的處理程序。

在包含所有需要的系統標題後,您可以通過爲signal()定義您自己的宏(非內聯函數)來替代此調用signal()。如果你對signal()的調用分散在多個文件中,那麼你可能想把這樣一個宏定義放在一個本地頭文件中。

+0

我認爲NDK的'signal()'實現內嵌了'bsd_signal()'實現,但是我還沒有完全確定。但迄今爲止,這是我的主要猜疑。塞爾希奧的帖子證實了這一點。 – Shark

+1

@Shark,是的,內聯調用'bsd_signal()'是我描述的替代方法之一。如果你有一個這樣做的頭文件和一個不提供'bsd_signal()'的庫實現,那麼這兩者不會在一起。可能這是一個主要的錯誤,但更可能是由於不同版本的頭文件和庫存在損壞的生成環境。對此進行排序(以及之後執行乾淨構建)應該可以解決您提供的鏈接器錯誤。切換到'sigaction()'不是一個壞主意,但它可能不是強制性的。 –

+0

「可能這是一個主要的錯誤,但更可能是由於不同版本的頭文件和庫存在損壞的生成環境。」情況就是這樣。 @ serhio的答案涵蓋了最可能的原因。 –