2
2
3
3
pub mod rusage;
4
4
5
- use std:: {
6
- future:: Future ,
7
- process:: ExitStatus ,
8
- time:: { Duration , Instant } ,
9
- } ;
5
+ use std:: { future:: Future , process:: ExitStatus , time:: Duration } ;
10
6
11
7
use nix:: sys:: resource:: { setrlimit, Resource } ;
12
8
use rsjudge_traits:: resource:: ResourceLimit ;
13
- use tokio:: process:: { Child , Command } ;
9
+ use tokio:: {
10
+ process:: { Child , Command } ,
11
+ time:: Instant ,
12
+ } ;
14
13
15
- use self :: rusage:: ResourceUsage ;
16
- use crate :: { utils :: resources :: rusage :: WaitForResourceUsage , Result } ;
14
+ use self :: rusage:: { ResourceUsage , WaitForResourceUsage } ;
15
+ use crate :: Result ;
17
16
18
17
#[ derive( Debug ) ]
19
- pub struct ChildWithTimeout {
20
- child : Child ,
21
- start : Instant ,
18
+ pub struct CommandWithResourceLimit {
19
+ command : Command ,
22
20
timeout : Option < Duration > ,
23
21
}
24
22
25
- impl AsRef < Child > for ChildWithTimeout {
26
- fn as_ref ( & self ) -> & Child {
27
- & self . child
23
+ impl CommandWithResourceLimit {
24
+ /// Get a reference to the inner [`Command`].
25
+ pub fn command ( & self ) -> & Command {
26
+ & self . command
28
27
}
29
- }
30
28
31
- impl AsMut < Child > for ChildWithTimeout {
32
- fn as_mut ( & mut self ) -> & mut Child {
33
- & mut self . child
29
+ /// Get a mutable reference to the inner [`Command`].
30
+ pub fn command_mut ( & mut self ) -> & mut Command {
31
+ & mut self . command
32
+ }
33
+
34
+ /// Spawn the [`Command`] with the given resource limit.
35
+ ///
36
+ /// This function is synchronous and won't wait for the child to exit.
37
+ pub fn spawn ( & mut self ) -> Result < ChildWithDeadline > {
38
+ Ok ( ChildWithDeadline {
39
+ child : self . command . spawn ( ) ?,
40
+ deadline : self . timeout . map ( |timeout| Instant :: now ( ) + timeout) ,
41
+ } )
34
42
}
35
43
}
36
44
37
- pub trait RunWithResourceLimit {
45
+ /// Setting resource limits for a [`Command`].
46
+ ///
47
+ /// This will take the [`Command`] by value and set the [`ResourceLimit`] for it.
48
+ pub trait WithResourceLimit {
49
+ /// Register resource limit for the command.
50
+ ///
51
+ /// Returns a [`CommandWithResourceLimit`] which can be spawned.
52
+ ///
53
+ /// You can also use [`command`][fn.command] or [`command_mut`][fn.command_mut]
54
+ /// to get the inner [`Command`][tokio::process::Command] object as needed.
55
+ ///
56
+ /// [fn.command]: CommandWithResourceLimit::command
57
+ /// [fn.command_mut]: CommandWithResourceLimit::command_mut
58
+ fn with_resource_limit ( self , resource_limit : ResourceLimit ) -> CommandWithResourceLimit ;
38
59
/// Spawn [`Self`] with optional resource limit.
39
60
///
40
61
/// This function won't wait for the child to exit.
41
62
/// Nor will it apply the [`ResourceLimit::wall_time_limit`] automatically.
42
63
///
43
- /// However, the wall time limit can be applied by using [`WaitForResourceUsage:: wait_for_resource_usage`].
64
+ /// However, the wall time limit can be applied by using [`wait_for_resource_usage`].
44
65
///
45
66
/// This function is synchronous.
46
67
///
47
68
/// # Errors
48
69
///
49
70
/// This function will return an error if the child process cannot be spawned.
50
- fn spawn_with_resource_limit (
51
- & mut self ,
52
- resource_info : ResourceLimit ,
53
- ) -> Result < ChildWithTimeout > ;
71
+ ///
72
+ /// [`wait_for_resource_usage`]: WaitForResourceUsage::wait_for_resource_usage
73
+ fn spawn_with_resource_limit ( self , resource_limit : ResourceLimit ) -> Result < ChildWithDeadline > ;
54
74
55
75
/// Run [`Self`] with given resource limit.
56
76
fn wait_with_resource_limit (
57
- & mut self ,
58
- resource_info : ResourceLimit ,
77
+ self ,
78
+ resource_limit : ResourceLimit ,
59
79
) -> impl Future < Output = Result < Option < ( ExitStatus , ResourceUsage ) > > > + Send ;
60
80
}
61
81
62
- impl RunWithResourceLimit for Command {
63
- fn spawn_with_resource_limit (
64
- & mut self ,
65
- resource_info : ResourceLimit ,
66
- ) -> Result < ChildWithTimeout > {
82
+ impl WithResourceLimit for Command {
83
+ fn with_resource_limit ( mut self , resource_info : ResourceLimit ) -> CommandWithResourceLimit {
67
84
if let Some ( cpu_time_limit) = resource_info. cpu_time_limit ( ) {
68
85
let set_cpu_limit = move || {
69
86
setrlimit (
@@ -78,6 +95,7 @@ impl RunWithResourceLimit for Command {
78
95
self . pre_exec ( set_cpu_limit) ;
79
96
}
80
97
}
98
+
81
99
if let Some ( memory_limit) = resource_info. memory_limit ( ) {
82
100
let set_memory_limit = move || {
83
101
setrlimit ( Resource :: RLIMIT_AS , memory_limit, memory_limit) ?;
@@ -104,15 +122,18 @@ impl RunWithResourceLimit for Command {
104
122
}
105
123
}
106
124
107
- Ok ( ChildWithTimeout {
108
- child : self . spawn ( ) ?,
109
- start : Instant :: now ( ) ,
125
+ CommandWithResourceLimit {
126
+ command : self ,
110
127
timeout : resource_info. wall_time_limit ( ) ,
111
- } )
128
+ }
129
+ }
130
+
131
+ fn spawn_with_resource_limit ( self , resource_limit : ResourceLimit ) -> Result < ChildWithDeadline > {
132
+ self . with_resource_limit ( resource_limit) . spawn ( )
112
133
}
113
134
114
135
async fn wait_with_resource_limit (
115
- & mut self ,
136
+ self ,
116
137
resource_limit : ResourceLimit ,
117
138
) -> Result < Option < ( ExitStatus , ResourceUsage ) > > {
118
139
self . spawn_with_resource_limit ( resource_limit) ?
@@ -121,21 +142,41 @@ impl RunWithResourceLimit for Command {
121
142
}
122
143
}
123
144
145
+ #[ derive( Debug ) ]
146
+ pub struct ChildWithDeadline {
147
+ child : Child ,
148
+
149
+ deadline : Option < Instant > ,
150
+ }
151
+
152
+ impl ChildWithDeadline {
153
+ /// Get a reference to the inner [`Child`].
154
+ pub fn child ( & self ) -> & Child {
155
+ & self . child
156
+ }
157
+
158
+ /// Get a mutable reference to the inner [`Child`].
159
+ pub fn child_mut ( & mut self ) -> & mut Child {
160
+ & mut self . child
161
+ }
162
+ }
163
+
124
164
#[ cfg( test) ]
125
165
mod tests {
126
166
use std:: time:: { Duration , Instant } ;
127
167
128
168
use rsjudge_traits:: resource:: ResourceLimit ;
129
169
130
170
use crate :: {
131
- utils:: resources:: { rusage:: WaitForResourceUsage as _, RunWithResourceLimit } ,
171
+ utils:: resources:: { rusage:: WaitForResourceUsage as _, WithResourceLimit as _ } ,
132
172
Error ,
133
173
} ;
134
174
135
175
#[ tokio:: test]
136
176
async fn test_wait_for_resource_usage ( ) {
137
- let mut child = tokio:: process:: Command :: new ( "sleep" )
138
- . arg ( "10" )
177
+ let mut command = tokio:: process:: Command :: new ( "sleep" ) ;
178
+ command. arg ( "10" ) ;
179
+ let mut child = command
139
180
. spawn_with_resource_limit ( ResourceLimit :: new (
140
181
Some ( Duration :: from_secs ( 1 ) ) ,
141
182
Some ( Duration :: from_secs_f64 ( 1.5 ) ) ,
0 commit comments