Click here to Skip to main content
15,868,043 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I'm porting a C++ program that runs on Windows to WSL/Ubuntu. It's multithreaded, and all application threads run at the same priority. However, one thread needs to run at priority+1, and another at priority+2. Round-robin scheduling is also desirable, as is running the entire process at a slightly higher priority than the default.

The Linux target uses POSIX threads, but trying to do the above fails. First, setting the process' priority returns -1 with errno set to EACCES (permission denied):
C++
auto err = setpriority(PRIO_PROCESS, 0, -1);
if(err != 0)
{
   ReportError(SysThread_ConfigureProcess, "setpriority", errno);  // EACCES
}
Later, pthread_create returns EINVAL (invalid attributes) when SCHED_RR is set as the scheduling algorithm. If that code is commented out, the thread gets created:
C++
auto err = pthread_attr_setinheritsched(&attrs, PTHREAD_EXPLICIT_SCHED);
if(err != 0)
{
   return ReportError(SysThread_Create, "setinheritsched", err);
}

err = pthread_attr_setschedpolicy(&attrs, SCHED_RR);  // causes trouble
if(err != 0)
{
   return ReportError(SysThread_Create, "setschedpolicy", err);
}

pthread_t thread;

err = pthread_create(&thread, &attrs, EnterThread, (void*) client);
if(err != 0)
{
   return ReportError(SysThread_Create, "create", err);  // EINVAL
}
Finally, setting a thread's priority returns EPERM (not permitted):
C++
auto err = pthread_setschedprio((pthread_t) nthread_, PriorityMap[prio]);
if(err != 0)
{
   ReportError(SysThread_SetPriority, "setschedprio", err);  // EPERM
}
Does anyone know how to do this sort of thing on WSL/Ubuntu?

What I have tried:

I found a post which said you had to give your program the necessary privileges:
sudo setcap cap_sys_nice=+ep <path-to-object-file>
I know next to nothing about arcane Ubuntu commands. But "nice" is actually used to describe Linux priorities, and Ubuntu accepts the command. But then, when I tell VS2022 to Debug the program, it fails with the following message:
Unable to start debugging. Unexpected GDB output from command
"-exec-run". During startup program exited with code 126.
Posted
Updated 2-Jun-22 5:52am
Comments
[no name] 2-Jun-22 16:10pm    
Have you tried calling setrlimit() to set the RLIMIT_NICE limit?
Greg Utas 2-Jun-22 16:25pm    
Thanks. Never heard of it, but I'll look into it. This is the first time I'm using Linux.
[no name] 2-Jun-22 16:49pm    
It should fix your nice/priority EPERM issue. But I don't think you can use SCHED_RR on WSL though.
Greg Utas 2-Jun-22 18:56pm    
It can set various limits, but there isn't one for priority.

https://man7.org/linux/man-pages/man3/getrlimit.3p.html

EDIT: What's with this bunch? There's another page where the nice value can be changed:

https://man7.org/linux/man-pages/man2/getrlimit.2.html
[no name] 2-Jun-22 19:22pm    
Yeah, man2 covers syscalls, man3 covers usermode libs or something.

I believe setting the RLIMIT_NICE would allow your app to raise it's own priority. I'm super rusty on Linux stuff as I'm mostly a Windows guy. But I have used setrlimit() in the past. Let me know how it works out.

1 solution

Two things:
1) setcap only seems to apply to the current executable.
2) You can't get the desired behavior using GDB, even using sudo

For example, using the following simple C program
C
#include <stdio.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <errno.h>

int main()
{
    int p = getpriority(PRIO_PROCESS, 0);
    printf("p = %d\n", p);
    if( setpriority(PRIO_PROCESS, 0, -1) == -1) {
        perror("setpriority()");
    }
    else {
        p = getpriority(PRIO_PROCESS, 0);
        printf("p = %d\n", p);
    }

    return 0;
}
Here's what happens as we build, rebuild and try to debug the program
Shell
$ make setprio
cc -Wall -Wextra -ggdb    setprio.c   -o setprio
$ # as expected, can't up our nice value
$ ./setprio 
p = 0
setpriority(): Permission denied
$ # do the set_cap thing
$ sudo setcap cap_sys_nice=+ep $PWD/setprio
$ ./setprio 
p = 0
p = -1
$ # and run it again
$ ./setprio
p = 0
p = -1
$ # works as expected
$ # now rebuildi
$ rm setprio; make setprio
cc -Wall -Wextra -ggdb    setprio.c   -o setprio
$ # and it fails to escalate priority again
$ ./setprio
p = 0
setpriority(): Permission denied
$ # now lets try a gdb session ...
$ sudo setcap cap_sys_nice=+ep $PWD/setprio
$ ./setprio 
p = 0
p = -1
$ # good, works again
$ gdb ./setprio
 gdb preamble omitted 
Reading symbols from ./setprio...
(gdb) r
Starting program: /home/ebacon/tmp/setprio 
p = 0
setpriority(): Permission denied
[Inferior 1 (process 1234832) exited normally]
(gdb) quit
$ # Oh No, setcap doesn't propogate down the exec tree!
$ # maybe it will work as sudo?
$ sudo gdb setprio
Type "apropos word" to search for commands related to "word"...
Reading symbols from setprio...
(gdb) r
Starting program: /home/ebacon/tmp/setprio 
p = 0
p = -1
[Inferior 1 (process 1235176) exited normally]
(gdb) quit
$ #nope. Dang!

Similarly, you can't escalate priority inside gdb with a setuid hack. So whatever VS is doing, there doesn't seem to be a good way around this. I can confirm, though, that if I log in as root, I can elevate the process nice value inside GDB. Not sure if that helps.

I'm wondering, though, if you can't go in the other direction? Rather than trying to raise the nice value of one thread, can you not reduce the nice value of the other threads - at least during the development phase?
 
Share this answer
 
Comments
Greg Utas 2-Jun-22 12:31pm    
Thank you for your detailed response. Lower the priorities?! That's a great idea. A deployment could then presumably use setcap to raise the process priority. It's the relative thread priorities that are the key in any case: if those are correct, then I basically control the rest of the scheduling anyway, so I think it will work.

I'll let you know how this works out. Maybe lowering the priority needs permission too. :)
k5054 2-Jun-22 12:38pm    
"Maybe lowering the priority needs permission too". Any user can reduce a processes nice value. The intent is that if you know you have a resource hog, you can make it "nice" and run at a lower scheduling priority. Important back in the days of single processors and limited RAM, etc. But you have to have root privileges to escalate a processes priority above the base of zero.
Greg Utas 2-Jun-22 19:14pm    
It looks like there will be an issue with thread priorities:

https://man7.org/linux/man-pages/man7/sched.7.html states

For threads scheduled under one of the normal scheduling policies (SCHED_OTHER, SCHED_IDLE, SCHED_BATCH), sched_priority is not used in scheduling decisions (it must be specified as 0).

So unless SCHED_RR (or SCHED_FIFO) can be set, it looks like lowering some threads' priorities will have no effect, or that it may not even be allowed.
Greg Utas 3-Jun-22 17:43pm    
5. Thanks for the info. I'm going to proceed with the default priorities and see how things turn out. I think it has a good chance of working even without them.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900