DPDK(三):入門2---DPDK部分代碼解釋


一、access函數
1.函數功能:
檢查調用進程是否可以對指定的文件執行某種操作。
2.函數原型:
1)函數頭文件
#include <stdio.h>
#include <unistd.h>
int access(const char * pathname, int mode)
3)形參
pathname:需要檢測的文件路勁名
mode:需要測試的操作模式。
4)函數返回值說明
成功執行時,返回0。失敗返回-1,errno被設為以下的某個值 
EINVAL: 模式值無效 
EACCES: 文件或路徑名中包含的目錄不可訪問 
ELOOP : 解釋路徑名過程中存在太多的符號連接 
ENAMETOOLONG:路徑名太長 
ENOENT:路徑名中的目錄不存在或是無效的符號連接 
ENOTDIR: 路徑名中當作目錄的組件並非目錄 
EROFS: 文件系統只讀 
EFAULT: 路徑名指向可訪問的空間外 
EIO:輸入輸出錯誤 
ENOMEM: 不能獲取足夠的內核內存 
ETXTBSY:對程序寫入出錯
5)mode說明
R_OK 測試讀許可權
W_OK 測試寫許可權
X_OK 測試執行許可權
F_OK 測試文件是否存在
3.函數實例
access("test.txt", F_OK)==0) printf("File exist\n");

二、__attribute__ 機制詳解
__attribute__ 可以設置函數屬性(Function Attribute )、變量屬性(Variable Attribute )和類型屬性(Type Attribute )。
_attribute__ 語法格式為:__attribute__ ((attribute-list)),其位置約束為:放於聲明的尾部“ ;” 之前。
1、對結構體(struct )或共用體(union )進行屬性設置。
大致有六個參數值可以被設定,即:aligned(字節對齊), packed(取消字節對齊即一字節對齊), transparent_union(弱類型的聯合體), unused(變量或函數可能不使用,避免編譯告警), deprecated (不提倡使用的函數或變量,編譯器必須生成警告)和 may_alias 。
(1)aligned
struct m
{
char a;
int b;
short c;
}__attribute__((aligned(4))) mm;
(2)packed
typedef struct {
    double x;
    double y;
} __attribute__((packed)) position_t;
(3)transparent_union
typedef union {
int i ;
float f;
}U __attribute__((transparent_union));
void foo (U u)
{
static int s;
s += u.i;
printf("s = %d\n",s);
}
void caller(void){
foo(1);
foo(1.0f);
}
int main(void){
caller();
}
(4)unused
__attribute__((unused)) static void a(void)
{

printf("a\n");
}
}
2、函數屬性(Function Attribute)
GNU CC編譯選項添加 –Wall打開所有告警,函數屬性可以幫助開發者把一些特性添加到函數聲明中,從而可以使編譯器在錯誤檢查方面的功能更強大。
下面介紹幾個常見的函數屬性:
(1)__attribute__ format,該__attribute__屬性可以給被聲明的函數加上類似printf或者scanf的特征,它可以使編譯器檢查函數聲明和函數實際調用參數之間的格式化字符串是否匹配。
具體使用格式如下:
format (archetype, string-index, first-to-check)
__attribute__((format(printf,m,n)))
__attribute__((format(scanf,m,n)))
其中參數m與n的含義為:
m:第幾個參數為格式化字符串(format string);
n:從函數的第幾個參數開始按上述規則進行檢查,即參數“…”里的第一個參數在函數參數總數排在第幾。
舉例:有參數不匹配的情況就會報編譯告警。
1:

2:extern void myprint(const char *format,...)
_
__attribute__((format(printf,1,2)));

3:
4:void test()

5:{

6: myprint("i=%d\n",6);

7: myprint("i=%s\n",6);

8: myprint("i=%s\n","abc");

9: myprint("%s,%d,%d\n",1,2);

10:}

運行$gcc –Wall –c attribute.c attribute后,輸出結果為:

