Linuxカーネルソースコード解析:プロセススケジューリングAPIのシステムコールケーススタディ

kthread_create_on_node関数

kthread_create_on_node関数の機能:指定されたメモリノードに新しいカーネルスレッドを作成します。ソースコードは以下の通りです。

実践例

#include <linux/module.h>
#include <linux/pid.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/wait.h>

int KernelWorkerFunction(void* data) {
    printk("ワーカースレッドが開始されました\n");
    
    printk("ワーカースレッドのPID: %d\n", current->pid);
    
    printk("ワーカースレッドが終了します\n");
    return 0;
}

static int __init KthreadCreationInit(void) {
    struct task_struct* new_thread = NULL;
    
    printk("kthread_create_on_nodeの初期化開始\n");
    
    // メモリノード-1(デフォルトノード)に新しいスレッドを作成
    new_thread = kthread_create_on_node(KernelWorkerFunction, NULL, -1, "kernel_worker");
    
    if (IS_ERR(new_thread)) {
        printk("スレッド作成に失敗\n");
        return PTR_ERR(new_thread);
    }
    
    printk("新規スレッドのPID: %d\n", new_thread->pid);
    
    // スレッドを起動
    wake_up_process(new_thread);
    
    printk("メインスレッドのPID: %d\n", current->pid);
    
    return 0;
}

static void __exit KthreadCreationExit(void) {
    printk("カーネルモジュール終了: KthreadCreationExit\n");
}

MODULE_LICENSE("GPL");
module_init(KthreadCreationInit);
module_exit(KthreadCreationExit);

wake_up_process関数

wake_up_process関数の機能:スリープ状態のプロセスを起床させ、その状態をRUNNINGに変更して、CPUによる再スケジューリングを促します。

  • 起床に成功した場合は1を返す
  • 起床に失敗した場合(スレッドがすでにRUNNING状態の場合)は0を返す

ソースコードは以下の通りです:

実践例

#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/module.h>
#include <linux/pid.h>
#include <linux/list.h>
#include <linux/delay.h>

struct task_struct* target_thread = NULL;

int WorkerThreadFunction(void* data) {
    int result = -1;
    
    printk("ワーカースレッド関数開始\n");
    
    printk("ワーカースレッドのPID: %d\n", current->pid);
    
    // 親プロセスの状態を確認
    printk("親プロセスの初期状態: %ld\n", target_thread->state);
    
    // 親プロセスを起床
    result = wake_up_process(target_thread);
    
    printk("wake_up実行後の親プロセス状態: %ld\n", target_thread->state);
    printk("wake_upの戻り値: %d\n", result);
    
    printk("ワーカースレッド関数終了\n");
    return 0;
}

static int __init ProcessWakeupInit(void) {
    int wakeup_result = 1;
    char thread_name[] = "process_watcher";
    struct task_struct* created_thread = NULL;
    long timeout_value;
    
    wait_queue_head_t wait_queue;
    wait_queue_entry_t wait_entry;
    
    printk("プロセス起床テストの初期化開始\n");
    
    // 指定されたノードに新しいカーネルスレッドを作成
    created_thread = kthread_create_on_node(WorkerThreadFunction, NULL, -1, thread_name);
    
    if (IS_ERR(created_thread)) {
        printk("スレッド作成に失敗\n");
        return PTR_ERR(created_thread);
    }
    
    printk("新規スレッドのPID: %d\n", created_thread->pid);
    printk("現在のスレッドのPID: %d\n", current->pid);
    
    // 待ち行列を初期化
    init_waitqueue_head(&wait_queue);
    init_waitqueue_entry(&wait_entry, current);
    add_wait_queue(&wait_queue, &wait_entry);
    
    target_thread = current;
    
    // 作成したスレッドを起床
    wakeup_result = wake_up_process(created_thread);
    printk("新規スレッド起床結果: %d\n", wakeup_result);
    
    // タイムアウトまでスケジューリング
    timeout_value = schedule_timeout_uninterruptible(2000*10);
    
    // 現在のスレッドを起床
    wakeup_result = wake_up_process(current);
    printk("現在のスレッド起床結果: %d\n", wakeup_result);
    
    printk("schedule_timeout_uninterruptibleの戻り値: %ld\n", timeout_value);
    
    printk("プロセス起床テストの初期化終了\n");
    return 0;
}

static void __exit ProcessWakeupExit(void) {
    printk("プロセス起床テストの終了処理\n");
}

module_init(ProcessWakeupInit);
module_exit(ProcessWakeupExit);

タグ: Linuxカーネル プロセススケジューリング kthread システムコール

6月26日 18:03 投稿