5
5
#include <ctype.h>
6
6
#include <dirent.h>
7
7
#include <errno.h>
8
+ #include <limits.h>
8
9
#include <signal.h>
9
10
#include <stdio.h>
10
11
#include <stdlib.h>
11
12
#include <string.h>
13
+ #include <sys/syscall.h> /* Definition of SYS_* constants */
12
14
#include <time.h>
13
15
#include <unistd.h>
14
- #include <limits.h>
15
16
16
17
#include "globals.h"
17
18
#include "kill.h"
@@ -126,33 +127,59 @@ static void notify_process_killed(const poll_loop_args_t* args, const procinfo_t
126
127
}
127
128
}
128
129
130
+ int send_signal (int pidfd_or_negative_pgid , int sig )
131
+ {
132
+ if (pidfd_or_negative_pgid >= 0 ) {
133
+ return (int )syscall (SYS_pidfd_send_signal , pidfd_or_negative_pgid , sig , NULL , 0 );
134
+ } else {
135
+ return kill (pidfd_or_negative_pgid , sig );
136
+ }
137
+ }
138
+
129
139
/*
130
- * Send the selected signal to "pid" and wait for the process to exit
140
+ * Send the selected signal to `victim` and wait for it to exit
131
141
* (max 10 seconds)
132
142
*/
133
- int kill_wait (const poll_loop_args_t * args , pid_t pid , int sig )
143
+ int kill_wait (const poll_loop_args_t * args , const procinfo_t * victim , int sig )
134
144
{
135
145
if (args -> dryrun && sig != 0 ) {
136
146
warn ("dryrun, not actually sending any signal\n" );
137
147
return 0 ;
138
148
}
149
+ int pidfd_or_negative_pgid = victim -> pidfd ;
150
+ int pid_or_negative_pgid = victim -> pid ;
139
151
const unsigned poll_ms = 100 ;
140
152
if (args -> kill_process_group ) {
141
- int res = getpgid (pid );
153
+ int res = getpgid (victim -> pid );
142
154
if (res < 0 ) {
143
155
return res ;
144
156
}
145
- pid = - res ;
146
- warn ("killing whole process group %d (-g flag is active)\n" , res );
157
+ pidfd_or_negative_pgid = - res ;
158
+ pid_or_negative_pgid = - res ;
159
+ if (sig != 0 ) {
160
+ warn ("killing whole process group %d (-g flag is active)\n" , res );
161
+ }
147
162
}
148
- int res = kill ( pid , sig );
163
+ int res = send_signal ( pidfd_or_negative_pgid , sig );
149
164
if (res != 0 ) {
150
165
return res ;
151
166
}
152
167
/* signal 0 does not kill the process. Don't wait for it to exit */
153
168
if (sig == 0 ) {
154
169
return 0 ;
155
170
}
171
+
172
+ #ifdef __NR_process_mrelease
173
+ if (pidfd_or_negative_pgid >= 0 ) {
174
+ int res = (int )syscall (__NR_process_mrelease , pidfd_or_negative_pgid , 0 );
175
+ if (res != 0 ) {
176
+ warn ("process_mrelease pidfd=%d failed: %s\n" , pidfd_or_negative_pgid , strerror (errno ));
177
+ } else {
178
+ debug ("process_mrelease success\n" );
179
+ }
180
+ }
181
+ #endif
182
+
156
183
for (unsigned i = 0 ; i < 100 ; i ++ ) {
157
184
float secs = (float )(i * poll_ms ) / 1000 ;
158
185
// We have sent SIGTERM but now have dropped below SIGKILL limits.
@@ -162,7 +189,7 @@ int kill_wait(const poll_loop_args_t* args, pid_t pid, int sig)
162
189
print_mem_stats (debug , m );
163
190
if (m .MemAvailablePercent <= args -> mem_kill_percent && m .SwapFreePercent <= args -> swap_kill_percent ) {
164
191
sig = SIGKILL ;
165
- res = kill ( pid , sig );
192
+ res = send_signal ( pidfd_or_negative_pgid , sig );
166
193
// kill first, print after
167
194
warn ("escalating to SIGKILL after %.1f seconds\n" , secs );
168
195
if (res != 0 ) {
@@ -173,7 +200,7 @@ int kill_wait(const poll_loop_args_t* args, pid_t pid, int sig)
173
200
meminfo_t m = parse_meminfo ();
174
201
print_mem_stats (printf , m );
175
202
}
176
- if (!is_alive (pid )) {
203
+ if (!is_alive (pid_or_negative_pgid )) {
177
204
warn ("process exited after %.1f seconds\n" , secs );
178
205
return 0 ;
179
206
}
@@ -268,6 +295,15 @@ bool is_larger(const poll_loop_args_t* args, const procinfo_t* victim, procinfo_
268
295
}
269
296
cur -> uid = res ;
270
297
}
298
+ {
299
+ int res = (int )syscall (SYS_pidfd_open , cur -> pid , 0 );
300
+ if (res < 0 ) {
301
+ // can happen if process has already exited
302
+ debug ("pid %d: error opening pidfd: %s\n" , cur -> pid , strerror (errno ));
303
+ return false;
304
+ }
305
+ cur -> pidfd = res ;
306
+ }
271
307
return true;
272
308
}
273
309
@@ -296,7 +332,10 @@ procinfo_t find_largest_process(const poll_loop_args_t* args)
296
332
clock_gettime (CLOCK_MONOTONIC , & t0 );
297
333
}
298
334
299
- procinfo_t victim = { 0 };
335
+ procinfo_t victim = {
336
+ .pidfd = -1 ,
337
+ /* omitted fields are set to zero */
338
+ };
300
339
while (1 ) {
301
340
errno = 0 ;
302
341
struct dirent * d = readdir (procdir );
@@ -313,6 +352,7 @@ procinfo_t find_largest_process(const poll_loop_args_t* args)
313
352
314
353
procinfo_t cur = {
315
354
.pid = (int )strtol (d -> d_name , NULL , 10 ),
355
+ .pidfd = -1 ,
316
356
.uid = -1 ,
317
357
.badness = -1 ,
318
358
.VmRSSkiB = -1 ,
@@ -326,6 +366,12 @@ procinfo_t find_largest_process(const poll_loop_args_t* args)
326
366
327
367
if (larger ) {
328
368
debug (" <--- new victim\n" );
369
+ if (victim .pidfd >= 0 ) {
370
+ int res = close (victim .pidfd );
371
+ if (res != 0 ) {
372
+ warn ("%s: pid %d: error closing pidfd %d: %s\n" , __func__ , victim .pid , victim .pidfd , strerror (errno ));
373
+ }
374
+ }
329
375
victim = cur ;
330
376
} else {
331
377
debug ("\n" );
@@ -353,7 +399,7 @@ procinfo_t find_largest_process(const poll_loop_args_t* args)
353
399
* Kill the victim process, wait for it to exit, send a gui notification
354
400
* (if enabled).
355
401
*/
356
- void kill_process (const poll_loop_args_t * args , int sig , const procinfo_t * victim )
402
+ void kill_process (const poll_loop_args_t * args , int sig , procinfo_t * victim )
357
403
{
358
404
if (victim -> pid <= 0 ) {
359
405
warn ("Could not find a process to kill. Sleeping 1 second.\n" );
@@ -378,9 +424,17 @@ void kill_process(const poll_loop_args_t* args, int sig, const procinfo_t* victi
378
424
sig_name , victim -> pid , victim -> uid , victim -> name , victim -> badness , victim -> VmRSSkiB / 1024 );
379
425
}
380
426
381
- int res = kill_wait (args , victim -> pid , sig );
427
+ int res = kill_wait (args , victim , sig );
382
428
int saved_errno = errno ;
383
429
430
+ if (victim -> pidfd >= 0 ) {
431
+ int res = close (victim -> pidfd );
432
+ if (res != 0 ) {
433
+ warn ("%s: pid %d: error closing pidfd %d: %s\n" , __func__ , victim -> pid , victim -> pidfd , strerror (errno ));
434
+ }
435
+ victim -> pidfd = -1 ;
436
+ }
437
+
384
438
// Send the GUI notification AFTER killing a process. This makes it more likely
385
439
// that there is enough memory to spawn the notification helper.
386
440
if (sig != 0 ) {
0 commit comments