attribute.c: In function `test':
attribute.c:7: warning: format argument is not a pointer (arg 2)
attribute.c:9: warning: format argument is not a pointer (arg 2)
attribute.c:9: warning: too few arguments for format
(2)__attribute__ noreturn
該屬性通知編譯器函數從不返回值,當遇到類似函數需要返回值而卻不可能運行到返回值處就已經退出來的情況,該屬性可以避免出現錯誤信息。C庫函數中的abort()和exit()的聲明格式就采用了這種格式。
例如:extern void myexit() __attribute__((noreturn));之后,編譯不會再出現警告信息。
(3)__attribute__ const
該屬性只能用於帶有數值類型參數的函數上。當重復調用帶有數值參數的函數時,由於返回值是相同的,所以此時編譯器可以進行優化處理,除第一次需要運算外, 其它只需要返回第一次的結果就可以了,進而可以提高效率。
extern int square(int n) __attribute__ ((const));
...
for (i = 0; i < 100; i++ )  {
       total += square (5) + i;            

通過添加__attribute__((const))聲明,編譯器只調用了函數一次,以后只是直接得到了相同的一個返回值。
const參數不能用在帶有指針類型參數的函數中,因為該屬性不但影響函數的參數值,同樣也影響到了參數指向的數據,它可能會對代碼本身產生嚴重甚至是不可恢復的嚴重后果。
(4)__attribute__ constructor/destructor
若函數被設定為constructor屬性,則該函數會在 main()函數執行之前被自動的執行。類似的,若函數被設定為destructor屬性,則該函數會在main()函數執行之后或者exit()被調用后被自動的執行。擁有此類屬性的函數經常隱式的用在程序的初始化數據方面。
__attribute__((constructor)) void before_main() {

printf("--- %s\n", __func__);
}
}


__attribute__((destructor)) void after_main() {

printf("--- %s\n", __func__);
}
}

int main(int argc, char **argv) {

printf("--- %s\n", __func__);

exit(0);

printf("--- %s, exit ?\n", __func__);


return 0;
}
}
執行結果:
--- before_main

--- main

--- after_main
三、gcc的__builtin_函數介紹
1、__builtin_prefetch() 說明
原型:void __builtin_prefetch (const void *addr, ...)
__builtin_prefetch() 是 gcc 的一個內置函數。這個函數為流操作實現預抓取機制。使用這個函數通常可以減少緩存缺失和停頓,從而提高性能。但該函數也需要 CPU 的支持。

其中參數 addr 是個內存指針,它指向要預取的數據,我們人工需要判定這些數據是很快能訪問到的,或者說是它們就在最近的內存中 --- 一般來說,對於鏈表而言,各個節點在內存中基本上是緊挨着的,所以我們容易預取鏈表節點里的指針項。
該函數還有兩個可選參數,rw 和 locality 。
rw 是個編譯時的常數,或 1 或 0 。1 時表示寫(w),0 時表示讀(r) 。
locality 必須是編譯時的常數,也稱為“時間局部性”(temporal locality) 。時間局部性是指,如果程序中某一條指令一旦執行,則不久之后該指令可能再被執行;如果某數據被訪問,則不久之后該數據會被再次訪問。該值的范圍在 0 - 3 之間。為 0 時表示,它沒有時間局部性,也就是說,要訪問的數據或地址被訪問之后的不長的時間里不會再被訪問;為 3 時表示,被訪問的數據或地址具有高 時間局部性,也就是說,在被訪問不久之后非常有可能再次訪問;對於值 1 和 2,則分別表示具有低 時間局部性 和中等 時間局部性。該值默認為 3 。
2、__builtin_constant_p (exp)說明
判斷exp是否在編譯時就可以確定其為常量,如果exp為常量,該函數返回1,否則返回0。
3、__builtin_expect 說明
這個指令是GCC (version >= 2.96)提供給程序員使用的,作用是允許程序員將最有可能執行的分支告訴編譯器。這樣編譯器可以對代碼進行優化,以減少指令跳轉帶來的性能下降。

這個指令的寫法為:__builtin_expect(EXP, N)。
意思是:EXP==N的概率很大。
一般的使用方法是將__builtin_expect指令封裝為likely和unlikely宏。這兩個宏的寫法如下.
#define likely(x) __builtin_expect(!!(x), 1) //x很可能為真
#define unlikely(x) __builtin_expect(!!(x), 0) //x很可能為假
首先要明確:
if(likely(value)) //等價於 if(value)

if(unlikely(value)) //也等價於 if(value)
進一步了解原理可以反匯編看一下函數的跳轉順序,參考文檔:https://blog.csdn.net/grublinux/article/details/37543489
4、__builtin_ffs(x):返回x中最后一個為1的位是從后向前的第幾位,如__builtin_ffs(0x789)=1, __builtin_ffs(0x78c)=3。
5、__builtin_popcount(x):x中1的個數。
6、__builtin_parity(x):x中1的奇偶性。
7、__builtin_return_address(n):當前函數的第n級調用者的地址,用的最多的就是__builtin_return_address(0),即獲得當前函數的調用者的地址。
8、__builtin_types_compatible_p(type1, type2):判斷type1和type2是否是相同的數據類型,相同返回1,否則返回0。該函數不區分const/volatile這樣的修飾符,即int和const int被認為是相同的類型。
四、
五、asm volatile
六、pipe
#include<unistd.h>
int pipe(int filedes[2]);
返回值:成功,返回0,否則返回-1。參數數組包含pipe使用的兩個文件的描述符。fd[0]:讀管道,fd[1]:寫管道。
必須在fork()前調用pipe(),否則子進程不會繼承文件描述符。兩個進程不共享祖先進程,就不能使用pipe。但是可以使用命名管道,下面介紹。
當管道進行寫入操作的時候,如果寫入的數據小於128K則是非原子的,如果大於128K字節,緩沖區的數據將被連續地寫入管道,直到全部數據寫完為止,如果沒有進程讀取數據,則將一直阻塞。
2、命名管道FIFO
與管道不同的是:每個FIFO都有一個路徑與之關聯,從而允許無親緣關系的進程訪問。
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
這里pathname是路徑名,mode是sys/stat.h里面定義的創建文件的權限.
fifo時需要注意:
fifo管道是先調用mkfifo創建,然后再用open打開得到fd來使用.
在打開fifo時要注意,它是半雙工的的,一般不能使用O_RDWR打開,而只能用只讀或只寫打開.
   fifo可以用在非親緣關系的進程間,而它的真正用途是在服務器和客戶端之間. 由於它是半雙工的所以,如果要進行客戶端和服務器雙方的通信的話,
每個方向都必須建立兩個管道,一個用於讀,一個用於寫。
3、socketpair
#include <sys/types.h>
#include <sys/socket.h>
int socketpair(int domain, int type, int protocol, int sv[2]);
參數1(domain):表示協議族,在Linux下只能為AF_LOCAL或者AF_UNIX。(自從Linux 2.6.27后也支持SOCK_NONBLOCK和SOCK_CLOEXEC)
參數2(type):表示協議,可以是SOCK_STREAM或者SOCK_DGRAM。SOCK_STREAM是基於TCP的,而SOCK_DGRAM是基於UDP的
參數3(protocol):表示類型,只能為0
參數4(sv[2]):套節字柄對,該兩個句柄作用相同,均能進行讀寫雙向操作
返回結果: 0為創建成功,-1為創建失敗,並且errno來表明特定的錯誤號,具體錯誤號如下所述:
使用注意:
該函數只能用於UNIX域(LINUX)下。 
只能用於有親緣關系的進程(或線程)間通信。 
所創建的套節字對作用是一樣的,均能夠可讀可寫(而管道PIPE只能進行單向讀或寫)。 
在讀的時候,管道內必須有內容,否則將會阻塞;簡而言之,該函數是阻塞的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM