Mercurial > hg > Game > Atoc
view driver/cdev_handler.c @ 0:42f240cc4bc6
From: 太田 篤志 <atoc@namikilab.tuat.ac.jp>
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 08 Sep 2009 13:44:18 +0900 |
parents | |
children |
line wrap: on
line source
/** * cdev_handler.c * SPE プロセスマネージャ spe_manager * キャラクタデバイスのハンドラ */ #include <linux/module.h> // カーネルモジュール全般 #include <linux/fs.h> // struct inode, struct file #include <linux/kernel.h> // printk //#include <linux/slab.h> // kmalloc, kfree #include <linux/vmalloc.h> // vmalloc, vfree #include <linux/semaphore.h> // down_interruptible, up #include <linux/spinlock.h> // spin_lock, spin_unlock #include <asm/uaccess.h> // copy_from_user, copy_to_user #include "../include/spe_process.h" #include "../include/ioctl.h" #include "cdev_handler.h" #include "lspe.h" #include "main.h" #include "critical.h" #include "process_list.h" // SPE プロセス ID 割り当て用 (open ハンドラが実行されるたびに加算される) static int spe_pid = 0; //=================================================================================================== spe_manager_open() /** * spe_manager_open * キャラクタデバイス open イベントハンドラ * * @param struct inode * inode * @param struct file * filp * @return int */ int spe_manager_open(struct inode *inode, struct file *filp) { spe_process_context_list_t *this_process; struct semaphore *semaphore_for_spe_pid = get_semaphore_for_spe_pid(); struct semaphore *semaphore_for_process_list = get_semaphore_for_process_list(); // SPE プロセスコンテキスト用のメモリを確保 (確保するまでにスリープするかもしれない) if ((this_process = (spe_process_context_list_t *)vmalloc(sizeof(spe_process_context_list_t))) == NULL) { printk(KERN_ERR "[%s] Error: vmalloc() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__); return -ENOSPC; } // SPE プロセスコンテキストの初期化 this_process->context.read.status = SPE_PROCESS_CONTEXT_STATUS_OPENED; this_process->prev_process = NULL; this_process->next_process = NULL; // this_process->context.read.spe_no = -1; // 暫定 // Critical Section >>> if (down_interruptible(semaphore_for_spe_pid)) goto spe_manager_open__error1; // SPE プロセス ID 番号の割り当て if ((this_process->context.read.spe_pid = ++spe_pid) < 0) { } up(semaphore_for_spe_pid); // <<< Critical Section // Critical Section >>> if (down_interruptible(semaphore_for_process_list)) goto spe_manager_open__error2; increment_opened(); up(semaphore_for_process_list); // <<< Critical Section filp->private_data = (void *)this_process; return 0; spe_manager_open__error2: spe_manager_open__error1: return -ERESTARTSYS; } //================================================================================================== spe_manager_write() /** * spe_manager_write * キャラクタデバイス write イベントハンドラ * * @param struct file * filp * @param char * buf * @param size_t count * @param loff_t * f_pos * @return ssize_t */ ssize_t spe_manager_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { spe_process_context_list_t *this_process = (spe_process_context_list_t *)(filp->private_data); struct semaphore *semaphore_for_process_list = get_semaphore_for_process_list(); if (this_process->context.read.status != SPE_PROCESS_CONTEXT_STATUS_OPENED && this_process->context.read.status != SPE_PROCESS_CONTEXT_STATUS_WRITTEN) { printk ( KERN_ERR "[%s] Error: spe_manager_write() can't be executed in the status. (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__ ); return -EFAULT; } // // Note: (1) 以降の処理が実行されるのは、 // SPE プロセスが OPENED 状態か WRITTEN 状態の時のみである。 // (2) OPENED → WRITTEN の状態遷移は、 // 書き込みオフセットが spe_process_context_write_data_t のサイズぶん移動した際に行われる。 // fseek 等でオフセットを移動してしまうとデータが不足したまま WRITTEN 状態になるおそれがあるので注意。 // if (*f_pos >= sizeof(spe_process_context_write_data_t)) { // Critical Section >>> if (down_interruptible(semaphore_for_process_list)) goto spe_manager_write__error1; decrement_opened(); increment_written(); up(semaphore_for_process_list); // <<< Critical Section // プロセス状態更新 this_process->context.read.status = SPE_PROCESS_CONTEXT_STATUS_WRITTEN; return 0; } if (*f_pos + count > sizeof(spe_process_context_write_data_t)) // そのまま転送するとサイズオーバーなので調節する count = sizeof(spe_process_context_write_data_t) - *f_pos; if (copy_from_user((void *)&(this_process->context.write) + *f_pos, buf, count)) { printk(KERN_ERR "[%s] Error: copy_from_user() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__); return -EFAULT; } if ((*f_pos += count) >= sizeof(spe_process_context_write_data_t)) { // Critical Section >>> if (down_interruptible(semaphore_for_process_list)) goto spe_manager_write__error1; decrement_opened(); increment_written(); up(semaphore_for_process_list); // <<< Critical Section // プロセス状態更新 this_process->context.read.status = SPE_PROCESS_CONTEXT_STATUS_WRITTEN; } return count; spe_manager_write__error1: return -ERESTARTSYS; } //================================================================================================== spe_manager_ioctl() /** * spe_manager_ioctl * キャラクタデバイス ioctl イベントハンドラ [要修正] * * @param struct inode * inode * @param struct file * filp * @param unsigned int cmd * @param unsigned long arg * @return int */ int spe_manager_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { // マジック番号の判定 if (_IOC_TYPE(cmd) != SPE_MANAGER_IOCTL_MAGIC) return -ENOTTY; switch (cmd) { // SPE プロセスを開始する case SPE_MANAGER_IOCTL_START_PROCESS: // データ転送方向判定 if (_IOC_DIR(cmd) != _IOC_NONE) return -ENOTTY; { spe_process_context_list_t *this_process = (spe_process_context_list_t *)(filp->private_data); struct semaphore *semaphore_for_process_list = get_semaphore_for_process_list(); spinlock_t *spinlock_for_process_list = get_spinlock_for_process_list(); int i, lspe_count = get_lspe_count(); // Critical Section (semaphore) >>> if (down_interruptible(semaphore_for_process_list)) goto spe_manager_ioctl__error1; decrement_written(); // Critical Section (spinlock) >>> spin_lock(spinlock_for_process_list); { for (i = 0; i < lspe_count; i++) { spe_process_context_list_t *running = get_running_process(i); // この論理 SPE でプロセスが実行中ではないか if (running == NULL) { // このプロセスを実行中にする // this_process->context.read.spe_no = i; this_process->context.read.status = SPE_PROCESS_CONTEXT_STATUS_RUNNING; set_running_process(i, this_process); break; } } if (i >= lspe_count) { // 空きの SPE がなかったので実行待ちプロセスリストへ追加する add_process_to_waiting(this_process); } } spin_unlock(spinlock_for_process_list); // <<< Critical Section (spinlock) up(semaphore_for_process_list); // <<< Critical Section (semaphore) // SPE プロセス開始 if (i < lspe_count) start_spe_process(i, this_process); } break; // それ以外のコマンド default: return -ENOTTY; } return 0; spe_manager_ioctl__error1: return -ERESTARTSYS; } //=================================================================================================== spe_manager_read() /** * spe_manager_read * キャラクタデバイス read イベントハンドラ * * @param struct file * filp * @param char * buf * @param size_t count * @param loff_t * f_pos * @return ssize_t */ ssize_t spe_manager_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { spe_process_context_list_t *this_process = (spe_process_context_list_t *)(filp->private_data); if (*f_pos >= sizeof(spe_process_context_read_data_t)) // これ以上転送しない return 0; if (*f_pos + count > sizeof(spe_process_context_read_data_t)) // そのまま転送するとサイズオーバーなので調節する count = sizeof(spe_process_context_read_data_t) - *f_pos; if (copy_to_user(buf, (void *)&(this_process->context.read) + *f_pos, count)) { printk(KERN_ERR "[%s] Error: copy_to_user() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__); return -EFAULT; } *f_pos += count; return count; } //================================================================================================ spe_manager_release() /** * spe_manager_release * キャラクタデバイス release イベントハンドラ * * @param struct inode * inode * @param struct file * filp * @return int */ int spe_manager_release(struct inode *inode, struct file *filp) { spe_process_context_list_t *this_process = (spe_process_context_list_t *)(filp->private_data); struct semaphore *semaphore_for_process_list = get_semaphore_for_process_list(); spinlock_t *spinlock_for_process_list = get_spinlock_for_process_list(); // // // ToDo: SPE プロセスが NOT_RELEASED 状態でない時に // 突然このハンドラが呼び出された場合の後始末 // // // Critical Section (semaphore) >>> if (down_interruptible(semaphore_for_process_list)) goto spe_manager_release__error1; // Critical Section (spinlock) >>> spin_lock(spinlock_for_process_list); { decrement_not_released(); } spin_unlock(spinlock_for_process_list); // <<< Critical Section (spinlock) increment_released(); up(semaphore_for_process_list); // <<< Critical Section (semaphore) // SPE プロセスコンテキストのためのメモリを解放 vfree(this_process); return 0; spe_manager_release__error1: return -ERESTARTSYS; }