Pages

2008年12月31日 星期三

mmap()

mmap 函式是用來將檔案映射到記憶體,video for linux two 就是透過這種方式,將 device memory mapping into user space,而 uvcvideo driver 會實作這個 file operation,來幫 camera application 建立 VMA 區段。mmap() 的原型如下:##ReadMore##

void *mmap(void *addr, size_t len, int prot,
      int
flags,int fildes, off_t off);
  • addr:用來告知從哪個記憶體位址開始映射,不過通常是擺 NULL,直接給作業系統決定,否則還要考慮對齊問題(alignment)
  • len:映射的大小
  • prot:對此記憶體的操作限制,如:PROT_READ、PROT_WRITE、PROT_EXEC、PROT_NONE
  • flags:對此記憶體的存取方式,如:MAP_SHARED、MAP_PRIVATE、MAP_FIXED,使用 MAP_SHARED 時,如果某一個行程有對 mmap 的記憶體做修改,那其他同樣有做 mmap 的行程會看到相同結果。(對同一個檔案)
  • fildes:open file 所得到的 fd。
  • off:指定檔案從哪裡開始對映
在此用 mmap 做個小實驗。首先建立一般的實體檔案,然後關閉它,接著透過映射到的記憶體來間接寫入字串到該檔案中。
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#define FILE_LENGTH 0x400 /* 1024 */

int main(int argc, char *argv[])
{
    int fd;
    void *map_memory;

    if(argc < 2) {
        printf("Usage: ./a.out <string>\n");
        return 1;
    }

    /*
     * Open a file to be mapped.
     * S_IRUSR: read permission, owner
     * S_IWUSR: write permission, owner
     */
    fd = open("/tmp/shared_file", O_RDWR | O_CREAT,
        S_IRUSR | S_IWUSR);
        lseek(fd, FILE_LENGTH-1, SEEK_SET);
        write(fd, "", 1);
        lseek(fd, 0, SEEK_SET);

    /* Create map memory. */
    map_memory = mmap(0, FILE_LENGTH,
        PROT_WRITE, MAP_SHARED,
        fd, 0);
    
    close(fd);

    /* Write to mapped memory. */
    if(strlen(argv[1]) < FILE_LENGTH)
        sprintf((char*)map_memory, "%s", argv[1]);

    munmap(map_memory, FILE_LENGTH);
    return 0;
}
這樣的作法還是可以將內容寫入檔案,而且速度比單純寫入檔案還要快,但似乎 mmap有大小的限制,因為我設定到 0x40000000,程式執行完後,系統變得怪怪的 =.=?。以下是該測試程式的 VMA 區段,位於 /proc/xxxx/maps,其中 xxxx 是 process id,可以在執行程式時輸入 &,如:./mmaptest input_string &。
08048000-08049000 r-xp 00000000 08:06 606289 /home/linly/Sample/mmap_write
...
b7df2000-b7f4a000 r-xp 00000000 08:06 1497227 /lib/tls/i686/cmov/libc-2.8.90.so
...
b7f61000-b7f62000 -w-s 00000000 08:06 686791 /tmp/shared_file
...
b7f80000-b7f81000 rw-p 0001b000 08:06 1479875 /lib/ld-2.8.90.so
bff6c000-bff81000 rw-p bffeb000 00:00 0 [stack]

2008年12月17日 星期三

如何使用 GtkProgressBar

  進度條(ProgressBar)是一個和使用者互動必備的元件,因為你必須讓使用者了解目前處理進度,若等不下去就可以趕緊取消。至於使用他的方式我覺得可以採取「Timer」或「Thread」。下面就以計時器的方式來介紹進度條的使用。但礙於程式太佔版面,所以只會顯示部份程式碼。
  
  一個進度條的產生是透過 gtk_progress_bar_new,進度條的範圍是[0,1],且以浮點數儲存。如果要讀取或修改進度條的數值利用 gtk_progress_bar_set(get)_fraction。了解這些之後,咱們就來看看程式碼。
