日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux内核关闭网络巨帧xenomai,xenomai内核解析--双核系统调用(二)--应用如何区分xenomai/linux系统调用或服务...

發布時間:2024/8/23 linux 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux内核关闭网络巨帧xenomai,xenomai内核解析--双核系统调用(二)--应用如何区分xenomai/linux系统调用或服务... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

版權聲明:本文為本文為博主原創文章,轉載請注明出處。如有錯誤,歡迎指正。

1. 引出問題

上一篇文章xenomai內核解析--雙核系統調用(一)以X86處理器為例,分析了xenomai內核調用的流程,讀了以后可能會覺得缺了點什么,你可能會有以下疑問:

系統中的兩個內核都是POSIX接口實現系統調用,那么我寫一個POSIX接口的應用程序,怎樣知道它調用的內核,或者說怎樣成為運行在cobalt內核的RT應用,而不是普通linux應用?

對于同一個POSIX接口,可能我的程序中,既需要xenomai內核提供服務(xenomai 系統調用),又需要調用linux內核提供服務(linux內核系統調用),或者說既有libcobalt,又有glibc庫,他們是如何實現或區分的?

2. 編譯鏈接

對于問題1,答案是:由編譯時鏈接的庫決定,如果普通的編譯,則該應用編譯后是一個普通linux運用。如果要編譯為xenomai應用,則需要鏈接到xenomai庫,那如何設置編譯鏈接參數?編譯安裝xenomai庫后,可通過執行/usr/bin/xeno-config來獲取。

$/usr/bin/xeno-config --help

xeno-config --verbose

--core=cobalt

--version="3.1"

--cc="gcc"

--ccld="/usr/bin/wrap-link.sh gcc"

--arch="x86"

--prefix="/usr"

--library-dir="/usr/lib"

Usage xeno-config OPTIONS

Options :

--help

--v,--verbose

--version

--cc

--ccld

--arch

--prefix

--[skin=]posix|vxworks|psos|alchemy|rtdm|smokey|cobalt

--auto-init|auto-init-solib|no-auto-init

--mode-check|no-mode-check

--cflags

--ldflags

--lib*-dir|libdir|user-libdir

--core

--info

--compat

復制代碼

例如編譯一個POSIX接口的實時應用,參數--cflags表示編譯,指定接口(skin)--posix,就能得到編譯該程序的gcc參數了:

$/usr/bin/xeno-config --posix --cflags

-I/usr/include/xenomai/cobalt -I/usr/include/xenomai -D_GNU_SOURCE -D_REENTRANT -fasynchronous-unwind-tables -D__COBALT__ -D__COBALT_WRAP__

復制代碼

再看鏈接,--ldflags表示鏈接,如下得到鏈接參數:

$/usr/bin/xeno-config --ldflags --posix

-Wl,--no-as-needed -Wl,@/usr/lib/cobalt.wrappers -Wl,@/usr/lib/modechk.wrappers /usr/lib/xenomai/bootstrap.o -Wl,--wrap=main -Wl,--dynamic-list=/usr/lib/dynlist.ld -L/usr/lib -lcobalt -lmodechk -lpthread -lrt

復制代碼

這樣就將POSIX接口源碼編譯成一個xenomai可執行程序了。通常我們會將獲取編譯參數的操作直接放到Makefile里,編譯時直接執行獲取使用,這里給一個簡單的Makefile示例如下:

XENO_CONFIG := /usr/xenomai/bin/xeno-config

PROJPATH = .

CFLAGS := $(shell $(XENO_CONFIG) --posix --alchemy --cflags)

LDFLAGS := $(shell $(XENO_CONFIG) --posix --alchemy --ldflags)

INCFLAGS= -I$(PROJPATH)/include/

EXECUTABLE := rt-task

