@@ -2,7 +2,7 @@ use std::collections::HashMap;
22use std:: ffi:: OsStr ;
33use std:: fs:: { self , File } ;
44use std:: io:: { BufRead , BufReader , Write } ;
5- use std:: path:: PathBuf ;
5+ use std:: path:: { Path , PathBuf } ;
66use std:: process;
77
88use regex:: Regex ;
@@ -17,8 +17,25 @@ pub struct Cgroup {
1717 tasks_files : Vec < PathBuf > ,
1818}
1919
20+ // This is called writeln_special because we have to use this rather convoluted way of writing
21+ // to avoid getting all sorts of weird errors. I would be nice to know why that happens.
22+ fn writeln_special < T , V > ( file_path : T , value : V ) -> Result < ( ) >
23+ where
24+ T : AsRef < Path > ,
25+ V : :: std:: fmt:: Display ,
26+ {
27+ // Open does not work here, or so it seemed at one point :-s
28+ let mut f = File :: create ( file_path. as_ref ( ) )
29+ . map_err ( |e| Error :: FileCreate ( PathBuf :: from ( file_path. as_ref ( ) ) , e) ) ?;
30+
31+ // For some reason, using writeln!(f, "{}", pid) doesn't work :(
32+ let mut bytes = format ! ( "{}\n " , value) . into_bytes ( ) ;
33+ f. write_all ( bytes. as_mut ( ) )
34+ . map_err ( |e| Error :: Write ( PathBuf :: from ( file_path. as_ref ( ) ) , e) )
35+ }
36+
2037impl Cgroup {
21- pub fn new ( id : & str , exec_file_name : & OsStr ) -> Result < Self > {
38+ pub fn new ( id : & str , numa_node : u32 , exec_file_name : & OsStr ) -> Result < Self > {
2239 let f =
2340 File :: open ( PROC_MOUNTS ) . map_err ( |e| Error :: FileOpen ( PathBuf :: from ( PROC_MOUNTS ) , e) ) ?;
2441
@@ -65,14 +82,21 @@ impl Cgroup {
6582 // We now both create the cgroup subfolders, and fill the tasks_files vector.
6683 let mut tasks_files = Vec :: with_capacity ( keys_len) ;
6784
68- for ( _controller , mut path_buf) in found_controllers. drain ( ) {
85+ for ( controller , mut path_buf) in found_controllers. drain ( ) {
6986 path_buf. push ( exec_file_name) ;
7087 path_buf. push ( id) ;
7188
7289 // Create the folders first. The cpuset.cpus and cpuset.mems files really do appear to
7390 // be inherited AND populated automatically :-s
7491 fs:: create_dir_all ( & path_buf) . map_err ( |e| Error :: CreateDir ( path_buf. clone ( ) , e) ) ?;
7592
93+ if controller == "cpuset" {
94+ // Enforce NUMA node restriction.
95+ path_buf. push ( "cpuset.mems" ) ;
96+ writeln_special ( & path_buf, numa_node) ?;
97+ path_buf. pop ( ) ;
98+ }
99+
76100 // And now add "tasks" to get the path of the corresponding tasks file.
77101 path_buf. push ( "tasks" ) ;
78102
@@ -87,15 +111,9 @@ impl Cgroup {
87111 // This writes the pid of the current process to each tasks file. These are special files that,
88112 // when written to, will assign the process associated with the pid to the respective cgroup.
89113 pub fn attach_pid ( & self ) -> Result < ( ) > {
114+ let pid = process:: id ( ) ;
90115 for tasks_file in & self . tasks_files {
91- // Open does not work here, or so it seemed at one point :-s
92- let mut f =
93- File :: create ( tasks_file) . map_err ( |e| Error :: FileCreate ( tasks_file. clone ( ) , e) ) ?;
94-
95- // For some reason, using write!("{}\n", pid) doesn't work :( I wonder why ...
96- let mut bytes = format ! ( "{}\n " , process:: id( ) ) . into_bytes ( ) ;
97- f. write_all ( bytes. as_mut ( ) )
98- . map_err ( |e| Error :: Write ( tasks_file. clone ( ) , e) ) ?;
116+ writeln_special ( tasks_file, pid) ?;
99117 }
100118 Ok ( ( ) )
101119 }
0 commit comments