@@ -11,7 +11,9 @@ use sleep::Sleep;
11
11
use std:: any:: Any ;
12
12
use std:: cell:: Cell ;
13
13
use std:: collections:: hash_map:: DefaultHasher ;
14
+ use std:: fmt;
14
15
use std:: hash:: Hasher ;
16
+ use std:: io;
15
17
use std:: mem;
16
18
use std:: ptr;
17
19
#[ allow( deprecated) ]
@@ -24,6 +26,49 @@ use unwind;
24
26
use util:: leak;
25
27
use { ErrorKind , ExitHandler , PanicHandler , StartHandler , ThreadPoolBuildError , ThreadPoolBuilder } ;
26
28
29
+ /// Thread builder used for customization via `ThreadPoolBuilder::spawn`.
30
+ pub struct ThreadBuilder {
31
+ name : Option < String > ,
32
+ stack_size : Option < usize > ,
33
+ worker : Worker < JobRef > ,
34
+ registry : Arc < Registry > ,
35
+ index : usize ,
36
+ }
37
+
38
+ impl ThreadBuilder {
39
+ /// Get the index of this thread in the pool, within `0..num_threads`.
40
+ pub fn index ( & self ) -> usize {
41
+ self . index
42
+ }
43
+
44
+ /// Get the string that was specified by `ThreadPoolBuilder::name()`.
45
+ pub fn name ( & self ) -> Option < & str > {
46
+ self . name . as_ref ( ) . map ( String :: as_str)
47
+ }
48
+
49
+ /// Get the value that was specified by `ThreadPoolBuilder::stack_size()`.
50
+ pub fn stack_size ( & self ) -> Option < usize > {
51
+ self . stack_size
52
+ }
53
+
54
+ /// Execute the main loop for this thread. This will not return until the
55
+ /// thread pool is dropped.
56
+ pub fn run ( self ) {
57
+ unsafe { main_loop ( self . worker , self . registry , self . index ) }
58
+ }
59
+ }
60
+
61
+ impl fmt:: Debug for ThreadBuilder {
62
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
63
+ f. debug_struct ( "ThreadBuilder" )
64
+ . field ( "pool" , & self . registry . id ( ) )
65
+ . field ( "index" , & self . index )
66
+ . field ( "name" , & self . name )
67
+ . field ( "stack_size" , & self . stack_size )
68
+ . finish ( )
69
+ }
70
+ }
71
+
27
72
pub ( super ) struct Registry {
28
73
thread_infos : Vec < ThreadInfo > ,
29
74
sleep : Sleep ,
@@ -58,39 +103,50 @@ static THE_REGISTRY_SET: Once = ONCE_INIT;
58
103
/// initialization has not already occurred, use the default
59
104
/// configuration.
60
105
fn global_registry ( ) -> & ' static Arc < Registry > {
61
- THE_REGISTRY_SET . call_once ( || unsafe { init_registry ( ThreadPoolBuilder :: new ( ) ) . unwrap ( ) } ) ;
62
- unsafe { THE_REGISTRY . expect ( "The global thread pool has not been initialized." ) }
106
+ unsafe {
107
+ THE_REGISTRY . unwrap_or_else ( || {
108
+ init_global_registry ( ThreadPoolBuilder :: new ( ) )
109
+ . expect ( "The global thread pool has not been initialized." )
110
+ } )
111
+ }
63
112
}
64
113
65
114
/// Starts the worker threads (if that has not already happened) with
66
115
/// the given builder.
67
116
pub ( super ) fn init_global_registry (
68
117
builder : ThreadPoolBuilder ,
69
- ) -> Result < & ' static Registry , ThreadPoolBuildError > {
70
- let mut called = false ;
71
- let mut init_result = Ok ( ( ) ) ; ;
72
- THE_REGISTRY_SET . call_once ( || unsafe {
73
- init_result = init_registry ( builder) ;
74
- called = true ;
75
- } ) ;
76
- if called {
77
- init_result?;
78
- Ok ( & * * global_registry ( ) )
79
- } else {
80
- Err ( ThreadPoolBuildError :: new (
81
- ErrorKind :: GlobalPoolAlreadyInitialized ,
82
- ) )
83
- }
118
+ ) -> Result < & ' static Arc < Registry > , ThreadPoolBuildError > {
119
+ set_global_registry ( || Registry :: new ( builder) )
120
+ }
121
+
122
+ /// Starts the worker threads (if that has not already happened) with
123
+ /// the given builder.
124
+ pub ( super ) fn spawn_global_registry (
125
+ builder : ThreadPoolBuilder ,
126
+ spawn : impl FnMut ( ThreadBuilder ) -> io:: Result < ( ) > ,
127
+ ) -> Result < & ' static Arc < Registry > , ThreadPoolBuildError > {
128
+ set_global_registry ( || Registry :: spawn ( builder, spawn) )
84
129
}
85
130
86
- /// Initializes the global registry with the given builder.
87
- /// Meant to be called from within the `THE_REGISTRY_SET` once
88
- /// function. Declared `unsafe` because it writes to `THE_REGISTRY` in
89
- /// an unsynchronized fashion.
90
- unsafe fn init_registry ( builder : ThreadPoolBuilder ) -> Result < ( ) , ThreadPoolBuildError > {
91
- let registry = Registry :: new ( builder) ?;
92
- THE_REGISTRY = Some ( leak ( registry) ) ;
93
- Ok ( ( ) )
131
+ /// Starts the worker threads (if that has not already happened)
132
+ /// by creating a registry with the given callback.
133
+ fn set_global_registry < F > ( registry : F ) -> Result < & ' static Arc < Registry > , ThreadPoolBuildError >
134
+ where
135
+ F : FnOnce ( ) -> Result < Arc < Registry > , ThreadPoolBuildError > ,
136
+ {
137
+ let mut result = Err ( ThreadPoolBuildError :: new (
138
+ ErrorKind :: GlobalPoolAlreadyInitialized ,
139
+ ) ) ;
140
+ THE_REGISTRY_SET . call_once ( || {
141
+ result = registry ( ) . map ( |registry| {
142
+ let registry = leak ( registry) ;
143
+ unsafe {
144
+ THE_REGISTRY = Some ( registry) ;
145
+ }
146
+ registry
147
+ } ) ;
148
+ } ) ;
149
+ result
94
150
}
95
151
96
152
struct Terminator < ' a > ( & ' a Arc < Registry > ) ;
@@ -102,7 +158,24 @@ impl<'a> Drop for Terminator<'a> {
102
158
}
103
159
104
160
impl Registry {
105
- pub ( super ) fn new ( mut builder : ThreadPoolBuilder ) -> Result < Arc < Self > , ThreadPoolBuildError > {
161
+ pub ( super ) fn new ( builder : ThreadPoolBuilder ) -> Result < Arc < Self > , ThreadPoolBuildError > {
162
+ Registry :: spawn ( builder, |thread| {
163
+ let mut b = thread:: Builder :: new ( ) ;
164
+ if let Some ( ref name) = thread. name {
165
+ b = b. name ( name. clone ( ) ) ;
166
+ }
167
+ if let Some ( stack_size) = thread. stack_size {
168
+ b = b. stack_size ( stack_size) ;
169
+ }
170
+ b. spawn ( || thread. run ( ) ) ?;
171
+ Ok ( ( ) )
172
+ } )
173
+ }
174
+
175
+ pub ( super ) fn spawn (
176
+ mut builder : ThreadPoolBuilder ,
177
+ mut spawn : impl FnMut ( ThreadBuilder ) -> io:: Result < ( ) > ,
178
+ ) -> Result < Arc < Self > , ThreadPoolBuildError > {
106
179
let n_threads = builder. get_num_threads ( ) ;
107
180
let breadth_first = builder. get_breadth_first ( ) ;
108
181
@@ -130,15 +203,14 @@ impl Registry {
130
203
let t1000 = Terminator ( & registry) ;
131
204
132
205
for ( index, worker) in workers. into_iter ( ) . enumerate ( ) {
133
- let registry = registry. clone ( ) ;
134
- let mut b = thread:: Builder :: new ( ) ;
135
- if let Some ( name) = builder. get_thread_name ( index) {
136
- b = b. name ( name) ;
137
- }
138
- if let Some ( stack_size) = builder. get_stack_size ( ) {
139
- b = b. stack_size ( stack_size) ;
140
- }
141
- if let Err ( e) = b. spawn ( move || unsafe { main_loop ( worker, registry, index) } ) {
206
+ let thread = ThreadBuilder {
207
+ name : builder. get_thread_name ( index) ,
208
+ stack_size : builder. get_stack_size ( ) ,
209
+ registry : registry. clone ( ) ,
210
+ worker,
211
+ index,
212
+ } ;
213
+ if let Err ( e) = spawn ( thread) {
142
214
return Err ( ThreadPoolBuildError :: new ( ErrorKind :: IOError ( e) ) ) ;
143
215
}
144
216
}
0 commit comments