/*
 以下程式執行會產生一個主視窗+按鍵
 當按下按鍵就建立另一個視窗+進度條
 並且透過計時器每次增加0.01,直到1.0為止
*/
#include<gtk/gtk.h>

gdouble new_val;
guint timer_id = 0;

static gboolean flush_progressbar(gpointer progressbar)
{
new_val= gtk_progress_bar_get_fraction(GTK_PROGRESS_BAR(progressbar))+0.01;
if(new_val >= 1.0) new_val = 1.0;

gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progressbar), new_val);

if(new_val >= 1.0) {
/* 舊版是用 gtk_timeout_remove() */
g_source_remove(timer_id);  
return FALSE;
}

return TRUE; // 如此計時器才會一直 work
}

static void create_window(GtkWidget *widget, gpointer window)
{
// 產生並初始化視窗
...

GtkWidget *progressbar;
progressbar = gtk_progress_bar_new();
gtk_layout_put(GTK_LAYOUT(layout), progressbar, 100, 200);

...
 
// 100毫秒執行一次
/* 舊版是用 gtk_timeout_add() */
timeId = g_timeout_add(100 , flush_progressbar, progressbar);
}

int main(int argc, char *argv[])
{
// window - 主視窗
// window_create_after - 按下按鍵後產生的視窗
GtkWidget *window;
GtkWidget *window_create_after;
GtkWidget *button;

gtk_set_locale();
gtk_init(&argc, &argv);

// 產生並初始化 window
// 產生並出使化 button、加到 window 中
// 註冊 clicked 事件用來產生 window_create_after
// 以及產生一個 timer
 
gtk_main();
return(0);
}


這裡要注意的有兩點:
  1. 不要計時器中加入 delay 的機制(如:sleep),因為會導致前一次沒處理完,下一次又開始處理(re-entrant routine),導致 stack overflow。 
  2. 不要讓主程式(main process)去處理 progressbar 的值,因為只會看到最終完成的畫面,中間的遞增過程使用者看不到。會有這種結果其實也不難想像,由於主程式正在執行某個function call,即使你不斷地更新進度條的內容,這些 event handler 只能等到目前的程式執行完,控制權回到 caller (也許好幾層),才會去執行這些更新畫面的 handler。
 

最後再介紹兩支和進度條相關的函式:
gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(progressbar),0.1);
gtk_progress_bar_pulse(GTK_PROGRESS_BAR(progressbar));

  這兩支函式可以讓進度條內的東東左跑右跑,就是放入 Live CD,在 ubuntu 圖樣的那個畫面,進度條開始跑進度之前的行為。就如同以上的程式碼,每次以0.1的間隔在移動,移動完右邊,就移左邊;移動完左邊,就移動右邊。

2008年12月12日 星期五

Video For Linux Two

  這是最近一兩個禮拜 study 的主題:V4L2,是在 Linux 中用來擷取影像的 API,隨著你安裝作業系統,V4L2 就會一併裝上去,以下是自己製作的投影片,Enjoy it... : )





參考資料:http://v4l2spec.bytesex.org/spec-single/v4l2.html

2008年12月7日 星期日

HP Pavilion DV7 安裝 Ubuntu 8.10 沒有音效

  在公司的工作機是 HP Pavilion DV7 ,我在上面安裝 Vista Business 與 Ubuntu,想當然爾,Windows 的運作正常得很,不過進入 Ubuntu 時,登入畫面在正常情況下會發出「登登」兩聲,但我的卻是詭異的「登登登登......(聲音越來越小 囧)」,且登入後沒有聲音,這種奇妙的狀況當然要交給 Google 大神,以下修改 /etc/modprobe.d/alsa-base 這個檔案,重開機後即正常:
##ReadMore##
sudo vi /etc/modprobe.d/alsa-base
在檔案最後加上 options snd-hda-intel enable_msi=1
參考網頁:http://www.ubuntu-tw.org/modules/newbb/viewtopic.php?viewmode=thread&topic_id=11933&forum=3&post_id=61152

