從 Solaris 遷移到 x86 上的 Linux 指南
轉自:IBMdeveloperWorks
Solaris 被認為是風格和 Linux 最為接近的一種 UNIX,但是對於程式的遷移來說,他們在諸如記憶體映射、線程連同對自然語言的支援等領域還是有很大區別的。這個移植指南能夠為您在計劃將程式移植到 Linux/x86 上時提供一些建議,並且協助您理解研發環境和體系架構之間的區別。
內容:
int get_stack(void **StackPtr) { *StackPtr = 0; __asm__ __volatile__ ("movl %%esp, %0": "=m" (StackPtr) ); return(0); }
移植規劃
研發環境
體系架構和系統特有的區別
結束語
在 Solaris,下面這段範例程式碼讓您能夠擷取堆棧指標:
清單 2. 在 Solaris 上擷取堆棧指標
.section ".text"
.align 8
.global my_stack
.type my_stack,2
my_stack:
! Save stack pointer through 1st parameter
st %sp,[%o0]
! Compute size of frame in return result reg
retl
sub %fp,%sp,%o0
.size my_stack,(.-my_stack)
在 Linux x86 上,您能夠使用一個 compare 和 swap 操作來實現原子鎖。例如,下面是 Linux x86 上使用 compare 和 swap 操作的一個簡單實現:
清單 3. Linux x86 上的 Compare 和 swap 操作
bool_t My_CompareAndSwap(IN int *ptr, IN int old, IN int new)
{
unsigned char ret;
/* Note that sete sets a 'byte' not the word */
__asm__ __volatile__ (
" lock/n"
" cmpxchgl %2,%1/n"
" sete %0/n"
: "=q" (ret), "=m" (*ptr)
: "r" (new), "m" (*ptr), "a" (old)
: "memory");
return ret;
}
在 Solaris SPARC 上,加鎖的原子操作能夠如下實現:
清單 4. Solaris 上的原子鎖
.section ".text"
.align 8
.global My_Ldstub
.type My_Ldstub,2
My_Ldstub:
ldstub [%o0],%o0 ! Atomic load set
sll %o0,24,%o0 ! Zero fill ...
retl ! ... result register
srl %o0,24,%o0 ! ... and retrn
.size My_Ldstub,(.-My_Ldstub)
位元組順序(endianness)
由於 SPARC 採用的是 big-endian,而 x86 採用的是 little-endian,因此您需要考慮 endianness 的問題。
Endianness 的問題在以下這些情況中都變得很重要:移植客戶機要在異構網路環境中進行通訊的應用程式,將資料永久地儲存到磁碟上,產品跟蹤(在 SPARC 平台上所產生的跟蹤資訊必須能夠在 x86 平台上正確地格式化),連同其他相關領域。IA-64 Linux 核心預設使用 little-endian,但是也能夠使用 big-endian 的位元組順序。
系統調用
Solaris 系統調用使用了一種在 Linux 上是停用不同的命名和簽名機制,這在“從 Solaris 向 Linux on POWER 遷移指南” 中已介紹過了。以下這些系統調用現在在 RHEL4 中能夠使用:
* Waitid
* Putmsg
* putpmsg
* Getmsg
* getpmsg
Curses 庫
Linux 用於 xurses 庫的那些庫函數比 Solaris 更加類似於 AIX。例如,諸如 addwch 之類的函數在 Linux 中不受支援。有些函數,例如 mvchgat,在 Solaris 中不可用。當您將和 curses 有關的代碼從 Solaris 移植到 Linux 上時,很多代碼都需要重寫。
Terminal IO
Solaris 中的 termio 結構和 Linux 中的這個結構是不同的。Linux 中的 termio 結構多了幾個域,您能夠使用他們來配置輸入和輸出速度。
Linux 中 termio 結構的定義位於 /usr/include/bits/termios.h 文檔中,而 Solaris 中 termio 的定義則位於 /usr/include/sys/termios.h 文檔中。
IOCTL
執行 ioctl 能夠使用的選項在 Solaris 和 Linux 中是不同的。例如,要獲得資源的利用情況,您能夠向 ioctl 系統調用傳遞 PIOCUSAGE:
Return_code = ioctl("/proc/", PIOCUSAGE, &buff) ;
在 Linux 中,您必須直接從 /proc/ 目錄中讀取相關的文檔來獲得相關資訊,在 Linux 上不能使用 PIOCUSAGE 選項。在這兩種情況中,pid 是正在執行命令的當前進程的進程 id。
另外一個例子是當您希望擷取該進程的堆資訊時。在 Solaris 中,要擷取堆資訊,您能夠使用下面的方法:
Return_code = Ioctl("/proc/",PIOCPSINFO,&psinfo)
在這段代碼中,psinfo 是個 struct prpsinfo 結構;Prpsinfo.pr_size 就給出了該進程的堆大小。
在 Linux 中,正在使用的頁數能夠從 /proc//mem 和 /proc//stat 中獲得。頁面大小能夠使用系統調用 getpagesize 獲得。這兩個值(頁數和頁面大小)的乘積就是堆的當前大小。
Getopt
在 Linux 中,只有在配置了 POSIXLY_CORRECT 環境變數之後,getopt 調用才遵循 POSIX 標準。
假如配置了環境變數 POSIXLY_CORRECT,那麼對參數的分析一碰到非選項參數(以“-”開始的參數)就立即停止。 其餘的參數全部被解釋為非選項參數。
調用 shell 指令碼之間的區別
假如 shell 指令碼使用了 su 命令,就會派生一個子 shell。這種行為和 Solaris 不同,在 Solaris 中, su 命令不會派生一個新 shell。
假如您在 Linux 上執行命令 su - root,那麼 ps 命令的輸出就會如下所示:
30931 pts/4 00:00:00 su
31004 pts/4 00:00:00 ksh
在這段代碼中,30931 是進程 31004 的祖先進程。您可能要修改一些受到這種關係影響的指令碼。
重啟動時的裝置處理
從 RHEL4 開始,Linux 就採用了熱插拔子系統 udev 的概念。他提供了可配置的動態裝置命名的支援。裝置配置是在每次重新啟動時動態構建的。
例如,假如您有一個新目錄 /dev/dsk,那麼系統可能並不知道他的存在,這個目錄在重啟之後可能就會丟失。為了避免 /dev/dsk 目錄丟失的問題,能夠建立一個 /etc/udev/devices/dsk 目錄,這樣系統在重新啟動時就能夠維護這種資訊,因此即使系統重新啟動之後,/dev/dsk 也依然會存在。
核心參數
在 Solaris 中,核心參數能夠在 /etc/system 文檔中進行配置。在 Linux 中,核心參數能夠使用 sysctl 系統調用進行修改。能夠修改的參數在 /proc/sys/kernel 中都能夠看到,procfs 的支援對於 sysctl 正常工作來說是必需的。
訊號
訊號之間的區別在“Technical guide for porting applications from Solaris to Linux”中已周詳介紹過了。其他值得注意的一些區別是 Solaris 有 38 個訊號,而 Linux 使用了 31 個訊號,而且sigaction 結構也不相同。例如,在 Linux 中,sigaction 介面如下所示: 清單 5. Linux 中的 sigaction 結構
struct sigaction
{
/* Signal handler. */
#ifdef __USE_POSIX199309
union
{
/* Used if SA_SIGINFO is not set. */
__sighandler_t sa_handler;
/* Used if SA_SIGINFO is set. */
void (*sa_sigaction) (int, siginfo_t *, void *);
}
__sigaction_handler;
# define sa_handler __sigaction_handler.sa_handler
# define sa_sigaction __sigaction_handler.sa_sigaction
#else
__sighandler_t sa_handler;
#endif
/* Additional set of signals to be blocked. */
__sigset_t sa_mask;
/* Special flags. */
int sa_flags;
/* Restore handler. */
void (*sa_restorer) (void);
};
在 Solaris 中,sigaction 結構如下所示:
清單 6. Solaris 中的 sigaction 結構
struct sigaction {
int sa_flags;
union {
#ifdef __cplusplus
void (*_handler)(int);
#else
void (*_handler)();
#endif
#if defined(__EXTENSIONS__) || ((__STDC__ - 0 == 0) && !defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE)) || (_POSIX_C_SOURCE > 2) || defined(_XPG4_2)
void (*_sigaction)(int, siginfo_t *, void *);
#endif
} _funcptr;
sigset_t sa_mask;
#ifndef _LP64
int sa_resv[2];
#endif
};
由於所支援的訊號個數不同,siginfo_t 結構也不相同。對於 Linux,這能夠在 /usr/include/bits/signal.h 文檔中找到;對於 Solaris,這能夠在 /usr/include/sys/siginfo.h 文檔中找到。
線程支援和 IPC
有關 Linux on POWER 和 Solaris 之間進行移植的出版物已介紹了 Solaris 線程和 Linux 的 POSIX 線程(由 NPTL 庫提供)之間的區別。
我的經驗是,假如應用程式早已在 Solaris 上就使用了 POSIX 線程,那麼他們移植到使用基於 NPTL 線程的 Linux 上就很簡單。在 Linux 上還能夠利用一些新特性,例如進程共用互斥鎖,因此 Solaris 中使用 pthread 互斥鎖和條件變數的那些有關 IPC 機制的代碼在 Linux 中都能夠使用。
自然語言的支援
在 Solaris 中對於自然語言的支援的代碼也和 Linux 中可能會有所不同,或他們只是名字有所不同而已。在 Solaris 中大部分的 locales 和字碼頁在 Linux 中都有對應的內容。
結束語
從 Solaris 到 x86 上的 Linux 的移植工作在大部分情況中只是個重新編譯的過程,或對編譯器/連結器開關稍微進行一些修改。有時可能需要對某些平台特有的內容進行一些修改,例如加鎖、記憶體映射、線程,等等。您應該瞭解一下這些差異,並對移植好好進行一下規劃,從而減少移植所需要的時間。
參考資料
* 您能夠參閱本文在 developerWorks 全球網站上的 英文原文。
* 下載 XL C/C V7.0 編譯器。
* GNU binutils 用來和 XL C/C 和 GCC 一起產生對象。在 GNU Binutils 網站中有周詳的解釋。
* 下載 IBM Developer Kit for Linux, Java Technology Edition version 1.4.2。
* IBM 紅皮書 AIX 5L Porting Guide 周詳介紹了在將應用程式從其他基於 UNIX 的平台上移植到 AIX 5L 作業系統上所可能碰到的問題。
* Multithreaded Programming Guide 介紹了 POSIX 和 Solaris 線程 API,使用同步對象進行編程連同編譯多線程程式的內容。
* Migrating to Linux kernel 2.6 討論了將現有應用程式遷移到 2.6 版本的核心和專有 POSIX 線程庫(NPTL)的問題。
* 下載 Performance Inspector,並擷取有關該工具的更多資訊。
* 訪問 OProfile 的 Web 網站。
* 訪問 RPM.org,閱讀有關 RPM 的更多資訊。
* developerWorks 遷移專題 能夠協助研發者尋找工具、技術文章、線上教程、課程、論壇、Web 網站、定製服務連同其他形式的協助,從而協助他們快速實現各種硬體平台向 Linux 的遷移。
* “Technical guide for porting applications from Solaris to Linux, version 1.0”(developerWorks,2002 年)介紹了更多有關 Solaris 和 Linux 之間的區別,連同將應用程式從 Solaris 移植到 Linux 上的內容。
* Solaris to Linux Porting Guide 討論了從 7.x 系列的 Red Hat Linux 發行版本到 Solaris 移植的問題。
* “將公司專屬應用程式程式從 UNIX 移植到 Linux”(developerWorks,2005 年)討論了在進行大型移植實踐時要考慮的問題。
* “從 Solaris 向 Linux on POWER 遷移指南 ”(developerWorks,2005 年)是對本文的補充,其中提供了移植到基於 POWER 的系統上的 Linux 的一些指導方針和資源。
* “用 OProfile 完全瞭解效能”(developerWorks,2003 年)介紹了如何使用這個工具來分析效能,而不考慮硬體和軟體之間的異常互動。
* 在 developerWorks Linux 專區 中能夠找到更多為 Linux 研發者準備的資源。