define SCULLIOCMAGIC k define SCULLIOCRESET IOSCULLIOCMAGIC 0 Use

  • Slides: 45
Download presentation

#define SCULL_IOC_MAGIC 'k' #define SCULL_IOCRESET _IO(SCULL_IOC_MAGIC, 0) /* Use 'k' as magic number */

#define SCULL_IOC_MAGIC 'k' #define SCULL_IOCRESET _IO(SCULL_IOC_MAGIC, 0) /* Use 'k' as magic number */ #define SCULL_IOCSQUANTUM _IOW(SCULL_IOC_MAGIC, 1, scull_quantum) #define SCULL_IOCSQSET _IOW(SCULL_IOC_MAGIC, 2, scull_qset) #define SCULL_IOCTQUANTUM _IO(SCULL_IOC_MAGIC, 3) #define SCULL_IOCTQSET _IO(SCULL_IOC_MAGIC, 4) #define SCULL_IOCGQUANTUM _IOR(SCULL_IOC_MAGIC, 5, scull_quantum) #define SCULL_IOCGQSET _IOR(SCULL_IOC_MAGIC, 6, scull_qset) #define SCULL_IOCQQUANTUM _IO(SCULL_IOC_MAGIC, 7) #define SCULL_IOCQQSET _IO(SCULL_IOC_MAGIC, 8) #define SCULL_IOCXQUANTUM _IOWR(SCULL_IOC_MAGIC, 9, scull_quantum) #define SCULL_IOCXQSET _IOWR(SCULL_IOC_MAGIC, 10, scull_qset) #define SCULL_IOCHQUANTUM _IO(SCULL_IOC_MAGIC, 11) #define SCULL_IOCHQSET _IO(SCULL_IOC_MAGIC, 12) /*HARDRESET命令,可將模組的用量計次歸零*/

/*分離出type和number位元欄位,如果遇到錯誤的cmd,直接傳回ENOTTY*/ if (_IOC_TYPE(cmd) != SCULL_IOC_MAGIC) return -ENOTTY; if (_IOC_NR(cmd) > SCULL_IOC_MAXNR) return -ENOTTY; /*

/*分離出type和number位元欄位,如果遇到錯誤的cmd,直接傳回ENOTTY*/ if (_IOC_TYPE(cmd) != SCULL_IOC_MAGIC) return -ENOTTY; if (_IOC_NR(cmd) > SCULL_IOC_MAXNR) return -ENOTTY; /* direction是一個位元遮罩, 而VERIFY_WRITE代表雙向傳輸 * `Type‘是從user-oriented來看 * access_ok卻是從kernel-oriented來看 * 所以“read”和“write”剛好相否 */ if (_IOC_DIR(cmd) & _IOC_READ) err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) & _IOC_WRITE) err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); if (err) return -EFAULT; • 在呼叫access_ok( )之後,驅動程式就可放心進行實際的傳輸。除 了使用copy_from_user以及copy_to_user函式之外,<asm/uaccess. h> 還提供了一組針對常用資料規格而設計的傳輸 具: put_user(datum, ptr), __put_user(datum, ptr); get_user(datum, ptr)……

5. 2. 1 -Going to Sleep and Awakening • 在待命佇列被宣告與初始化之後,就可用來安置休眠行 程。將行程推入休眠狀態(催眠),世界由呼叫sleep_on( ) 的各種變體函式之一來達成的,要使用哪一種變體,要 看希望休眠程度有多“沉”:

5. 2. 1 -Going to Sleep and Awakening • 在待命佇列被宣告與初始化之後,就可用來安置休眠行 程。將行程推入休眠狀態(催眠),世界由呼叫sleep_on( ) 的各種變體函式之一來達成的,要使用哪一種變體,要 看希望休眠程度有多“沉”: – – – sleep_on(wait_queue_head_t *queue); zombie殭屍… interruptible_sleep_on(wait_queue_head_t *queue); sleep_on_timeout(wait_queue_head_t *queue, long timeout); interruptible_sleep_on(wait_queue_head_t *queue, long timeout); void wait_event(wait_queue_head_t queue, int condition); int wait_event_interruptible(wait_queue_head_t queue, int condition); 結合了“等待事件發生”與一個“指定測試條件”為甦醒 條件,藉此避免發生相競情況。也就是說,休眠狀態會持續蹈 事件發生,或是condition所代表的條件成立為止。這兩個巨集 展開後都會行程do-while迴圈,而回圈每一回合都會重新估算 condition的值…

