1
1
//! Configure the process resource limits.
2
2
use cfg_if:: cfg_if;
3
+ use libc:: { c_int, c_long, rusage} ;
3
4
4
5
use crate :: errno:: Errno ;
6
+ use crate :: sys:: time:: TimeVal ;
5
7
use crate :: Result ;
6
8
pub use libc:: rlim_t;
7
9
use std:: mem;
@@ -19,7 +21,7 @@ cfg_if! {
19
21
target_os = "dragonfly" ,
20
22
all( target_os = "linux" , not( target_env = "gnu" ) )
21
23
) ) ] {
22
- use libc:: { c_int , rlimit} ;
24
+ use libc:: rlimit;
23
25
}
24
26
}
25
27
@@ -242,11 +244,7 @@ pub fn getrlimit(resource: Resource) -> Result<(rlim_t, rlim_t)> {
242
244
/// [`Resource`]: enum.Resource.html
243
245
///
244
246
/// Note: `setrlimit` provides a safe wrapper to libc's `setrlimit`.
245
- pub fn setrlimit (
246
- resource : Resource ,
247
- soft_limit : rlim_t ,
248
- hard_limit : rlim_t ,
249
- ) -> Result < ( ) > {
247
+ pub fn setrlimit ( resource : Resource , soft_limit : rlim_t , hard_limit : rlim_t ) -> Result < ( ) > {
250
248
let new_rlim = rlimit {
251
249
rlim_cur : soft_limit,
252
250
rlim_max : hard_limit,
@@ -261,3 +259,179 @@ pub fn setrlimit(
261
259
262
260
Errno :: result ( res) . map ( drop)
263
261
}
262
+
263
+ libc_enum ! {
264
+ /// Whose resource usage should be returned by [`getrusage`].
265
+ #[ repr( i32 ) ]
266
+ #[ non_exhaustive]
267
+ pub enum UsageWho {
268
+ /// Resource usage for the current process.
269
+ RUSAGE_SELF ,
270
+
271
+ /// Resource usage for all the children that have terminated and been waited for.
272
+ RUSAGE_CHILDREN ,
273
+
274
+ #[ cfg( any( target_os = "linux" , target_os = "freebsd" , target_os = "openbsd" ) ) ]
275
+ #[ cfg_attr( docsrs, doc( cfg( all( ) ) ) ) ]
276
+ /// Resource usage for the calling thread.
277
+ RUSAGE_THREAD ,
278
+ }
279
+ }
280
+
281
+ /// Output of `getrusage` with information about resource usage. Some of the fields
282
+ /// may be unused in some platforms, and will be always zeroed out. See their manuals
283
+ /// for details.
284
+ #[ repr( transparent) ]
285
+ #[ derive( Clone , Copy , Debug , Eq , Hash , PartialEq ) ]
286
+ pub struct Usage ( rusage ) ;
287
+
288
+ impl AsRef < rusage > for Usage {
289
+ fn as_ref ( & self ) -> & rusage {
290
+ & self . 0
291
+ }
292
+ }
293
+
294
+ impl AsMut < rusage > for Usage {
295
+ fn as_mut ( & mut self ) -> & mut rusage {
296
+ & mut self . 0
297
+ }
298
+ }
299
+
300
+ impl Usage {
301
+ /// Total amount of time spent executing in user mode.
302
+ pub fn user_time ( & self ) -> TimeVal {
303
+ TimeVal :: from ( self . 0 . ru_utime )
304
+ }
305
+
306
+ /// Total amount of time spent executing in kernel mode.
307
+ pub fn system_time ( & self ) -> TimeVal {
308
+ TimeVal :: from ( self . 0 . ru_stime )
309
+ }
310
+
311
+ /// The resident set size at its peak, in kilobytes.
312
+ pub fn max_rss ( & self ) -> c_long {
313
+ self . 0 . ru_maxrss
314
+ }
315
+
316
+ /// Integral value expressed in kilobytes times ticks of execution indicating
317
+ /// the amount of text memory shared with other processes.
318
+ pub fn shared_integral ( & self ) -> c_long {
319
+ self . 0 . ru_ixrss
320
+ }
321
+
322
+ /// Integral value expressed in kilobytes times ticks of execution indicating
323
+ /// the amount of unshared memory used by data.
324
+ pub fn unshared_data_integral ( & self ) -> c_long {
325
+ self . 0 . ru_idrss
326
+ }
327
+
328
+ /// Integral value expressed in kilobytes times ticks of execution indicating
329
+ /// the amount of unshared memory used for stack space.
330
+ pub fn unshared_stack_integral ( & self ) -> c_long {
331
+ self . 0 . ru_isrss
332
+ }
333
+
334
+ /// Number of page faults that were served without resorting to I/O, with pages
335
+ /// that have been allocated previously by the kernel.
336
+ pub fn minor_page_faults ( & self ) -> c_long {
337
+ self . 0 . ru_minflt
338
+ }
339
+
340
+ /// Number of page faults that were served through I/O (i.e. swap).
341
+ pub fn major_page_faults ( & self ) -> c_long {
342
+ self . 0 . ru_majflt
343
+ }
344
+
345
+ /// Number of times all of the memory was fully swapped out.
346
+ pub fn full_swaps ( & self ) -> c_long {
347
+ self . 0 . ru_nswap
348
+ }
349
+
350
+ /// Number of times a read was done from a block device.
351
+ pub fn block_reads ( & self ) -> c_long {
352
+ self . 0 . ru_inblock
353
+ }
354
+
355
+ /// Number of times a write was done to a block device.
356
+ pub fn block_writes ( & self ) -> c_long {
357
+ self . 0 . ru_oublock
358
+ }
359
+
360
+ /// Number of IPC messages sent.
361
+ pub fn ipc_sends ( & self ) -> c_long {
362
+ self . 0 . ru_msgsnd
363
+ }
364
+
365
+ /// Number of IPC messages received.
366
+ pub fn ipc_receives ( & self ) -> c_long {
367
+ self . 0 . ru_msgrcv
368
+ }
369
+
370
+ /// Number of signals received.
371
+ pub fn signals ( & self ) -> c_long {
372
+ self . 0 . ru_nsignals
373
+ }
374
+
375
+ /// Number of times a context switch was voluntarily invoked.
376
+ pub fn voluntary_context_switches ( & self ) -> c_long {
377
+ self . 0 . ru_nvcsw
378
+ }
379
+
380
+ /// Number of times a context switch was imposed by the kernel (usually due to
381
+ /// time slice expiring or preemption by a higher priority process).
382
+ pub fn involuntary_context_switches ( & self ) -> c_long {
383
+ self . 0 . ru_nivcsw
384
+ }
385
+ }
386
+
387
+ /// Get usage information for a process, its children or the current thread
388
+ ///
389
+ /// Real time information can be obtained for either the current process or (in some
390
+ /// systems) thread, but information about children processes is only provided for
391
+ /// those that have terminated and been waited for (see [`super::wait::wait`]).
392
+ ///
393
+ /// Some information may be missing depending on the platform, and the way information
394
+ /// is provided for children may also vary. Check the manuals for details.
395
+ ///
396
+ /// # References
397
+ ///
398
+ /// * [getrusage(2)](https://pubs.opengroup.org/onlinepubs/009696699/functions/getrusage.html)
399
+ /// * [Linux](https://man7.org/linux/man-pages/man2/getrusage.2.html)
400
+ /// * [FreeBSD](https://www.freebsd.org/cgi/man.cgi?query=getrusage)
401
+ /// * [NetBSD](https://man.netbsd.org/getrusage.2)
402
+ /// * [MacOS](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getrusage.2.html)
403
+ ///
404
+ /// [`UsageWho`]: enum.UsageWho.html
405
+ ///
406
+ /// Note: `getrusage` provides a safe wrapper to libc's [`libc::getrusage`].
407
+ pub fn getrusage ( who : UsageWho ) -> Result < Usage > {
408
+ unsafe {
409
+ let mut rusage = mem:: MaybeUninit :: < rusage > :: uninit ( ) ;
410
+ let res = libc:: getrusage ( who as c_int , rusage. as_mut_ptr ( ) ) ;
411
+ Errno :: result ( res) . map ( |_| Usage ( rusage. assume_init ( ) ) )
412
+ }
413
+ }
414
+
415
+ #[ cfg( test) ]
416
+ mod test {
417
+ use super :: { getrusage, UsageWho } ;
418
+
419
+ #[ test]
420
+ pub fn test_self_cpu_time ( ) {
421
+ // Make sure some CPU time is used.
422
+ let mut numbers: Vec < i32 > = ( 1 ..1_000_000 ) . collect ( ) ;
423
+ numbers. iter_mut ( ) . for_each ( |item| * item *= 2 ) ;
424
+
425
+ // FIXME: this is here to help ensure the compiler does not optimize the whole
426
+ // thing away. Replace the assert with test::black_box once stabilized.
427
+ assert_eq ! ( numbers[ 100 ..200 ] . iter( ) . sum:: <i32 >( ) , 30_100 ) ;
428
+
429
+ let usage = getrusage ( UsageWho :: RUSAGE_SELF ) . expect ( "Failed to call getrusage for SELF" ) ;
430
+ let rusage = usage. as_ref ( ) ;
431
+
432
+ let user = usage. user_time ( ) ;
433
+ assert ! ( user. tv_sec( ) > 0 || user. tv_usec( ) > 0 ) ;
434
+ assert_eq ! ( user. tv_sec( ) , rusage. ru_utime. tv_sec) ;
435
+ assert_eq ! ( user. tv_usec( ) , rusage. ru_utime. tv_usec) ;
436
+ }
437
+ }
0 commit comments