1
1
from asyncio import get_event_loop , shield , sleep , wait_for , TimeoutError
2
2
from itertools import chain
3
- from os import access , cpu_count , geteuid , kill , makedirs , path , rmdir , W_OK
3
+ from os import access , cpu_count , geteuid , getpid , kill , makedirs , path , rmdir , W_OK
4
4
from signal import SIGKILL
5
5
from socket import socket , AF_UNIX , SOCK_STREAM , SOL_SOCKET , SO_PEERCRED
6
6
from subprocess import call
10
10
from jd4 .log import logger
11
11
from jd4 .util import read_text_file , write_text_file
12
12
13
- CPUACCT_CGROUP_ROOT = '/sys/fs/cgroup/cpuacct/jd4'
14
- MEMORY_CGROUP_ROOT = '/sys/fs/cgroup/memory/jd4'
15
- PIDS_CGROUP_ROOT = '/sys/fs/cgroup/pids/jd4'
13
+ CGROUP2_ROOT = '/sys/fs/cgroup/jd4'
14
+ CGROUP2_DAEMON_ROOT = path .join (CGROUP2_ROOT , 'daemon' )
16
15
WAIT_JITTER_NS = 5000000
17
16
18
17
def try_init_cgroup ():
19
18
euid = geteuid ()
20
- cgroups_to_init = list ()
21
- if not (path .isdir (CPUACCT_CGROUP_ROOT ) and access (CPUACCT_CGROUP_ROOT , W_OK )):
22
- cgroups_to_init .append (CPUACCT_CGROUP_ROOT )
23
- if not (path .isdir (MEMORY_CGROUP_ROOT ) and access (MEMORY_CGROUP_ROOT , W_OK )):
24
- cgroups_to_init .append (MEMORY_CGROUP_ROOT )
25
- if not (path .isdir (PIDS_CGROUP_ROOT ) and access (PIDS_CGROUP_ROOT , W_OK )):
26
- cgroups_to_init .append (PIDS_CGROUP_ROOT )
27
- if cgroups_to_init :
19
+ if not (path .isdir (CGROUP2_ROOT ) and access (CGROUP2_ROOT , W_OK )):
20
+ cgroup2_subtree_control = path .join (CGROUP2_ROOT , 'cgroup.subtree_control' )
28
21
if euid == 0 :
29
- logger .info ('Initializing cgroup: %s' , ', ' .join (cgroups_to_init ))
30
- for cgroup_to_init in cgroups_to_init :
31
- makedirs (cgroup_to_init , exist_ok = True )
22
+ logger .info ('Initializing cgroup: %s' , CGROUP2_ROOT )
23
+ write_text_file ('/sys/fs/cgroup/cgroup.subtree_control' , '+cpu +memory +pids' )
24
+ makedirs (CGROUP2_ROOT , exist_ok = True )
25
+ write_text_file (cgroup2_subtree_control , '+cpu +memory +pids' )
26
+ makedirs (CGROUP2_DAEMON_ROOT , exist_ok = True )
32
27
elif __stdin__ .isatty ():
33
- logger .info ('Initializing cgroup: %s' , ', ' .join (cgroups_to_init ))
34
- call (['sudo' , 'sh' , '-c' , 'mkdir -p "{1}" && chown -R "{0}" "{1}"' .format (
35
- euid , '" "' .join (cgroups_to_init ))])
28
+ logger .info ('Initializing cgroup: %s' , CGROUP2_ROOT )
29
+ call (['sudo' , 'sh' , '-c' ,
30
+ '''echo "+cpu +memory +pids" > "/sys/fs/cgroup/cgroup.subtree_control" &&
31
+ mkdir -p "{1}" &&
32
+ chown -R "{0}" "{1}" &&
33
+ echo "+cpu +memory +pids" > "{2}" &&
34
+ mkdir -p "{3}" &&
35
+ chown -R "{0}" "{3}"''' .format (
36
+ euid , CGROUP2_ROOT , cgroup2_subtree_control , CGROUP2_DAEMON_ROOT )])
36
37
else :
37
38
logger .error ('Cgroup not initialized' )
38
39
40
+ # Put myself into the cgroup that I can write.
41
+ pid = getpid ()
42
+ cgroup2_daemon_procs = path .join (CGROUP2_DAEMON_ROOT , 'cgroup.procs' )
43
+ if euid == 0 :
44
+ logger .info ('Entering cgroup: %s' , CGROUP2_DAEMON_ROOT )
45
+ write_text_file (cgroup2_daemon_procs , str (pid ))
46
+ elif __stdin__ .isatty ():
47
+ logger .info ('Entering cgroup: %s' , CGROUP2_DAEMON_ROOT )
48
+ call (['sudo' , 'sh' , '-c' , 'echo "{0}" > "{1}"' .format (pid , cgroup2_daemon_procs )])
49
+ else :
50
+ logger .error ('Cgroup not entered' )
51
+
39
52
class CGroup :
40
53
def __init__ (self ):
41
- self .cpuacct_cgroup_dir = mkdtemp (prefix = '' , dir = CPUACCT_CGROUP_ROOT )
42
- self .memory_cgroup_dir = mkdtemp (prefix = '' , dir = MEMORY_CGROUP_ROOT )
43
- self .pids_cgroup_dir = mkdtemp (prefix = '' , dir = PIDS_CGROUP_ROOT )
54
+ self .cgroup2_dir = mkdtemp (prefix = '' , dir = CGROUP2_ROOT )
44
55
45
56
def close (self ):
46
- rmdir (self .cpuacct_cgroup_dir )
47
- rmdir (self .memory_cgroup_dir )
48
- rmdir (self .pids_cgroup_dir )
57
+ rmdir (self .cgroup2_dir )
49
58
50
59
async def accept (self , sock ):
51
60
loop = get_event_loop ()
52
61
accept_sock , _ = await loop .sock_accept (sock )
53
62
pid = accept_sock .getsockopt (SOL_SOCKET , SO_PEERCRED )
54
- write_text_file (path .join (self .cpuacct_cgroup_dir , 'tasks' ), str (pid ))
55
- write_text_file (path .join (self .memory_cgroup_dir , 'tasks' ), str (pid ))
56
- write_text_file (path .join (self .pids_cgroup_dir , 'tasks' ), str (pid ))
63
+ write_text_file (path .join (self .cgroup2_dir , 'cgroup.procs' ), str (pid ))
57
64
accept_sock .close ()
58
65
59
66
@property
60
67
def procs (self ):
61
- return set (chain (
62
- map (int , read_text_file (path .join (self .cpuacct_cgroup_dir , 'cgroup.procs' )).splitlines ()),
63
- map (int , read_text_file (path .join (self .memory_cgroup_dir , 'cgroup.procs' )).splitlines ()),
64
- map (int , read_text_file (path .join (self .pids_cgroup_dir , 'cgroup.procs' )).splitlines ())))
68
+ return set (map (int ,
69
+ read_text_file (path .join (self .cgroup2_dir , 'cgroup.procs' )).splitlines ()))
65
70
66
71
def kill (self ):
67
72
procs = self .procs
@@ -77,27 +82,28 @@ def kill(self):
77
82
78
83
@property
79
84
def cpu_usage_ns (self ):
80
- return int (read_text_file (path .join (self .cpuacct_cgroup_dir , 'cpuacct.usage' )))
85
+ return 1000 * int (read_text_file (path .join (self .cgroup2_dir , 'cpu.stat' ))
86
+ .splitlines ()[0 ].split ()[1 ])
81
87
82
88
@property
83
89
def memory_limit_bytes (self ):
84
- return int (read_text_file (path .join (self .memory_cgroup_dir , 'memory.limit_in_bytes ' )))
90
+ return int (read_text_file (path .join (self .cgroup2_dir , 'memory.max ' )))
85
91
86
92
@memory_limit_bytes .setter
87
93
def memory_limit_bytes (self , value ):
88
- write_text_file (path .join (self .memory_cgroup_dir , 'memory.limit_in_bytes ' ), str (value ))
94
+ write_text_file (path .join (self .cgroup2_dir , 'memory.max ' ), str (value ))
89
95
90
96
@property
91
97
def memory_usage_bytes (self ):
92
- return int (read_text_file (path .join (self .memory_cgroup_dir , 'memory.max_usage_in_bytes ' )))
98
+ return int (read_text_file (path .join (self .cgroup2_dir , 'memory.peak ' )))
93
99
94
100
@property
95
101
def pids_max (self ):
96
- return int (read_text_file (path .join (self .pids_cgroup_dir , 'pids.max' )))
102
+ return int (read_text_file (path .join (self .cgroup2_dir , 'pids.max' )))
97
103
98
104
@pids_max .setter
99
105
def pids_max (self , value ):
100
- write_text_file (path .join (self .pids_cgroup_dir , 'pids.max' ), str (value ))
106
+ write_text_file (path .join (self .cgroup2_dir , 'pids.max' ), str (value ))
101
107
102
108
def enter_cgroup (socket_path ):
103
109
with socket (AF_UNIX , SOCK_STREAM ) as sock :
0 commit comments