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 }