57

I was wondering if there is a way to freeze any process for a certain amount of time?

What I mean is that: is it possible for one application (probably running as root) to pause the execution of another already running process (any process, both GUI and command line) and then resume it later? In other words I don't want certain processes to be scheduled by the linux scheduler for a certain amount of time.

0

3 Answers 3

90

See here

There are two signals that can suspend the execution of a process. One is "graceful", and one is "forceful".

The "graceful" one is SIGTSTP, and its purpose is to "nicely" ask the process, if it feels like it, to please suspend execution until it receives a SIGCONT. In the case of SIGTSTP, the process can ignore SIGTSTP and continue executing anyway, so this requires cooperation from a program that is designed to handle SIGTSTP.

The "forceful" one is SIGSTOP, and its purpose is to suspend all userspace threads associated with that process. It is just as impossible for the process to ignore SIGSTOP as it is for it to ignore SIGKILL (the latter kills the process forcefully).

To send an arbitrary signal, including any of the ones mentioned here, you can use programs such as kill, killall, or pkill; or use the system call kill(2). See your operating system's manpages for platform/architecture/version-dependent details and errata regarding any of the above. Note that the word "kill" in all of these commands and the syscall is a bad misnomer. These commands are not designed, exclusively, to terminate processes. They can do that by sending certain ones of the signals; but signals can also be used for functionality other than terminating a process. For example, SIGSTOP only suspends the process, and it's just one of several signals that can be sent this way.

To add a condition of automatically resuming the process after a period of time has elapsed, you will need to use some sort of monitoring process that remains running and sets a timer in order to wake up the monitoring process, which then in turn calls kill(2) again and sends the SIGCONT signal to the stopped process, in order to request the kernel to resume execution. Note that Linux has several timing mechanisms with various degrees of accuracy and precision; furthermore, if your system is very busy, your monitoring process might not get woken up until well after its timer has expired, and thus the wakeup might be delayed.

If you depend on very accurate precision of suspension and resumption of the suspended process, you may need to run your monitoring program with real-time permissions (see this manpage on sched_setscheduler(2) for information about making your process real-time). You can also use High-Resolution Timers, a feature of the Linux kernel (which is only available if your hardware provides support for them), in combination with real-time scheduling, to get very accurate, sub-millisecond precision on timing, then wakeup and send the signal to resume the monitored process very quickly.

You didn't indicate which technologies you are willing to use to implement this. At a bare minimum, you'll need at least bash scripting, although you won't be able to get very fine-grained timing that way. Here is a bash "script" (untested, so please be careful) that is just a proof of concept of your query. If you need precise timing, you'll have to write a program, probably in C/C++ or another native language, and use real-time scheduling and hrtimers.

#!/bin/bash
#This is the process you want to suspend.
screen -mdS child bash -c "cat /dev/urandom | base64"
#This is the process ID of the child process
THEPID=$(screen -list | grep child | cut -f1 -d'.' | sed 's/\W//g')
#Send SIGSTOP to the child process.
kill -SIGSTOP ${THEPID}
#Now it is suspended. This process will sleep for 10 seconds asynchronously, then resume the process.
screen -mdS monitor bash -c "sleep 10; kill -SIGCONT ${THEPID}"

Note that the script will end and the controlling script will terminate, but due to screen controlling the monitor process, it will continue running in the background for 10 seconds (based on the argument passed to sleep) and then wake up and continue the child process. But this will be long after the controlling script has ended. If you want to synchronously wait for the time to elapse, just omit the second call to screen and hard-code the sleep and kill into the controlling script.

You can test that the process does in fact suspend by running

screen -rS child

after you start this script. You won't see anything on the console. Then after the timer expires (10 seconds), it will flood your screen with base64 data (random characters from 0-9 and A-F). Press Ctrl+C to exit.

5
  • Very good very complete answer including PoC bash snippet. Nice!
    – fgysin
    Mar 31, 2016 at 8:26
  • If a process gets frozen in the middle of a network session like a TCP connection, when it gets continued, could that network session be corrupted or drop? Is there a defined behaviour for this? Apr 1, 2016 at 11:00
  • 1
    @cmcdragonkai because as stopped process in not running, it can't read from or write to any fd, but the kernel keeps transferring bytes till its buffer is full in a TCP session, i.e. no transfer between kernel space and user space. freezing processes is different check https://www.kernel.org/doc/Documentation/power/freezing-of-tasks.txt Jan 2, 2017 at 17:03
  • I have found that TCP connections can continue after bringing the process back to the foreground (timeouts are application specific, there's TCP keepalive but also application-level keepalive). Freezing processes, seems to mean when the computer is in hibernation or sleep mode. Is that right? Jan 3, 2017 at 9:03
  • This script does no effect on non-cooperative codes: gist.github.com/ceremcem/864dd94b52ffe7b18da29558df4f1f5b
    – ceremcem
    May 1, 2017 at 13:37
19

Yes, you can do that by sending a STOP signal to a process to suspend it and then a CONT to continue.

usage:

kill -STOP <pid>

kill -CONT <pid>
12

If you have a suitably loose definition of "freeze" you might check out the renice command.

Renice allows you to alter the scheduling priority of running processes.

The normal process nice value is 0. Increasing the nice value makes the process nicer, as in "why don't you go first". While decreasing the nice value makes a process less nice, as in "get out of my way, I'm in a hurry". The nice value range is -20 to 19.

Anyone can make their own processes nicer. Only root can make a process less nice or change another users processes niceness.

If you set a processes nice value to 19 it will only run when nothing else on the system wants to.

Here is an example run on my local linux box.

Use ps -l and look at the NI column to see a processes nice value.

-> ps -l
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY     CMD
0 S 29190   402 31146  0  75   0 - 16547 wait   pts/0   bash
0 T 29190  1105   402  0  75   0 - 23980 finish pts/0   vim
0 R 29190   794   402  0  76   0 - 15874 -      pts/0   ps

Running renice +10 on the vim process causes it to run at a lower priority.

-> renice +10 -p 1105
1105: old priority 0, new priority 10

-> ps -l
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY    CMD
0 S 29190   402 31146  0  76   0 - 16547 wait   pts/0  bash
0 T 29190  1105   402  0  95  10 - 23980 finish pts/0  vim
0 R 29190  1998   402  0  78   0 - 15874 -      pts/0  ps

Assuming that you can stretch "freeze" to mean "not bother anyone else on the system" you could scriptify something like:

renice 20 -p <pid of interest>
sleep <certain amount of time>
renice 0 -p <pid of interest>

(remember to run it as root).


note that I took some liberties with the above ps -l output to get the interesting columns to show up nicely in the little blue boxes :)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .