2013-10-14 141 views
2

我需要從內核發送一個字符串到用戶空間函數,而不用特別從用戶空間請求它,通過內核中的某個事件觸發用戶空間中的函數或應用程序。 到目前爲止,我已經嘗試了一個在用戶空間的init上啓動的Ioctl,然後睡覺並繼續閱讀關於netlink的內容,但找不到一個好的工作示例。 任何建議或例子都將非常有用。用內核觸發用戶空間

回答

4

這裏是我的過程是如何工作的,我會感興趣的改進以及任何建議:

  1. 啓動內核模塊
  2. 啓動用戶空間的應用程序,它發送一個自定義命令,以內核模塊爲內核模塊信號註冊用戶空間PID。在我的情況下,這是通過寫入/ dev/mymodule。內核模塊註冊PID:

    ... 
    printk("registering a new process id to receive signals: %d\n", current->pid); 
    signal_pid = current->pid; 
    ... 
    

    用戶空間應用程序還爲特定類型的信號在內核中註冊了一個處理程序。

    void local_sig_handler(int signum) { 
         printf("received a signal from my module\n"); 
         fflush(stdout); } 
    ... 
    signal(SIGIO, local_sig_handler); 
    
  3. 內核模塊產生的信號

    ... 
    struct siginfo info; 
    struct task_struct *t; 
    info.si_signo=SIGIO; 
    info.si_int=1; 
    info.si_code = SI_QUEUE;   
    
    printk("<1>IRQ received: %d\n", irq); 
    printk("<1>searching for task id: %d\n", signal_pid); 
    
    t= pid_task(find_vpid(signal_pid),PIDTYPE_PID);//user_pid has been fetched successfully 
    
    if(t == NULL){ 
         printk("<1>no such pid, cannot send signal\n"); 
    } else { 
         printk("<1>found the task, sending signal\n"); 
         send_sig_info(SIGIO, &info, t); 
    } 
    
  4. 內核中繼信號到應用程序的處理程序

+5

您不應該使用PID來識別內核中的進程。該過程可以退出並且不同的過程重新使用該PID。相反,你應該爲進程使用指向'task_struct'的指針(而不是在註冊時存儲'current-> pid',只需存儲'current')。 – caf

2

你有幾種選擇:

  1. 信號。用戶進程定義了一個信號處理程序,並且內核在收到事件時向用戶進程發出信號。這很好,但要求處理代碼在異步信號處理程序中運行(這使得編寫正確的代碼變得更加棘手)。缺點是可以使用信號處理程序傳輸的數據量有限。確保使用可以排隊的信號(例如實時信號),以便在進程處於信號處理過程中時不會丟失消息。
  2. 阻止系統調用或文件訪問。用戶進程執行系統調用(或讀取/寫入文件),使其進入睡眠狀態。調用的內核驅動程序維護一系列事件,並在事件到達時以及阻塞的服務器存在時解除事件隊列(這可避免在用戶進程解除阻塞時丟失事件)。
  3. 創建一個配置sigevent的系統調用。在內核方面,創建一個sigqueue來觸發相關事件。
0

我以前用過的一個例子是從內核空間的硬件中斷向用戶空間發送信號。

核空間

你必須發送一個信號之前準備SIGINFO和task_struct的:

struct siginfo info; 
struct task_struct *t; 

info.si_signo = SIG_TEST; 
info.si_code = SI_QUEUE; 
info.si_int = 1234; // Any value you want to send 
rcu_read_lock(); 

,也找到了與用戶空間應用PID任務。您必須通過寫或ioctl操作將它從用戶空間發送到內核空間。

t = pid_task(find_pid_ns(pid, &init_pid_ns), PIDTYPE_PID); 

然後你可以發送信號。

rcu_read_unlock();  
send_sig_info(SIG_TEST, &info, t); 

我在這裏省略,但你必須檢查每個操作的結果。

上面的代碼準備信號結構併發送它。請記住,您需要應用程序的PID。在我的情況下,用戶空間的應用程序通過ioctl驅動程序發送它的PID。

用戶空間

你必須定義和實現回調函數:

void signalFunction(int n, siginfo_t *info, void *unused) { 
     ..... 
     ..... 
} 

在主要程序:

struct sigaction sig; 

sig.sa_sigaction = signalFunction; // Callback function 
sig.sa_flags = SA_SIGINFO; 
sigaction(SIG_TEST, &sig, NULL); 

我希望它能幫助。

相關問題