Mercurial > hg > Game > Atoc
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:42f240cc4bc6 |
---|---|
1 /** | |
2 * cdev_handler.c | |
3 * SPE プロセスマネージャ spe_manager | |
4 * キャラクタデバイスのハンドラ | |
5 */ | |
6 | |
7 #include <linux/module.h> // カーネルモジュール全般 | |
8 #include <linux/fs.h> // struct inode, struct file | |
9 #include <linux/kernel.h> // printk | |
10 //#include <linux/slab.h> // kmalloc, kfree | |
11 #include <linux/vmalloc.h> // vmalloc, vfree | |
12 #include <linux/semaphore.h> // down_interruptible, up | |
13 #include <linux/spinlock.h> // spin_lock, spin_unlock | |
14 #include <asm/uaccess.h> // copy_from_user, copy_to_user | |
15 | |
16 #include "../include/spe_process.h" | |
17 #include "../include/ioctl.h" | |
18 #include "cdev_handler.h" | |
19 #include "lspe.h" | |
20 #include "main.h" | |
21 #include "critical.h" | |
22 #include "process_list.h" | |
23 | |
24 | |
25 // SPE プロセス ID 割り当て用 (open ハンドラが実行されるたびに加算される) | |
26 static int spe_pid = 0; | |
27 | |
28 | |
29 | |
30 //=================================================================================================== spe_manager_open() | |
31 /** | |
32 * spe_manager_open | |
33 * キャラクタデバイス open イベントハンドラ | |
34 * | |
35 * @param struct inode * inode | |
36 * @param struct file * filp | |
37 * @return int | |
38 */ | |
39 int spe_manager_open(struct inode *inode, struct file *filp) | |
40 { | |
41 spe_process_context_list_t *this_process; | |
42 struct semaphore *semaphore_for_spe_pid = get_semaphore_for_spe_pid(); | |
43 struct semaphore *semaphore_for_process_list = get_semaphore_for_process_list(); | |
44 | |
45 | |
46 // SPE プロセスコンテキスト用のメモリを確保 (確保するまでにスリープするかもしれない) | |
47 if ((this_process = (spe_process_context_list_t *)vmalloc(sizeof(spe_process_context_list_t))) == NULL) | |
48 { | |
49 printk(KERN_ERR "[%s] Error: vmalloc() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__); | |
50 return -ENOSPC; | |
51 } | |
52 | |
53 // SPE プロセスコンテキストの初期化 | |
54 this_process->context.read.status = SPE_PROCESS_CONTEXT_STATUS_OPENED; | |
55 this_process->prev_process = NULL; | |
56 this_process->next_process = NULL; | |
57 // this_process->context.read.spe_no = -1; // 暫定 | |
58 | |
59 | |
60 // Critical Section >>> | |
61 if (down_interruptible(semaphore_for_spe_pid)) | |
62 goto spe_manager_open__error1; | |
63 | |
64 // SPE プロセス ID 番号の割り当て | |
65 if ((this_process->context.read.spe_pid = ++spe_pid) < 0) | |
66 { | |
67 } | |
68 | |
69 up(semaphore_for_spe_pid); | |
70 // <<< Critical Section | |
71 | |
72 | |
73 // Critical Section >>> | |
74 if (down_interruptible(semaphore_for_process_list)) | |
75 goto spe_manager_open__error2; | |
76 | |
77 increment_opened(); | |
78 | |
79 up(semaphore_for_process_list); | |
80 // <<< Critical Section | |
81 | |
82 | |
83 filp->private_data = (void *)this_process; | |
84 return 0; | |
85 | |
86 | |
87 spe_manager_open__error2: | |
88 spe_manager_open__error1: | |
89 return -ERESTARTSYS; | |
90 } | |
91 | |
92 | |
93 //================================================================================================== spe_manager_write() | |
94 /** | |
95 * spe_manager_write | |
96 * キャラクタデバイス write イベントハンドラ | |
97 * | |
98 * @param struct file * filp | |
99 * @param char * buf | |
100 * @param size_t count | |
101 * @param loff_t * f_pos | |
102 * @return ssize_t | |
103 */ | |
104 ssize_t spe_manager_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) | |
105 { | |
106 spe_process_context_list_t *this_process = (spe_process_context_list_t *)(filp->private_data); | |
107 struct semaphore *semaphore_for_process_list = get_semaphore_for_process_list(); | |
108 | |
109 | |
110 if (this_process->context.read.status != SPE_PROCESS_CONTEXT_STATUS_OPENED && | |
111 this_process->context.read.status != SPE_PROCESS_CONTEXT_STATUS_WRITTEN) | |
112 { | |
113 printk ( | |
114 KERN_ERR "[%s] Error: spe_manager_write() can't be executed in the status. (%s:%u)\n", | |
115 SPE_MANAGER_MODULE_NAME, | |
116 __FILE__, | |
117 __LINE__ | |
118 ); | |
119 return -EFAULT; | |
120 } | |
121 | |
122 // | |
123 // Note: (1) 以降の処理が実行されるのは、 | |
124 // SPE プロセスが OPENED 状態か WRITTEN 状態の時のみである。 | |
125 // (2) OPENED → WRITTEN の状態遷移は、 | |
126 // 書き込みオフセットが spe_process_context_write_data_t のサイズぶん移動した際に行われる。 | |
127 // fseek 等でオフセットを移動してしまうとデータが不足したまま WRITTEN 状態になるおそれがあるので注意。 | |
128 // | |
129 | |
130 if (*f_pos >= sizeof(spe_process_context_write_data_t)) | |
131 { | |
132 // Critical Section >>> | |
133 if (down_interruptible(semaphore_for_process_list)) | |
134 goto spe_manager_write__error1; | |
135 | |
136 decrement_opened(); | |
137 increment_written(); | |
138 | |
139 up(semaphore_for_process_list); | |
140 // <<< Critical Section | |
141 | |
142 // プロセス状態更新 | |
143 this_process->context.read.status = SPE_PROCESS_CONTEXT_STATUS_WRITTEN; | |
144 return 0; | |
145 } | |
146 | |
147 if (*f_pos + count > sizeof(spe_process_context_write_data_t)) | |
148 // そのまま転送するとサイズオーバーなので調節する | |
149 count = sizeof(spe_process_context_write_data_t) - *f_pos; | |
150 | |
151 if (copy_from_user((void *)&(this_process->context.write) + *f_pos, buf, count)) | |
152 { | |
153 printk(KERN_ERR "[%s] Error: copy_from_user() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__); | |
154 return -EFAULT; | |
155 } | |
156 | |
157 if ((*f_pos += count) >= sizeof(spe_process_context_write_data_t)) | |
158 { | |
159 // Critical Section >>> | |
160 if (down_interruptible(semaphore_for_process_list)) | |
161 goto spe_manager_write__error1; | |
162 | |
163 decrement_opened(); | |
164 increment_written(); | |
165 | |
166 up(semaphore_for_process_list); | |
167 // <<< Critical Section | |
168 | |
169 // プロセス状態更新 | |
170 this_process->context.read.status = SPE_PROCESS_CONTEXT_STATUS_WRITTEN; | |
171 } | |
172 | |
173 return count; | |
174 | |
175 | |
176 spe_manager_write__error1: | |
177 return -ERESTARTSYS; | |
178 } | |
179 | |
180 | |
181 //================================================================================================== spe_manager_ioctl() | |
182 /** | |
183 * spe_manager_ioctl | |
184 * キャラクタデバイス ioctl イベントハンドラ [要修正] | |
185 * | |
186 * @param struct inode * inode | |
187 * @param struct file * filp | |
188 * @param unsigned int cmd | |
189 * @param unsigned long arg | |
190 * @return int | |
191 */ | |
192 int spe_manager_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) | |
193 { | |
194 // マジック番号の判定 | |
195 if (_IOC_TYPE(cmd) != SPE_MANAGER_IOCTL_MAGIC) return -ENOTTY; | |
196 | |
197 switch (cmd) | |
198 { | |
199 // SPE プロセスを開始する | |
200 case SPE_MANAGER_IOCTL_START_PROCESS: | |
201 // データ転送方向判定 | |
202 if (_IOC_DIR(cmd) != _IOC_NONE) return -ENOTTY; | |
203 | |
204 { | |
205 spe_process_context_list_t *this_process = (spe_process_context_list_t *)(filp->private_data); | |
206 struct semaphore *semaphore_for_process_list = get_semaphore_for_process_list(); | |
207 spinlock_t *spinlock_for_process_list = get_spinlock_for_process_list(); | |
208 int i, lspe_count = get_lspe_count(); | |
209 | |
210 | |
211 // Critical Section (semaphore) >>> | |
212 if (down_interruptible(semaphore_for_process_list)) | |
213 goto spe_manager_ioctl__error1; | |
214 | |
215 decrement_written(); | |
216 | |
217 // Critical Section (spinlock) >>> | |
218 spin_lock(spinlock_for_process_list); | |
219 { | |
220 for (i = 0; i < lspe_count; i++) | |
221 { | |
222 spe_process_context_list_t *running = get_running_process(i); | |
223 | |
224 // この論理 SPE でプロセスが実行中ではないか | |
225 if (running == NULL) | |
226 { | |
227 // このプロセスを実行中にする | |
228 // this_process->context.read.spe_no = i; | |
229 this_process->context.read.status = SPE_PROCESS_CONTEXT_STATUS_RUNNING; | |
230 | |
231 set_running_process(i, this_process); | |
232 break; | |
233 } | |
234 } | |
235 if (i >= lspe_count) | |
236 { | |
237 // 空きの SPE がなかったので実行待ちプロセスリストへ追加する | |
238 add_process_to_waiting(this_process); | |
239 } | |
240 } | |
241 spin_unlock(spinlock_for_process_list); | |
242 // <<< Critical Section (spinlock) | |
243 | |
244 up(semaphore_for_process_list); | |
245 // <<< Critical Section (semaphore) | |
246 | |
247 | |
248 // SPE プロセス開始 | |
249 if (i < lspe_count) start_spe_process(i, this_process); | |
250 } | |
251 | |
252 break; | |
253 | |
254 // それ以外のコマンド | |
255 default: | |
256 return -ENOTTY; | |
257 } | |
258 | |
259 return 0; | |
260 | |
261 | |
262 spe_manager_ioctl__error1: | |
263 return -ERESTARTSYS; | |
264 } | |
265 | |
266 | |
267 //=================================================================================================== spe_manager_read() | |
268 /** | |
269 * spe_manager_read | |
270 * キャラクタデバイス read イベントハンドラ | |
271 * | |
272 * @param struct file * filp | |
273 * @param char * buf | |
274 * @param size_t count | |
275 * @param loff_t * f_pos | |
276 * @return ssize_t | |
277 */ | |
278 ssize_t spe_manager_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) | |
279 { | |
280 spe_process_context_list_t *this_process = (spe_process_context_list_t *)(filp->private_data); | |
281 | |
282 | |
283 if (*f_pos >= sizeof(spe_process_context_read_data_t)) | |
284 // これ以上転送しない | |
285 return 0; | |
286 | |
287 if (*f_pos + count > sizeof(spe_process_context_read_data_t)) | |
288 // そのまま転送するとサイズオーバーなので調節する | |
289 count = sizeof(spe_process_context_read_data_t) - *f_pos; | |
290 | |
291 if (copy_to_user(buf, (void *)&(this_process->context.read) + *f_pos, count)) | |
292 { | |
293 printk(KERN_ERR "[%s] Error: copy_to_user() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__); | |
294 return -EFAULT; | |
295 } | |
296 | |
297 *f_pos += count; | |
298 return count; | |
299 } | |
300 | |
301 | |
302 //================================================================================================ spe_manager_release() | |
303 /** | |
304 * spe_manager_release | |
305 * キャラクタデバイス release イベントハンドラ | |
306 * | |
307 * @param struct inode * inode | |
308 * @param struct file * filp | |
309 * @return int | |
310 */ | |
311 int spe_manager_release(struct inode *inode, struct file *filp) | |
312 { | |
313 spe_process_context_list_t *this_process = (spe_process_context_list_t *)(filp->private_data); | |
314 struct semaphore *semaphore_for_process_list = get_semaphore_for_process_list(); | |
315 spinlock_t *spinlock_for_process_list = get_spinlock_for_process_list(); | |
316 | |
317 | |
318 // | |
319 // | |
320 // ToDo: SPE プロセスが NOT_RELEASED 状態でない時に | |
321 // 突然このハンドラが呼び出された場合の後始末 | |
322 // | |
323 // | |
324 | |
325 | |
326 // Critical Section (semaphore) >>> | |
327 if (down_interruptible(semaphore_for_process_list)) | |
328 goto spe_manager_release__error1; | |
329 | |
330 // Critical Section (spinlock) >>> | |
331 spin_lock(spinlock_for_process_list); | |
332 { | |
333 decrement_not_released(); | |
334 } | |
335 spin_unlock(spinlock_for_process_list); | |
336 // <<< Critical Section (spinlock) | |
337 | |
338 increment_released(); | |
339 | |
340 up(semaphore_for_process_list); | |
341 // <<< Critical Section (semaphore) | |
342 | |
343 | |
344 // SPE プロセスコンテキストのためのメモリを解放 | |
345 vfree(this_process); | |
346 return 0; | |
347 | |
348 | |
349 spe_manager_release__error1: | |
350 return -ERESTARTSYS; | |
351 } |