CodeBlocks 設定值無法儲存

  不知道為什麼,這次重灌 Ubuntu,竟然發生每次啟動 Codeblocks,都像"第一次"使用一樣,導致設定值都要重設,卻又儲存不了,Google了一下,發現原來它和 gcin 相衝(?),所以改了以下的設定檔,然後重開機就正常了:##ReadMore##
sudo gedit /etc/X11/xinit/xinput.d/gcin
將 GTK_IM_MODULE=gcin 改成 GTK_IM_MODULE=xim
  從來沒發生過的事情,這次竟然莫名其妙的發生了(攤)。

2008年10月17日 星期五

C++ STL 容器的建(解)構

最近複習 STL,使用時發現一個現象,這邊我以 vector 為例來描述:
##ReadMore##
#include <iostream>
#include <vector>

using namespace std;

struct Foo {
    Foo() {
        cout << "Constructed" << endl;
    }

    ~Foo() {
        cout << "Destructed" << endl;
    }
};

int main() {
    vector<Foo> data(3);
    return 0;
}
跑出來的結果如下所示:
Constructed
Destructed
Destructed
Destructed
Destructed

從輸出的結果我們可以發現,vector的建構子會先建構出一個 FOO 類別的實體,接著再將內容複製三份至容器中,所以 vector data(3); 這一行敘述相當於 FOO foo; vector data(3,foo);。其實,C++ 容器都是以複製的方式來做建構,如:list、deque..,etc。不過搞不太懂是如何實作XD!有空再想想看好了。

2008年10月5日 星期日

如何讓束縛函式作用在自訂的函式物件中

束縛函式可以對雙元的函式物件作限制,共分為兩種:bind1st bind2nd。例如:
less<T>(a, b);      // 比較 a 是否比 b 小
bind1st(less<T>(), 50); // 限制 a 為 50,比較 50 < b
bind2nd(less<T>(), 90);  // 限制 b 為 90,比較 a < b ##ReadMore##  
如果我想讓束縛函式限制我自訂的函式物件,該如何做?這時只要去繼承 binary_function 這個結構即可,我們可以稍微看一下他的長相:include/bits/stl_function.h
template <class _Arg1, class _Arg2, class _Result> 
struct binary_function
{
 typedef _Arg1 first_argument_type;
 typedef _Arg2 second_argument_type;
 typedef _Result result_type;
};
它是由三個樣板參數組成,前兩個為運算元(operand),第三個為回傳型別,所以以下實際舉個例子,定義一個繼承自 binary_function 的結構,名為 Less。
// 自訂函式物件的結構,並繼承自 binary_function
template <class _Tp> 
struct Less : public binary_function<_Tp, _Tp, bool>
{
 bool operator() (const _Tp& __x, const _Tp& __y) const
 {
  return __x < __y;
 }
};
接著透過 adjust 函式來使用束縛函式,並配合上面所定義的 Less 函式物件結構:
// 若資料小於門檻值,就直接調整成門檻值
template &ltclass Iter, class Fn, class T&gt  
void adjust( Iter itr1 , Iter itr2 , Fn fn, T threshold ) {
 for (; itr1 != itr2; ++itr1 )
 {
  if (fn(*itr1)) *itr1 = threshold ;
 }
}

int main() {
 srand((unsigned)time(NULL));

 int i;
 const int SIZE = 10;
 const int THRESHOLD = 50;

 vector<int> data1(SIZE);
 for (i = 0; i < SIZE; ++i) data1[i] = rand()%100+1;

 cout << "original data: ";      
 for (i = 0; i < SIZE; ++i) cout << data1[i] << ' ';      
 cout << endl;

 adjust(data1.begin(), data1.end(),
    bind1st(Less<int>(), THRESHOLD), THRESHOLD);

 cout << "changed data: ";      
 for (i = 0; i < SIZE; data1[i]; ++i) cout << data1[i] << ' ';
 cout << endl;
 return 0;
}
輸出結果:
original data: 58 25 13 96 11 47 68 33 86 35
changed data: 50 25 13 50 11 47 50 33 50 35