5. 2. 1 -Going to Sleep and Awakening • 範例misc-modules/sleepy. c [root@zwai misc-modules]# make

5. 2. 1 -Going to Sleep and Awakening • 範例misc-modules/sleepy. c [root@zwai misc-modules]# make [root@zwai misc-modules]# insmod. /sleepy. o Warning: loading. /sleepy. o will taint the kernel: no license [root@zwai misc-modules]# cat /proc/devices |grep sleepy 253 sleepy [root@zwai misc-modules]# mknod /dev/sleepy c 253 0 [1]+ Exit 1 cat /dev/sleep [root@zwai misc-modules]# cat /dev/sleepy & [1] 26770 [root@zwai misc-modules]# echo trash > /dev/sleepy

wait_queue_head_t spinlock_t lock; struct list_head task_list; Wait Queues in Linux 2. 4 佇列中沒有休眠的行程 wait_queue_t

wait_queue_head_t spinlock_t lock; struct list_head task_list; Wait Queues in Linux 2. 4 佇列中沒有休眠的行程 wait_queue_t struct task_struct *task; struct list_head task_list; 目前的行程正在裝置的佇列裡休眠 自備wait_queue_head_t 的裝置結構 wait_queue結構本身 目前行程與 其堆疊頁 另一行程與 其堆疊頁 多個行程正在同一個佇列裡休眠

5. 2. 2 -A Deeper Look at Wait Queues • • 建立新的wait_queue_t變數(wait,來自堆疊)並設定初值。 設定行程的狀態為TASK_INTERRUPTIBLE(隨時可岔斷) 將待命佇列項目加到佇列(wait_queue_head_t*

5. 2. 2 -A Deeper Look at Wait Queues • • 建立新的wait_queue_t變數(wait,來自堆疊)並設定初值。 設定行程的狀態為TASK_INTERRUPTIBLE(隨時可岔斷) 將待命佇列項目加到佇列(wait_queue_head_t* 引數) 呼叫schedule( ),把處理器的使用權讓出 void simplified_sleep_on(wait_queue_head_t *queue) { wait_queue_t wait; init_waitqueue_entry(&wait, current); current->state=TASK_INTERRUPTIBLE; add_wait_queue(queue, &wait); schedule( ); remove_wait_queue (queue, &wait); }

5. 2. 2 -A Deeper Look at Wait Queues • 在 2. 3版研發過程中,開發人員提出了專程修眠(exclusive sleep)的

5. 2. 2 -A Deeper Look at Wait Queues • 在 2. 3版研發過程中,開發人員提出了專程修眠(exclusive sleep)的 觀念。對於需要競逐獨占資源的行程,在休眠之前,事先告訴核 心,當獨占資源釋出時,一次只叫醒其中之一就夠了。 void simplified_sleep_exclusive(wait_queue_head_t *queue) { wait_queue_t wait; init_waitqueue_entry(&wait, current); current->state=TASK_INTERRUPTIBLE|TASK_Ex. CLUSIVE; add_wait_queue(queue, &wait); schedule( ); remove_wait_queue (queue, &wait); }

5. 3 -poll and select • poll_table結構 – 宣告在<linux/poll. h> – 每個驅動程式都應該引入此標頭檔 void poll_wait(struct

5. 3 -poll and select • poll_table結構 – 宣告在<linux/poll. h> – 每個驅動程式都應該引入此標頭檔 void poll_wait(struct file *, wait_queue_head_t *, poll_table *); • poll. h預先定義了一系列常數的各種可能的輪詢狀態 – – POLLIN - POLLOUT POLLRDNORM - POLLWRNORM POLLRDBAND - POLLWRBAND POLLPRI, POLLHUP, POLLER

Poll 所用的資料結構 只調查一個裝置 struct poll_table_struct int error; struct poll_table_page *tables; struct poll_table_entry wait_queue_t wait;

Poll 所用的資料結構 只調查一個裝置 struct poll_table_struct int error; struct poll_table_page *tables; struct poll_table_entry wait_queue_t wait; wait_queue_head_t *wait_address; 自備wait_queue_head_t 的一般裝置結構 一個觸發了poll() 系統呼叫的行程 poll_table_struct結構 輪詢表項目 正在輪詢兩個裝置