Linux dma-fence demo--筆記


 
前面的幾篇筆記記錄dma-fence的一些用途,這里簡單寫了個DMA-FENCE的測試代碼。
 
dma-fence本身的實現和使用並不復雜,其只有兩種狀態signaled和unsigned。可能正是因為其本身的精簡,在融入其他概念中時,在不同的環境下,賦予了dma-fence不同的含義。 所以通常需要根據dma-fence的具體使用的情況來理解其含義。
 
dma-fence是內核中的同步原語,本身只能表示兩種狀態,這點上就和complete有點類似了。
但是dma-fence是可以跨設備,跨進程的。
具體來說:
1.就是A設備驅動程序中創建的dma-fence可以被B驅動程序使用。
2.dma-fence是由內核創建,但是可以在進程間傳遞,並且可以在用戶層獲取fence的當前狀態。
而常規的內核中的同步方法,則不具備對上述兩點的支持。
 
基本原理:
 
一個被初始化的dma-fence,使用wait函數后,會將當前進程換出,即當前進程會sleep,而當調用signal函數時會喚醒被wait函數換出的進程。
dma-fence的使用還可以通過向dma-fence添加一個或多個callback函數,當dma-fence調用signal操作時,會依次遍歷callback list,並調用每個callback函數。當調用wait函數時,會把默認的一個callback函數加入到dma-fence中,而這個函數就起到喚醒的作用。
 
dma-fence在內核中被創建,可以通過導出一個文件描述符fd到user層,然后用戶層可以對該fd做常規的文件操作,也可以把該fence傳遞給其他進程。這個fd給到內核中后,又可以還原出dma-fence的內核數據結構。所以在user層看到的dma-fence是一個文件描述符。
 
其中提到的幾個操作對用函數如下:
init:dma_fence_init()
wait:dma_fence_wait()
signal:dma_fence_signal()
callback:dma_fence_add_callback()
 
具體的例子:
 
driver通過一個字符設備驅動程序實現的。在字符設備被open時,會新創建一個dma-fence的內核數據對象。
通過ioctl實現了三個命令,主要實現三個功能,1.導出內核dma-fence的fd到user層;2.user層導入一個fd到內核中,並還原為內核dma-fence對象;3.觸發dma-fence變為signaled。
 
user層的測試代碼會使用driver層提供的ioctl命令,操作dma-fence。並通過系統函數poll(),在user層等待內核中dma-fence的變為signaled。
 
ioctl命令實現對dma-fence的操作:
DMA_FENCE_IN_CMD:通過將fd將一個外來的fence傳遞到driver層,driver中先向該dma-fence添加一個callback回調函數,然后在顯示調用wait函數,進程會阻塞直到該dma-fence變成signaled。
DMA_FENCE_OUT_CMD:將driver創建的dma-fence通過fd的方式導出到user層
DMA_FENCE_SIGNAL_CMD:對driver創建的dma-fence調用signal操作
 
1.內核中對dma-fence初始化:
 
static DEFINE_SPINLOCK(fence_lock);
 
static void dma_fence_cb(struct dma_fence *f, struct dma_fence_cb *cb)
{
    printk("dma-fence callback !");
}
 
static const char *dma_fence_get_name(struct dma_fence *fence)
{
    return "dma-fence-example";
}
 
static const struct dma_fence_ops fence_ops = {
    .get_driver_name = dma_fence_get_name,
    .get_timeline_name = dma_fence_get_name,
};
 
static struct dma_fence *create_fence(void)
{
    struct dma_fence *fence;
 
    fence = kzalloc(sizeof(*fence), GFP_KERNEL);
    if (!fence)
        return NULL;
 
     dma_fence_init(fence, &fence_ops, &fence_lock, 0, 0);
 
    return fence;
}
 
2.內核中,dma-fence導出fd到user層:
 
sync_file = sync_file_create(out_fence);
out_fence_fd = get_unused_fd_flags(O_CLOEXEC);
fd_install(out_fence_fd, sync_file->file);
 
if (copy_to_user((void __user *)arg, &out_fence_fd, sizeof(int)) != 0)
            return -EFAULT;
 
3.內核中,接收user層傳遞的fd,還原出dma-fence內核對象,並通過調用dma_fence_wait()等待in-fence變為signaled:
 
if (copy_from_user(&in_fence_fd, (void __user *)arg, sizeof(int)) != 0)
   return -EFAULT;
 
in_fence = sync_file_get_fence(in_fence_fd);
 
/* add a callback func */
dma_fence_add_callback(in_fence, &cb, dma_fence_cb);
dma_fence_wait(in_fence, true);
 
4.user層中,通過系統調用poll()函數在用戶層判斷dma-fence的狀態值:
 
static inline int sync_wait(int fd, int timeout)
{
    struct pollfd fds = {0};
    int ret;
 
    fds.fd = fd;
    fds.events = POLLIN;
 
    do {
        ret = poll(&fds, 1, timeout);
        if (ret > 0) {
            if (fds.revents & (POLLERR | POLLNVAL)) {
                errno = EINVAL;
                return -1;
            }
            return 0;
        } else if (ret == 0) {
            errno = ETIME;
            return -1;
        }
    } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
 
    return ret;
}
 
5.signal dma-fence:
 
dma_fence_signal(out_fence);
 
 


免責聲明!

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



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