Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SetPriorityClass equivalent on Linux

I have a daemon-like application that does some disk-intensive processing at initialization. To avoid slowing down other tasks I do something like this on Windows:

SetPriorityClass(GetCurrentProcess(), PROCESS_MODE_BACKGROUND_BEGIN);

// initialization tasks

SetPriorityClass(GetCurrentProcess(), PROCESS_MODE_BACKGROUND_END);

// daemon is ready and running at normal priority

AFAIK, on Unices I can call nice or setpriority and lower the process priority but I can't raise it back to what it was at process creation (i.e. there's no equivalent to the second SetPriorityClass invocation) unless I have superuser privileges. Is there by any chance another way of doing it that I'm missing? (I know I can create an initialization thread that runs at low priority and wait for it to complete on the main thread, but I'd rather prefer avoiding it)

edit: Bonus points for the equivalent SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN); and SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_END);

like image 274
CAFxX Avatar asked Dec 01 '25 14:12

CAFxX


1 Answers

You've said that your processing is disk intensive, so solutions using nice won't work. nice handles the priority of CPU access, not I/O access. PROCESS_MODE_BACKGROUND_BEGIN lowers I/O priority as well as CPU priority, and requires kernel features that don't exist in XP and older.

Controlling I/O priority is not portable across Unices, but there is a solution on modern Linux kernels. You'll need CAP_SYS_ADMIN to lower I/O priority to IO_PRIO_CLASS_IDLE, but it is possible to lower and raise priority within the best effort class without this.

The key function call is ioprio_set, which you'll have to call via a syscall wrapper:

static int ioprio_set(int which, int who, int ioprio)
{
    return syscall(SYS_ioprio_set, which, who, ioprio);
}

For full example source, see here.

Depending on permissions, your entry to background mode is either IOPRIO_PRIO_VALUE(IO_PRIO_CLASS_IDLE,0) or IOPRIO_PRIO_VALUE(IO_PRIO_CLASS_BE,7). The sequence should then be:

#define IOPRIO_PRIO_VALUE(class, data)  (((class) << IOPRIO_CLASS_SHIFT) | data)

ioprio_set(IOPRIO_WHO_PROCESS, 0, IOPRIO_PRIO_VALUE(IO_PRIO_CLASS_BE,7));
// Do work
ioprio_set(IOPRIO_WHO_PROCESS, 0, IOPRIO_PRIO_VALUE(IO_PRIO_CLASS_BE,4));

Note that you many not have permission to return to your original io priority, so you'll need to return to another best effort value.

like image 69
Adrian Cox Avatar answered Dec 04 '25 22:12

Adrian Cox



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!