6
6
#![ feature( allocator_api, global_asm) ]
7
7
#![ feature( test) ]
8
8
9
- use alloc:: boxed:: Box ;
9
+ use alloc:: { boxed:: Box , sync :: Arc } ;
10
10
use core:: pin:: Pin ;
11
11
use kernel:: prelude:: * ;
12
12
use kernel:: {
13
13
chrdev, condvar_init, cstr,
14
- file_operations:: { FileOpener , FileOperations } ,
14
+ file_operations:: { File , FileOpener , FileOperations } ,
15
15
miscdev, mutex_init, spinlock_init,
16
16
sync:: { CondVar , Mutex , SpinLock } ,
17
+ user_ptr:: { UserSlicePtrReader , UserSlicePtrWriter } ,
18
+ Error ,
17
19
} ;
18
20
19
21
module ! {
@@ -51,6 +53,106 @@ module! {
51
53
} ,
52
54
}
53
55
56
+ const MAX_TOKENS : usize = 3 ;
57
+
58
+ struct SharedStateInner {
59
+ token_count : usize ,
60
+ }
61
+
62
+ struct SharedState {
63
+ state_changed : CondVar ,
64
+ inner : Mutex < SharedStateInner > ,
65
+ }
66
+
67
+ impl SharedState {
68
+ fn try_new ( ) -> KernelResult < Arc < Self > > {
69
+ let state = Arc :: try_new ( Self {
70
+ // SAFETY: Init is called below.
71
+ state_changed : unsafe { CondVar :: new ( ) } ,
72
+ // SAFETY: Init is called below.
73
+ inner : unsafe { Mutex :: new ( SharedStateInner { token_count : 0 } ) } ,
74
+ } ) ?;
75
+ // SAFETY: `state_changed` is pinned behind `Arc`.
76
+ let state_changed = unsafe { Pin :: new_unchecked ( & state. state_changed ) } ;
77
+ kernel:: condvar_init!( state_changed, "SharedState::state_changed" ) ;
78
+ // SAFETY: `inner` is pinned behind `Arc`.
79
+ let inner = unsafe { Pin :: new_unchecked ( & state. inner ) } ;
80
+ kernel:: mutex_init!( inner, "SharedState::inner" ) ;
81
+ Ok ( state)
82
+ }
83
+ }
84
+
85
+ struct Token {
86
+ shared : Arc < SharedState > ,
87
+ }
88
+
89
+ impl FileOpener < Arc < SharedState > > for Token {
90
+ fn open ( shared : & Arc < SharedState > ) -> KernelResult < Self :: Wrapper > {
91
+ Ok ( Box :: try_new ( Self {
92
+ shared : shared. clone ( ) ,
93
+ } ) ?)
94
+ }
95
+ }
96
+
97
+ impl FileOperations for Token {
98
+ type Wrapper = Box < Self > ;
99
+
100
+ kernel:: declare_file_operations!( read, write) ;
101
+
102
+ fn read (
103
+ & self ,
104
+ _file : & File ,
105
+ data : & mut UserSlicePtrWriter ,
106
+ offset : u64 ,
107
+ ) -> KernelResult < usize > {
108
+ // Succeed if the caller doesn't provide a buffer or if not at the start.
109
+ if data. is_empty ( ) || offset != 0 {
110
+ return Ok ( 0 ) ;
111
+ }
112
+
113
+ {
114
+ let mut inner = self . shared . inner . lock ( ) ;
115
+
116
+ // Wait until we are allowed to decrement the token count or a signal arrives.
117
+ while inner. token_count == 0 {
118
+ if self . shared . state_changed . wait ( & mut inner) {
119
+ return Err ( Error :: EINTR ) ;
120
+ }
121
+ }
122
+
123
+ // Consume a token.
124
+ inner. token_count -= 1 ;
125
+ }
126
+
127
+ // Notify a possible writer waiting.
128
+ self . shared . state_changed . notify_all ( ) ;
129
+
130
+ // Write a one-byte 1 to the reader.
131
+ data. write_slice ( & [ 1u8 ; 1 ] ) ?;
132
+ Ok ( 1 )
133
+ }
134
+
135
+ fn write ( & self , data : & mut UserSlicePtrReader , _offset : u64 ) -> KernelResult < usize > {
136
+ {
137
+ let mut inner = self . shared . inner . lock ( ) ;
138
+
139
+ // Wait until we are allowed to increment the token count or a signal arrives.
140
+ while inner. token_count == MAX_TOKENS {
141
+ if self . shared . state_changed . wait ( & mut inner) {
142
+ return Err ( Error :: EINTR ) ;
143
+ }
144
+ }
145
+
146
+ // Increment the number of token so that a reader can be released.
147
+ inner. token_count += 1 ;
148
+ }
149
+
150
+ // Notify a possible reader waiting.
151
+ self . shared . state_changed . notify_all ( ) ;
152
+ Ok ( data. len ( ) )
153
+ }
154
+ }
155
+
54
156
struct RustFile ;
55
157
56
158
impl FileOpener < ( ) > for RustFile {
@@ -69,7 +171,7 @@ impl FileOperations for RustFile {
69
171
struct RustExample {
70
172
message : String ,
71
173
_chrdev : Pin < Box < chrdev:: Registration < 2 > > > ,
72
- _dev : Pin < Box < miscdev:: Registration > > ,
174
+ _dev : Pin < Box < miscdev:: Registration < Arc < SharedState > > > > ,
73
175
}
74
176
75
177
impl KernelModule for RustExample {
@@ -148,9 +250,11 @@ impl KernelModule for RustExample {
148
250
chrdev_reg. as_mut ( ) . register :: < RustFile > ( ) ?;
149
251
chrdev_reg. as_mut ( ) . register :: < RustFile > ( ) ?;
150
252
253
+ let state = SharedState :: try_new ( ) ?;
254
+
151
255
Ok ( RustExample {
152
256
message : "on the heap!" . to_owned ( ) ,
153
- _dev : miscdev:: Registration :: new_pinned :: < RustFile > ( cstr ! ( "rust_miscdev" ) , None , ( ) ) ?,
257
+ _dev : miscdev:: Registration :: new_pinned :: < Token > ( cstr ! ( "rust_miscdev" ) , None , state ) ?,
154
258
_chrdev : chrdev_reg,
155
259
} )
156
260
}
0 commit comments