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,102 @@ 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: `condvar_init!` is called below.
71
+ state_changed : unsafe { CondVar :: new ( ) } ,
72
+ // SAFETY: `mutex_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 ( & self , _file : & File , data : & mut UserSlicePtrWriter , offset : u64 ) -> KernelResult {
103
+ // Succeed if the caller doesn't provide a buffer or if not at the start.
104
+ if data. is_empty ( ) || offset != 0 {
105
+ return Ok ( ( ) ) ;
106
+ }
107
+
108
+ {
109
+ let mut inner = self . shared . inner . lock ( ) ;
110
+
111
+ // Wait until we are allowed to decrement the token count or a signal arrives.
112
+ while inner. token_count == 0 {
113
+ if self . shared . state_changed . wait ( & mut inner) {
114
+ return Err ( Error :: EINTR ) ;
115
+ }
116
+ }
117
+
118
+ // Consume a token.
119
+ inner. token_count -= 1 ;
120
+ }
121
+
122
+ // Notify a possible writer waiting.
123
+ self . shared . state_changed . notify_all ( ) ;
124
+
125
+ // Write a one-byte 1 to the reader.
126
+ data. write_slice ( & [ 1u8 ; 1 ] ) ?;
127
+ Ok ( ( ) )
128
+ }
129
+
130
+ fn write ( & self , data : & mut UserSlicePtrReader , _offset : u64 ) -> KernelResult < isize > {
131
+ {
132
+ let mut inner = self . shared . inner . lock ( ) ;
133
+
134
+ // Wait until we are allowed to increment the token count or a signal arrives.
135
+ while inner. token_count == MAX_TOKENS {
136
+ if self . shared . state_changed . wait ( & mut inner) {
137
+ return Err ( Error :: EINTR ) ;
138
+ }
139
+ }
140
+
141
+ // Increment the number of token so that a reader can be released.
142
+ inner. token_count += 1 ;
143
+ }
144
+
145
+ // Notify a possible reader waiting.
146
+ self . shared . state_changed . notify_all ( ) ;
147
+ data. read_all ( ) ?;
148
+ Ok ( 0 )
149
+ }
150
+ }
151
+
54
152
struct RustFile ;
55
153
56
154
impl FileOpener < ( ) > for RustFile {
@@ -69,7 +167,7 @@ impl FileOperations for RustFile {
69
167
struct RustExample {
70
168
message : String ,
71
169
_chrdev : Pin < Box < chrdev:: Registration < 2 > > > ,
72
- _dev : Pin < Box < miscdev:: Registration > > ,
170
+ _dev : Pin < Box < miscdev:: Registration < Arc < SharedState > > > > ,
73
171
}
74
172
75
173
impl KernelModule for RustExample {
@@ -148,9 +246,11 @@ impl KernelModule for RustExample {
148
246
chrdev_reg. as_mut ( ) . register :: < RustFile > ( ) ?;
149
247
chrdev_reg. as_mut ( ) . register :: < RustFile > ( ) ?;
150
248
249
+ let state = SharedState :: try_new ( ) ?;
250
+
151
251
Ok ( RustExample {
152
252
message : "on the heap!" . to_owned ( ) ,
153
- _dev : miscdev:: Registration :: new_pinned :: < RustFile > ( cstr ! ( "rust_miscdev" ) , None , ( ) ) ?,
253
+ _dev : miscdev:: Registration :: new_pinned :: < Token > ( cstr ! ( "rust_miscdev" ) , None , state ) ?,
154
254
_chrdev : chrdev_reg,
155
255
} )
156
256
}
0 commit comments