1
1
//! A small module that's intended to provide an example of creating a pool of
2
2
//! web workers which can be used to execute `rayon`-style work.
3
3
4
- use futures:: sync:: oneshot;
5
- use futures:: Future ;
6
- use std:: cell:: { RefCell , UnsafeCell } ;
7
- use std:: mem;
4
+ use std:: cell:: RefCell ;
8
5
use std:: rc:: Rc ;
9
- use std:: sync:: atomic:: { AtomicBool , Ordering :: SeqCst } ;
10
- use std:: sync:: Arc ;
11
6
use wasm_bindgen:: prelude:: * ;
12
7
use wasm_bindgen:: JsCast ;
13
8
use web_sys:: { DedicatedWorkerGlobalScope , MessageEvent } ;
@@ -141,12 +136,11 @@ impl WorkerPool {
141
136
/// whatn it's done the worker is ready to execute more work. This method is
142
137
/// used for all spawned workers to ensure that when the work is finished
143
138
/// the worker is reclaimed back into this pool.
144
- fn reclaim_on_message ( & self , worker : Worker , on_finish : impl FnOnce ( ) + ' static ) {
139
+ fn reclaim_on_message ( & self , worker : Worker ) {
145
140
let state = Rc :: downgrade ( & self . state ) ;
146
141
let worker2 = worker. clone ( ) ;
147
142
let reclaim_slot = Rc :: new ( RefCell :: new ( None ) ) ;
148
143
let slot2 = reclaim_slot. clone ( ) ;
149
- let mut on_finish = Some ( on_finish) ;
150
144
let reclaim = Closure :: wrap ( Box :: new ( move |event : Event | {
151
145
if let Some ( error) = event. dyn_ref :: < ErrorEvent > ( ) {
152
146
console_log ! ( "error in worker: {}" , error. message( ) ) ;
@@ -155,11 +149,9 @@ impl WorkerPool {
155
149
return ;
156
150
}
157
151
158
- // If this is a completion event then we can execute our `on_finish`
159
- // callback and we can also deallocate our own callback by clearing
160
- // out `slot2` which contains our own closure.
152
+ // If this is a completion event then can deallocate our own
153
+ // callback by clearing out `slot2` which contains our own closure.
161
154
if let Some ( _msg) = event. dyn_ref :: < MessageEvent > ( ) {
162
- on_finish. take ( ) . unwrap ( ) ( ) ;
163
155
if let Some ( state) = state. upgrade ( ) {
164
156
state. push ( worker2. clone ( ) ) ;
165
157
}
@@ -193,80 +185,9 @@ impl WorkerPool {
193
185
/// a web worker, that error is returned.
194
186
pub fn run ( & self , f : impl FnOnce ( ) + Send + ' static ) -> Result < ( ) , JsValue > {
195
187
let worker = self . execute ( f) ?;
196
- self . reclaim_on_message ( worker, || { } ) ;
188
+ self . reclaim_on_message ( worker) ;
197
189
Ok ( ( ) )
198
190
}
199
-
200
- /// Executes the closure `f` in a web worker, returning a future of the
201
- /// value that `f` produces.
202
- ///
203
- /// This method is the same as `run` execept that it allows recovering the
204
- /// return value of the closure `f` in a nonblocking fashion with the future
205
- /// returned.
206
- ///
207
- /// # Errors
208
- ///
209
- /// If an error happens while spawning a web worker or sending a message to
210
- /// a web worker, that error is returned.
211
- pub fn run_notify < T > (
212
- & self ,
213
- f : impl FnOnce ( ) -> T + Send + ' static ,
214
- ) -> Result < impl Future < Item = T , Error = JsValue > + ' static , JsValue >
215
- where
216
- T : Send + ' static ,
217
- {
218
- // FIXME(#1379) we should just use the `oneshot` directly as the future,
219
- // but we have to use JS callbacks to ensure we don't have futures cross
220
- // threads as that's currently not safe to do so.
221
- let ( tx, rx) = oneshot:: channel ( ) ;
222
- let storage = Arc :: new ( AtomicValue :: new ( None ) ) ;
223
- let storage2 = storage. clone ( ) ;
224
- let worker = self . execute ( move || {
225
- assert ! ( storage2. replace( Some ( f( ) ) ) . is_ok( ) ) ;
226
- } ) ?;
227
- self . reclaim_on_message ( worker, move || match storage. replace ( None ) {
228
- Ok ( Some ( val) ) => drop ( tx. send ( val) ) ,
229
- _ => unreachable ! ( ) ,
230
- } ) ;
231
-
232
- Ok ( rx. map_err ( |_| JsValue :: undefined ( ) ) )
233
- }
234
- }
235
-
236
- /// A small helper struct representing atomic access to an internal value `T`
237
- ///
238
- /// This struct only supports one API, `replace`, which will either succeed and
239
- /// replace the internal value with another (returning the previous one), or it
240
- /// will fail returning the value passed in. Failure happens when two threads
241
- /// try to `replace` at the same time.
242
- ///
243
- /// This is only really intended to help safely transfer information between
244
- /// threads, it doesn't provide any synchronization capabilities itself other
245
- /// than a guaranteed safe API.
246
- struct AtomicValue < T > {
247
- modifying : AtomicBool ,
248
- slot : UnsafeCell < T > ,
249
- }
250
-
251
- unsafe impl < T : Send > Send for AtomicValue < T > { }
252
- unsafe impl < T : Send > Sync for AtomicValue < T > { }
253
-
254
- impl < T > AtomicValue < T > {
255
- fn new ( val : T ) -> AtomicValue < T > {
256
- AtomicValue {
257
- modifying : AtomicBool :: new ( false ) ,
258
- slot : UnsafeCell :: new ( val) ,
259
- }
260
- }
261
-
262
- fn replace ( & self , val : T ) -> Result < T , T > {
263
- if self . modifying . swap ( true , SeqCst ) {
264
- return Err ( val) ;
265
- }
266
- let ret = unsafe { mem:: replace ( & mut * self . slot . get ( ) , val) } ;
267
- self . modifying . store ( false , SeqCst ) ;
268
- Ok ( ret)
269
- }
270
191
}
271
192
272
193
impl PoolState {
0 commit comments