src = $(wildcard ./*.c)

obj = $(patsubst %.c, %.o, $(src))

all: $(EXECUTABLE)

$(EXECUTABLE): $(obj)

$(CC) -g -o $@ $^ $(INCFLAGS) $(CFLAGS) $(LDFLAGS)

%.o:%.c

$(CC) -g -o $@ -c $< $(INCFLAGS) $(CFLAGS) $(LDFLAGS)

.PHONY: clean

clean:

rm -f $(EXECUTABLE) $(obj)

復制代碼

3. libcobalt中的實現

下面來看問題2,既然我們已將一個接口鏈接到實時內核庫libcobalt,當然由實時內核庫libcobalt來區分該發起linux內核調用還是xenomai內核系統。與上一篇文章一樣,以一個POSIX接口pthread_cretate()來解析libcobalt中的實現。

xenomai線程的創建流程比較復雜,需要先讓linux創建普通線程,然后再由xenomai創建該線程的shadow 線程,即xenomai調度的實時線程,很符合我們上面的提出的問題2。 說到這先簡答介紹一下xenomai實時線程的創建,詳細的創建流程后面會寫專門寫一篇文章解析,敬請期待。

pthread_cretate()不是一個系統調用,由NPTL(Native POSIX Threads Library)實現(NPTL是Linux 線程實現的現代版,由UlrichDrepper 和Ingo Molnar 開發,以取代LinuxThreads),NPTL負責一個用戶線程的用戶空間棧創建、內存分配、初始化等工作,與linux內核配合完成線程的創建。每一線程映射一個單獨的內核調度實體(KSE,Kernel Scheduling Entity)。內核分別對每個線程做調度處理。線程同步操作通過內核系統調用實現。

xenomai coblat作為實時任務的調度器,每個實時線程需要對應到 coblat調度實體,如果要創建實時線程就需要像linux那樣NPTL與linux 內核深度結合,那么coblat與libcoblat實現將會變得很復雜。在這里,xenomai使用了一種方式,由NPTL方式去完成實時線程實體的創建(linux部分),在普通線程的基礎上附加一些屬性,對應到xenomai cobalt內核實體時能被實時內核cobalt調度。

所以libcoblat庫中的實時線程創建函數pthread_cretate最后還是需要使用 glibc的pthread_cretate函數,xenomai只是去擴展glibc pthread_cretate創建的線程,使這個線程可以在實時內核cobalt調度。

pthread_cretate()在libcobalt中pthread.h文件中定義如下:

COBALT_DECL(int, pthread_create(pthread_t *ptid_r,

const pthread_attr_t *attr,

void *(*start) (void *),

void *arg));

復制代碼

COBALT_DECL宏在wrappers.h中如下,展開上面宏,會為pthread_create()生成三個類型函數:

#define __WRAP(call)__wrap_ ## call

#define __STD(call)__real_ ## call

#define __COBALT(call)__cobalt_ ## call

#define __RT(call)__COBALT(call)

#define COBALT_DECL(T, P)\

__typeof__(T) __RT(P);\

__typeof__(T) __STD(P); \

__typeof__(T) __WRAP(P)

int __cobalt_pthread_create(pthread_t *ptid_r,

const pthread_attr_t *attr,

void *(*start) (void *),

void *arg);

int __wrap_pthread_create(pthread_t *ptid_r,

const pthread_attr_t *attr,

void *(*start) (void *),

void *arg);

int __real_pthread_create(pthread_t *ptid_r,

const pthread_attr_t *attr,

void *(*start) (void *),

void *arg);

復制代碼

聲明pthread_create()函數的這三個宏意思為:

__RT(P):__cobalt_pthread_create 表示Cobalt實現的POSIX函數

__STD(P):__real_pthread_create表示原始的POSIX函數(Linux glibc實現),cobalt庫內部通過它來表示調用原始的POSIX函數(glibc NPTL).

__WRAP(P):__wrap_pthread_create是__cobalt_pthread_create 的弱別名,如果編譯器編譯時知道有該函數其它的實現,該函數就會被覆蓋。

主要關注前面兩個,對于最后一個宏,如果外部庫想覆蓋已有的函數,應提供其自己的__wrap_pthread_create()實現,來覆蓋Cobalt實現的pthread_create()版本。 原始的Cobalt實現仍可以引用為__COBALT(pthread_create)。由宏COBALT_IMPL來定義:

#define COBALT_IMPL(T, I, A)\

__typeof__(T) __wrap_ ## I A __attribute__((alias("__cobalt_" __stringify(I)), weak));\

__typeof__(T) __cobalt_ ## I A

復制代碼

最后cobalt庫函數pthread_create實現主體為(xenomai3.x.x\lib\cobalt\thread.c):

COBALT_IMPL(int, pthread_create, (pthread_t *ptid_r,

const pthread_attr_t *attr,

void *(*start) (void *), void *arg))

{

pthread_attr_ex_t attr_ex;

......

return pthread_create_ex(ptid_r, &attr_ex, start, arg);

}

復制代碼

COBALT_IMPL定義了__cobalt_pthread_create函數及該函數的一個弱別名__wrap_pthread_create,調用這兩個函數執行的是同一個函數體。

對于 NPTL函數pthread_create,在Cobalt庫里使用__STD()修飾,展開后即__real_pthread_create(),其實只是NPTL pthread_create()的封裝,__real_pthread_create()會直接調用 NPTL pthread_create,在lib\cobalt\wrappers.c實現如下:

/* pthread */

__weak

int __real_pthread_create(pthread_t *ptid_r,

const pthread_attr_t * attr,

void *(*start) (void *), void *arg)

{

return pthread_create(ptid_r, attr, start, arg);

}

復制代碼

它調用的就是glibc中的pthread_create函數.同樣我們接著__cobalt_pthread_create()看哪里調用的.

int pthread_create_ex(pthread_t *ptid_r,

const pthread_attr_ex_t *attr_ex,

void *(*start) (void *), void *arg)

{

......

__STD(sem_init(&iargs.sync, 0, 0));

ret = __STD(pthread_create(&lptid, &attr, cobalt_thread_trampoline, &iargs));/*__STD 調用標準庫的函數*/

if (ret) {

__STD(sem_destroy(&iargs.sync));

return ret;

}

__STD(clock_gettime(CLOCK_REALTIME, &timeout));

.....

}

復制代碼

下面再看另一個例子,實時任務在代碼中使用了linux的網絡套接字(xenomai任務也是一個linux任務,也可以使用linux來提供服務,只不過會影響實時性),有以下代碼,:

....

int sockfd,ret;

struct sockaddr_in addr;

sockfd = socket(PF_INET, SOCK_STREAM, 0);

.....

bind(sockfd, (struct sockaddr *)&my_addr,sizeof(struct sockaddr_in));

....

復制代碼

該代碼編譯時鏈接到了libcobalt,socket()函數即libcobalt中的__cobalt_socket(),其定義在xenomai-3.x.x\lib\cobalt\rtdm.c,如下:

COBALT_IMPL(int, socket, (int protocol_family, int socket_type, int protocol))

{

int s;

s = XENOMAI_SYSCALL3(sc_cobalt_socket, protocol_family,

socket_type, protocol);

if (s < 0) {

s = __STD(socket(protocol_family, socket_type, protocol));

}

return s;

}

復制代碼

可以看到,libcobalt中的函數會先嘗試調用實時內核cobalt的系統調用, 當cobalt系統調用不成功的時候才繼續嘗試通過__STD()宏來調用linux系統調用(cobalt內核根據socket協議類型參數PF_INET,SOCK_STREAM判斷),這樣就有效的分清了是linux系統調用還是xenomai系統調用。

一般情況下,可以直接在代碼中使用__STD()宏指明我們調用的linux內核的服務,修改如下:

....

int sockfd,ret;

struct sockaddr_in addr;

sockfd = __STD(socket(PF_INET, SOCK_STREAM, 0));

.....

__STD(bind(sockfd, (struct sockaddr *)&my_addr,sizeof(struct sockaddr_in)));

....

復制代碼

現在一切都明了了,一個函數編譯時通過參數鏈接到xenomai庫后,通過__STD()宏來表示使用linux接口。

4. 總結

在實時程序或實時庫libcobalt中,通過__STD()宏來表示使用linux接口。

對于一個未指明的接口,libcobalt會先嘗試發起xenomai系統調用,不成功會接著嘗試linux內核系統調用。

總結

以上是生活随笔為你收集整理的linux内核关闭网络巨帧xenomai,xenomai内核解析--双核系统调用(二)--应用如何区分xenomai/linux系统调用或服务...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。