linux结构体对齐(linux结构体)
linux下怎樣進行攝像頭編程?
在linux下所有設備都是文件。所以對攝像頭的操作其實就是對文件的操作。USB攝像頭的設備文件就是在/dev目錄下的video0(假如只有一個攝像頭)。在linux下操作攝像頭就是使用v4l2對攝像頭進行的操作,操作步驟如下
打開設備文件。
int fd=open(”/dev/video0″,O_RDWR);
2. 取得設備的capability,看看設備具有什么功能,比如是否具有輸入,或者音頻輸入輸出等。VIDIOC_QUERYCAP,struct v4l2_capability
v4l2_std_id std;
do {
ret= ioctl(fd, VIDIOC_QUERYSTD, std);
} while (ret == -1 errno == EAGAIN);
switch (std) {
case V4L2_STD_NTSC:
//……
case V4L2_STD_PAL:
//……
}
3. 選擇輸入,一個設備可以有多個輸入。VIDIOC_S_INPUT,struct v4l2_input(可不要)
4. 設置的制式和幀格式,制式包括PAL,NTSC,幀的格式個包括寬度和高度等。
VIDIOC_S_STD,VIDIOC_S_FMT,struct v4l2_std_id,struct v4l2_format
struct v4l2_format fmt;
memset ( fmt, 0, sizeof(fmt) );
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 320;
fmt.fmt.pix.height = 240;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
if (ioctl(fd, VIDIOC_S_FMT, fmt) < 0)
{
printf("set format failedn");
//return 0;
}
5. 向驅動申請幀緩沖,一般不超過5個。struct v4l2_requestbuffers
struct v4l2_requestbuffers req;
memset(req, 0, sizeof (req));
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (ioctl(fd,VIDIOC_REQBUFS,req) == -1)
{
perror("VIDIOC_REQBUFS error n");
//return -1;
}
6.申請物理內存
將申請到的幀緩沖映射到用戶空間,這樣就可以直接操作采集到的幀了,而不必去復制。將申請到的幀緩沖全部入隊列,以便存放采集到的數據.VIDIOC_QBUF,struct v4l2_buffer
VideoBuffer* buffers = calloc( req.count, sizeof(VideoBuffer) );
printf("sizeof(VideoBuffer) is %dn",sizeof(VideoBuffer));
struct v4l2_buffer buf;
for (numBufs = 0; numBufs < req.count; numBufs++)
{
memset( buf, 0, sizeof(buf) );
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = numBufs;
if (ioctl(fd, VIDIOC_QUERYBUF, buf) < 0)
{
printf("VIDIOC_QUERYBUF errorn");
//return -1;
}
printf("buf len is %dn",sizeof(buf));
//內存映射
buffers.length = buf.length;
buffers.offset = (size_t) buf.m.offset;
buffers.start = mmap (NULL, buf.length,PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
printf("buffers.length = %d,buffers.offset = %d ,buffers.start = %dn",buffers.length,buffers.offset,buffers.start);
printf("buf2 len is %dn",sizeof(buffers.start));
if (buffers.start == MAP_FAILED)
{
perror("buffers errorn");
//return -1;
}
if (ioctl (fd, VIDIOC_QBUF, buf) < 0)
{
printf("VIDIOC_QBUF errorn");
//return -1;
}
}
7. 開始的采集。
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl (fd, VIDIOC_STREAMON, type) < 0)
{
printf("VIDIOC_STREAMON errorn");
// return -1;
}
8. 出隊列以取得已采集數據的幀緩沖,取得原始采集數據。VIDIOC_DQBUF, 將緩沖重新入隊列尾,這樣可以循環采集。VIDIOC_QBUF
if (ioctl(fd, VIDIOC_DQBUF, buf) < 0)
{
perror("VIDIOC_DQBUF failed.n");
//return -1;
}
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
unsigned char *ptcur = buffers.start;
DEBUG("buf.bytesused = %d n",buf.bytesused);
int i1;
for(i1=0; i1<buf.bytesused; i1++)
{
if((buffers.start == 0xFF) (buffers.start == 0xC4))
{
DEBUG("huffman table finded! nbuf.bytesused = %dnFFC4 = %d n",buf.bytesused,i1);
break;
}
}
if(i1 == buf.bytesused)printf("huffman table don't exist! n");
int i;
for(i=0; i<buf.bytesused; i++)
{
if((buffers.start == 0xFF) (buffers.start == 0xD8)) break;
ptcur++;
}
DEBUG("i=%d,FF=%02x,D8=%02xn",i,buffers.start,buffers.start);
int imagesize =buf.bytesused - i;
DEBUG("buf.bytesused = %d n",buf.bytesused);
DEBUG ("imagesize = %d n",imagesize);
9. 停止的采集。VIDIOC_STREAMOFF
10. 關閉設備。close(fd);
每天進步一點點――Linux下的磁盤緩存?
前段時間在開發一個使用SSD做緩存的系統,在高速寫入數據時會出現大量的磁盤緩存。太多的磁盤緩存如果沒有及時的寫入磁盤中,在機器出現問題時是非常危險的,這樣會導致很多的數據丟失,但是如果實時的將數據刷入磁盤中,這樣寫入效率有太低了。為了弄明白linux系統的這種磁盤寫入特性,最近深入的學習了一下。 VFS(Virtual File System)的存在使得linux可以兼容不同的文件系統,例如ext3、ext4、xfs、ntfs等等,其不僅具有為所有的文件系統實現一個通用的外接口的作用,還具有另一個與系統性能相關的重要作用——緩存。VFS中引入了高速磁盤緩存的機制,這屬于一種軟件機制,允許內核將原本存在磁盤上的某些信息保存在RAM中,以便對這些數據的進一步訪問能快速進行,而不必慢速訪問磁盤本身。高速磁盤緩存可大致分為以下三種:
目錄項高速緩存——主要存放的是描述文件系統路徑名的目錄項對象
索引節點高速緩存——主要存放的是描述磁盤索引節點的索引節點對象
頁高速緩存——主要存放的是完整的數據頁對象,每個頁所包含的數據一定屬于某個文件,同時,所有的文件讀寫操作都依賴于頁高速緩存。其是linux內核所使用的主要磁盤高速緩存。 正是由于緩存的引入,所以VFS文件系統采用了文件數據延遲寫的技術,因此,如果在調用系統接口寫入數據時沒有使用同步寫模式,那么大多數據將會先保存在緩存中,待等到滿足某些條件時才將數據刷入磁盤里。
內核是如何將數據刷入磁盤的呢?在看完以下兩點后就能得到答案。
1. 把臟頁寫入磁盤 正如我們所了解的,內核不斷用包含塊設備數據的頁填充頁高速緩存。只要進程修改了數據,相應的頁就被標記為臟頁,即把它的PG_dirty標志位置。 Unix系統允許把臟緩沖區寫入塊設備的操作延遲執行,因為這種策略可以顯著地提高系統的性能。對高速緩存中的頁的幾次寫操作可能只需對相應的磁盤塊進行一次緩慢的物理更新就可以滿足。此外,寫操作沒有讀操作那么緊迫,因為進程通常是不會因為延遲寫而掛起,而大部分情況都因為延遲讀而掛起。正是由于延遲寫,使得任一物理塊設備平均為讀請求提供服務將多于寫請求。一個臟頁可能直到最后一刻(即直到系統關閉時)都一直逗留在主存中。然而,從延遲寫策略的局限性來看,它有兩個主要的缺點: 一、如果發生了硬件錯誤或者電源掉電的情況,那么就無法再獲得RAM的內容,因此,從系統啟動以來對文件進行的很多修改就丟失了。 二、頁高速緩存的大小(由此存放它所需的RAM的大小)就可要很大——至少要與所訪問塊設備的大小不同。因此,在下列條件下把臟頁刷新(寫入)到磁盤:
頁高速緩存變得太滿,但還需要更多的頁,或者臟頁的數量已經太多。
自從頁變成臟頁以來已過去太長時間。
進程請求對塊設備或者特定文件任何待定的變化都進行刷新。通過調用sync()、fsync()或者fdatasync()系統調用來實現。 緩沖區頁的引入是問題更加復雜。與每個緩沖區頁相關的緩沖區首部使內核能夠了解每個獨立塊緩沖區的狀態。如果至少有一個緩沖區首部的PG_Dirty標志被置位,就應該設置相應緩沖區頁的PG_dirty標志。當內核選擇要刷新的緩沖區時,它掃描相應的緩沖區首部,并只把臟塊的內容有效的寫到磁盤。一旦內核把緩沖區的所有臟頁刷新到磁盤,就把頁的PG_dirty標志清0。
2. pdflush內核線程 早期版本的linux使用bdfllush內核線程系統地掃描頁高速緩存以搜索要刷新的臟頁,并且使用另一個內核線程kupdate來保證所有的頁不會臟太長時間。linux 2.6用一組通用內核線程pdflush替代上述兩個線程。這些內核線程結構靈活,它們作用于兩個參數:一個指向線程要執行的函數的指針和一個函數要用的參數。系統中pdflush內核線程的數量是要動態調整的:pdflush線程太少時就創建,太多時就殺死。因為這些內核線程所執行的函數可以阻塞,所以創建多個而不是一個pdflush內核線程可以改善系統性能。根據下面的原則控制pdflush線程的產生和消亡:
必須有至少兩個,最多八個pdflush內核線程
如果最近一次pdflush變為空閑的時間超過了1s,就應該刪除一個pdflush線程 所有的pdflush內核線程都有pdflush_work描述符,其數據結構如下:
類型 字段 說明 struct task_struct who 指向內核線程描述符的指針 void (*) (unsigned long) fn 內核線程所執行的回調函數 unsigned long arg0 給回調函數的參數 struct list head list pdflush_list鏈表的鏈接 unsigned long when_i_went_to_sleep 當內核線程可用時的時間(以jiffies表示)
當系統沒有要刷新的臟頁時,pdflush線程會自動處于睡眠狀態,最后由pdflush_operation()函數來喚醒。那么在這個過程中pdflush內核線程主要完成了哪些工作呢?其中一些工作與臟數據的刷新有關。尤其是pdflush通常執行下面的回調函數之一: 1. background_writeout(): 系統地掃描頁高速緩存以搜索要刷新的臟頁。
為了得到需要刷新的臟頁,就要徹底的搜索與在磁盤上有映像的索引節點相應的所有address_space對象(是一棵搜索樹)。由于頁高速緩存可能有大量的頁,如果用一個單獨的執行流來掃描整個高速緩存,會令CPU和磁盤長時間繁忙,因此,linux使用一種復雜的機制把對頁高速緩存的掃描劃分為幾個執行流。當內存不足或者用戶顯式的(用戶態進程發出sync()系統調用等)調用請求刷新操作時會執行wakeup_bdflush()函數。wakeup_bdflush()函數會調用pdflush_operation()喚醒pdflush內核線程,并委托它執行回調函數background_writeout()。background_writeout()函數有效的從頁高速緩存中獲得指定數量的臟頁,并把它寫回磁盤。此外,執行background_writeout()函數的pdflush內核線程只有在滿足以下兩個條件下才能被喚醒:一是對頁高速緩存中的頁內容進行了修改,二是引起臟頁部分增加到超過某個臟背景閾值。背景閾值通常設置為系統中所有頁的10%,不過可以通過修改文件/proc/sys/vm/dirty_background_ratio來調整該值。
linux內核編程書籍有那些比較經典?
學習內核不是件容易事,前面有很多前續課程要讀。
1.C語言,推薦Theprogrammginclanguage被稱為圣經的書,不過沒有中文版,不過C語言不太難,而且讀內核也不需要你對C有多深了解。學習到指針和結構體就夠你用了。
2.數據結構,不懂這個想學是不可能的,推薦《數據結構》C語言版本。
3.操作系統,任何一個大學的教科書都可以。一定要看,雖然是純理論。但不看這個,想看懂內核,那是不可能的。
4.微機原理,內核和底層相關,不知道微機原理是不行的。我學的時候書上是以INTEL8086為藍本,非常簡單。后來看內核時候,補充了80386以后出現的保護模式,非常復雜。但還是先看下老版的微機原理,先從簡單的下手。
5.linux系統管理,推薦《linux系統管理手冊》,被linux的作者推薦的系統管理書籍。 6,終于到內核了,我看的是《Linux內核代碼情景分析》雖然有點老。但結合新的源代碼,在了解機制后,代碼實現上差距不大。
linux怎么管理空閑內存?
內存組織層次:頁式管理—>(numa)—>node的zonelist—>32位DMA/NORMAL/HIGHMEM三個區,64位沒有高端內存—>伙伴分配系統—>slab/slub/slob2.創建進程時內存分配:實際上只分配task_struct和thread_info的內存,而且很可能是從slab緩存中分配的,當進程運行時由于缺頁中斷,才由內核層具體分配物理內存并與vm掛接3.malloc是c runtime中的實現,是上層庫的內存分配層,至于內核層的,可以看看__alloc_pages/alloc_pages/kmalloc(小內存直接slab,大內存還是alloc_pages)/vmalloc(alloc_page分配不連續的物理頁,映射到連續的vm_struct中的pages指針數組)/vmap/map_vm_area等幾個函數
總結
以上是生活随笔為你收集整理的linux结构体对齐(linux结构体)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JUnit 5和Selenium –使用
- 下一篇: 安卓app设计规范有哪些(安卓app设计