5
5
//!
6
6
//! How to build only modules:
7
7
//! make LLVM=1 M=samples/rust
8
- use core:: marker:: PhantomPinned ;
8
+ //!
9
+ //! How to use:
10
+ //! / # insmod rust_ldd06.ko
11
+ //! / # mknod /dev/rust_ldd06 c 10 124
12
+ //! / # echo "hello" > /dev/rust_ldd06
13
+ //! / # cat /dev/rust_ldd06
9
14
use kernel:: prelude:: * ;
10
15
use kernel:: {
11
16
bindings,
12
17
file:: { self , File } ,
13
18
fmt,
14
19
io_buffer:: { IoBufferReader , IoBufferWriter } ,
15
- miscdev, pin_init,
16
- sync:: { Arc , ArcBorrow } ,
17
- types:: Opaque ,
20
+ miscdev, new_mutex, pin_init,
21
+ sync:: { Arc , ArcBorrow , Mutex } ,
18
22
} ;
19
23
20
24
module ! {
@@ -25,24 +29,40 @@ module! {
25
29
license: "GPL" ,
26
30
}
27
31
32
+ // Fist I made CompletionDev { completion: bindings::completion }.
33
+ // But it didn't work because we cannot get mutable reference to CompletionDev in read/write functions.
34
+ // The argument of read/write functions is ArcBorrow<'_, CompletionDev>.
35
+ // So it's not allowed to get the mutable reference to CompletionDev.
36
+ // The only way to mutate through ArcBorrow is to use Mutex/RwLock/Atomic types.
37
+ // (see doc.rust-lang.org/std/sync/struct.Mutex.html)
38
+ // Finally I makde CompletionInner struct and put it into Mutex.
39
+ struct CompletionInner {
40
+ completion : bindings:: completion ,
41
+ dummy : usize , // nothing but to check how to use Mutex
42
+ }
43
+
28
44
// internal info between file operations
29
45
#[ pin_data]
30
46
struct CompletionDev {
31
47
pub completion : bindings:: completion ,
32
48
33
49
#[ pin]
34
- _pin : PhantomPinned ,
50
+ inner : Mutex < CompletionInner > ,
35
51
}
36
52
37
53
// TODO: impl CompletionDev::try_new
38
54
impl CompletionDev {
39
55
fn try_new ( ) -> Result < Arc < Self > > {
40
56
pr_info ! ( "completion_dev created\n " ) ;
41
-
42
- Ok ( Arc :: try_new ( Self {
43
- _pin : PhantomPinned ,
44
- completion : bindings:: completion:: default ( ) ,
45
- } ) ?)
57
+ let dev = Arc :: pin_init ( pin_init ! ( Self {
58
+ completion: bindings:: completion:: default ( ) , // Default trait is implmented by bindget. See rust/bindings/bindings_generates.rs
59
+ inner <- new_mutex!( CompletionInner {
60
+ completion: bindings:: completion:: default ( ) ,
61
+ dummy: 0 ,
62
+ } ) ,
63
+ } ) ) ?;
64
+
65
+ Ok ( dev)
46
66
}
47
67
}
48
68
@@ -66,29 +86,51 @@ impl file::Operations for RustFile {
66
86
fn read (
67
87
shared : ArcBorrow < ' _ , CompletionDev > ,
68
88
_: & File ,
69
- data : & mut impl IoBufferWriter ,
70
- offset : u64 ,
89
+ _data : & mut impl IoBufferWriter ,
90
+ _offset : u64 ,
71
91
) -> Result < usize > {
72
92
pr_info ! ( "read is invoked\n " ) ;
73
93
94
+ let mut inner_guard = shared. inner . lock ( ) ;
95
+ inner_guard. dummy += 1 ;
96
+ pr_info ! ( "read:dummy={}\n " , inner_guard. dummy) ;
97
+
98
+ unsafe {
99
+ bindings:: wait_for_completion ( & mut inner_guard. completion ) ;
100
+ }
101
+
74
102
Ok ( 0 )
75
103
}
76
104
77
105
fn write (
78
106
shared : ArcBorrow < ' _ , CompletionDev > ,
79
107
_: & File ,
80
108
data : & mut impl IoBufferReader ,
81
- offset : u64 ,
109
+ _offset : u64 ,
82
110
) -> Result < usize > {
83
111
pr_debug ! ( "write is invoked\n " ) ;
84
112
85
- let len: usize = data. len ( ) ;
86
- pr_info ! ( "write: {} bytes\n " , len) ;
87
- Ok ( len)
113
+ let mut inner_guard = shared. inner . lock ( ) ;
114
+ pr_info ! ( "write:dummy={}\n " , inner_guard. dummy) ;
115
+ if inner_guard. dummy == 1 {
116
+ pr_info ! ( "read() is waiting for completion\n " ) ;
117
+
118
+ unsafe {
119
+ bindings:: complete ( & mut inner_guard. completion ) ;
120
+ }
121
+ } else if inner_guard. dummy == 0 {
122
+ pr_info ! ( "read() is not waiting for completion\n " ) ;
123
+ } else {
124
+ pr_info ! ( "Something went wrong\n " ) ;
125
+ }
126
+
127
+ // return non-zero value to avoid infinite re-try
128
+ Ok ( data. len ( ) )
88
129
}
89
130
90
- fn release ( _data : Self :: Data , _file : & File ) {
131
+ fn release ( data : Self :: Data , _file : & File ) {
91
132
pr_info ! ( "release is invoked\n " ) ;
133
+ pr_info ! ( "release:dummy={}\n " , data. inner. lock( ) . dummy) ;
92
134
}
93
135
}
94
136
@@ -101,6 +143,7 @@ impl kernel::Module for RustCompletion {
101
143
pr_info ! ( "rust_ldd06 is loaded\n " ) ;
102
144
103
145
let dev: Arc < CompletionDev > = CompletionDev :: try_new ( ) ?;
146
+
104
147
let reg = miscdev:: Registration :: new_pinned ( fmt ! ( "rust_ldd06" ) , dev) ?;
105
148
106
149
Ok ( RustCompletion { _dev : reg } )
0 commit comments