]> git.proxmox.com Git - pve-common.git/blame - src/PVE/CpuSet.pm
fix #1819: fork_worker: ensure sync'ed workers control terminal
[pve-common.git] / src / PVE / CpuSet.pm
CommitLineData
a1c3f18e
DM
1package PVE::CpuSet;
2
3use strict;
4use warnings;
5use PVE::Tools;
ae97d553 6use PVE::ProcFSTools;
a1c3f18e 7
a1c3f18e
DM
8sub new {
9 my ($this) = @_;
10
11 my $class = ref($this) || $this;
12
13 my $self = bless { members => {} }, $class;
3f76daba 14
a1c3f18e
DM
15 return $self;
16}
17
18sub new_from_cgroup {
19 my ($this, $cgroup, $kind) = @_;
20
21 $kind //= 'cpus';
22
23 my $filename = "/sys/fs/cgroup/cpuset/$cgroup/cpuset.$kind";
24 my $set_text = PVE::Tools::file_read_firstline($filename) // '';
25
26 my $cpuset = $this->new();
27
28 my $members = $cpuset->{members};
29
30 my $count = 0;
31
32 foreach my $part (split(/,/, $set_text)) {
33 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
34 my ($from, $to) = ($1, $2);
35 $to //= $1;
a1c3f18e
DM
36 die "invalid range: $part ($to < $from)\n" if $to < $from;
37 for (my $i = $from; $i <= $to; $i++) {
38 $members->{$i} = 1;
39 $count++;
40 };
41 } else {
42 die "invalid range: $part\n";
43 }
44 }
45
46 die "got empty cpuset for cgroup '$cgroup'\n"
47 if !$count;
48
49 return $cpuset;
50}
51
52sub write_to_cgroup {
53 my ($self, $cgroup) = @_;
54
55 my $filename = "/sys/fs/cgroup/cpuset/$cgroup/cpuset.cpus";
56
57 my $value = '';
58 my @members = $self->members();
59 foreach my $cpuid (@members) {
60 $value .= ',' if length($value);
61 $value .= $cpuid;
62 }
63
64 die "unable to write empty cpu set\n" if !length($value);
65
66 open(my $fh, '>', $filename) || die "failed to open '$filename' - $!\n";
67 PVE::Tools::safe_print($filename, $fh, "$value\n");
dbfaa2b8 68 close($fh) || die "failed to close '$filename' - $!\n";
a1c3f18e
DM
69}
70
71sub insert {
72 my ($self, @members) = @_;
73
74 my $count = 0;
75
76 foreach my $cpu (@members) {
a1c3f18e
DM
77 next if $self->{members}->{$cpu};
78 $self->{members}->{$cpu} = 1;
79 $count++;
80 }
81
82 return $count;
83}
84
85sub delete {
86 my ($self, @members) = @_;
87
88 my $count = 0;
89
90 foreach my $cpu (@members) {
a1c3f18e
DM
91 next if !$self->{members}->{$cpu};
92 delete $self->{members}->{$cpu};
93 $count++;
94 }
95
96 return $count;
97}
98
99sub has {
100 my ($self, $cpuid) = @_;
101
102 return $self->{members}->{$cpuid};
103}
104
105# members: this list is always sorted!
106sub members {
107 my ($self) = @_;
108
1cffb285 109 return sort { $a <=> $b } keys %{$self->{members}};
a1c3f18e
DM
110}
111
112sub size {
113 my ($self) = @_;
114
115 return scalar(keys %{$self->{members}});
116}
117
118sub is_equal {
119 my ($self, $set2) = @_;
120
121 my $members1 = $self->{members};
122 my $members2 = $set2->{members};
123
124 foreach my $id (keys %$members1) {
125 return 0 if !$members2->{$id};
126 }
127 foreach my $id (keys %$members2) {
128 return 0 if !$members1->{$id};
129 }
130
131 return 1;
132}
133
284dca70
DM
134sub short_string {
135 my ($self) = @_;
136
137 my @members = $self->members();
138
139 my $res = '';
140 my ($last, $next);
141 foreach my $cpu (@members) {
142 if (!defined($last)) {
143 $last = $next = $cpu;
144 } elsif (($next + 1) == $cpu) {
145 $next = $cpu;
146 } else {
147 $res .= ',' if length($res);
74116083
DM
148 if ($last != $next) {
149 $res .= "$last-$next";
150 } else {
151 $res .= "$last";
152 }
9c07db40 153 $last = $next = $cpu;
284dca70
DM
154 }
155 }
156
157 if (defined($last)) {
158 $res .= ',' if length($res);
159 if ($last != $next) {
160 $res .= "$last-$next";
161 } else {
162 $res .= "$last";
163 }
164 }
165
166 return $res;
167}
168
a1c3f18e 1691;