因此,只要繼承 binary_function,自訂的函式物件結構也能使用束縛函式。另外還有一個稱作否定函式,對象是單元的函式物件,所以只要自訂的函式物件結構去繼承 unary_function 即可。

2008年10月2日 星期四

TrueType 中的細明體、新細明體、與標楷體所造成文字破碎的情況

由於自己的論文,需要 pdf library 的輔助,來讀取該檔案格式,所以找來了 Xpdf 這個 open source 來使用,卻發現到當中文字使用微軟細明體、新細明體、或者是標楷體時,會發生文字破碎的清況...如下圖所示:( 我是在 Windows XP上面開發 )

2008年10月1日 星期三

將 MDF、MDS 轉換成 ISO 檔

最近在抓 Friends 的 DVD 版本,打算燒下來收藏,不過供檔的類型是 mdf、mds,甚至還有 md0、md1、md2...等,這個是 Alcohol 120% 可以支援的格式,不過懶的安裝,所以就把這些檔案(md*)轉換成 iso檔就方便多了。說是轉換,其實只是把這些檔案「串接」起來而已,指令如下:(假設有md0~md10、以及 mdf、mds)

2008年9月13日 星期六

重灌 Windows 後,該如何重建 Grub (雙系統)

使用 Windows 時常發生執行某個軟體, CPU 使用率爆高,沒有週期性;也沒針對哪一個軟體,心想或許是 OS 的資源分配出了問題,該是重灌的時候了!!

不過自己是使用雙系統(Ubuntu和Windows XP),所以重灌勢必造成原先的 Grub 被覆蓋掉,導致 Ubuntu 進不去,所以必須重建 Grub,以下就是最後成功的版本:(使用 Live-CD)
linly-desktop:$ sudo grub
grub:$ find /grub/stage1    // 顯示原先 Grub 所在的磁碟和磁區,例如:(hd0,1)代表我原先的 Grub 在第一顆硬碟的第二個磁區
grub:$ root (hd0,1)         // 告訴 Grub,Linux root 所在
grub:$ setup (hd0)          // 在第一顆硬碟重建 Grub
以上有一點需要注意的是,很多網頁會在第二行指令輸入成 find /boot/grub/stage1,因為我當初在分割 Ubuntu 的磁區,我有特別分出一個 /boot,所以在此就不需要出現上述的紅色字眼。 

最後補充一點,由於我的雙系統並非在同一顆硬碟,Ubuntu 在第一顆硬碟(hd0) 的第二個磁區;Windows XP 在第二顆硬碟(hd1) 的第一個磁區。對於雙系統安裝在同一顆硬碟的人,以上方式依舊沒問題。

2008年5月6日 星期二

Gtk+-2.0 初步

OS:Ubuntu 8.04 Hardy Heron
IDE: Code::Blocks svn build rev 5020 with Gtk+-2.0
/etc/apt/sources.list 中加入以下網址:
# Code::Blocks
deb http://apt.wxwidgets.org/ gutsy-wx main
deb http://archive.ubuntu.com/ubuntu/ gutsy multiverse restricted universe main
deb http://lgp203.free.fr/ubuntu/ gutsy universe
linly-desktop:$ wget -q http://apt.wxwidgets.org/key.asc -O- | sudo apt-key add -
linly-desktop:$ wget -q http://lgp203.free.fr/public.key -O- | sudo apt-key add -
linly-desktop:$ sudo apt-get update
linly-desktop:$ sudo apt-get install libgtk2.0-dev
linly-desktop:$ sudo apt-get install codeblocks
準備工作完成後,接著開始我的第一支 Gtk+ 程式...
 
Blogger Templates