Nios® V/II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® V/II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++

scheduling policy

Altera_Forum
Honored Contributor II
1,075 Views

We're running uClinux based on linux version 2.6.x under the Nios II IDE v1.0.0 build 393. 

 

In experimenting with POSIX threads, I've been attempting to activate timeslicing for an 

application run from the shell. The scheduling policy is set to SCHED_OTHER, which is clearly, 

based on results, not the same as SCHED_RR, and attempts to change it to SCHED_RR or 

SCHED_FIFO using sched_setscheduler fail with a 'bad argument' error. 

 

The process is running as root, so it appears (from looking at the source for sched.c in the kernel) 

that the cause of the failure is that such processes don't have the CAP_SYS_NICE capability (from the 

recently-created POSIX libcap capabilities). 

 

I've been unable to do anything about it, or even confirm my hypothesis, because none of the 

functions to set or get capabilities are declared or defined (capget, capset, cap_get_proc, 

cap_set_proc, capgetp, capsetp) in the runtime libraries. There are syscall numbers for capget 

and capset but no wrapper functions are declared or defined. 

 

As far as I can determine, none of the kernel configuration options help with this (there are 

some flags related to SELinux, but they don't seem to affect this). 

 

Has anybody had any success doing this? I've run out of ideas.
0 Kudos
5 Replies
Altera_Forum
Honored Contributor II
346 Views

Hi Halfdome, 

 

Can you try the following code? 

 

    struct sched_param schp;     /*  * set the process to realtime privs  */     memset(&schp, 0, sizeof(schp));     schp.sched_priority = sched_get_priority_max(SCHED_FIFO);          if (sched_setscheduler(0, SCHED_FIFO, &schp) != 0) {  perror("sched_setscheduler");  exit(1);     } 

 

Regards, 

wentao
0 Kudos
Altera_Forum
Honored Contributor II
346 Views

Thanks, wentao, for the suggested code fragment. 

 

The call to sched_setscheduler() successfully changed the scheduling policy without returning 

an error. 

 

I had tried something more like this: 

struct sched_param schp; sched_getparam(getpid(), &schp); schp.sched_priority = sched_get_priority_max(SCHED_RR); if (sched_setscheduler(getpid(), SCHED_RR, &schp) != 0) {    perror("sched_setscheduler");    exit(1); } 

 

Apparently, one needs to pass the root process ID of 0 in order to change 

the policy. Whatever, a subsequent call to sched_getparam passing it the 

calling process returns the changed schedule policy value, and a subsequent 

sched_setparam call with getpid() also works, so there it is. 

 

However, I'm not sure changing the policy did anything: 

 

My test case, minus the# includes and various queries and printf() calls, is: 

 

static int done; void* threaddie(void* arg) {    int i;    char c = *((char*) arg);    for(i = 0; i < 20; i++) {        putchar(c);    }    done++;    pthread_exit(NULL);    return NULL; } int main(int argc, char** argv) {    pthread_t t1, t2, t3, t4;    char c1 = &#39;1&#39;;    char c2 = &#39;2&#39;;    char c3 = &#39;3&#39;;    char c4 = &#39;4&#39;;    int policy;    struct sched_param schp;    policy = SCHED_RR;    memset(&schp, 0, sizeof(schp));    schp.sched_priority = sched_get_priority_min(policy);    if (sched_setscheduler(0, policy, &schp) != 0) {        perror("sched_setscheduler");        exit(1);    }    done = 0;    pthread_create(&t1, NULL, threaddie, (void*) &c1);    pthread_create(&t2, NULL, threaddie, (void*) &c2);    pthread_create(&t3, NULL, threaddie, (void*) &c3);    pthread_create(&t4, NULL, threaddie, (void*) &c4);    while (done < 4) {        sched_yield();    }    return 0; 

 

The output from this test case, regardless of whether policy is set to SCHED_RR, SCHED_FIFO, 

or SCHED_OTHER, is: 

11111111111111111111222222222222222222223333333333333333333344444444444444444444 

 

...so linux is not preempting the first thread to run the second, and so on, which indicates 

to me that the scheduling policy change didn&#39;t work. Increasing the number of iterations just 

increases the number of 1&#39;s in a row etc. Inserting some busywork code (for example, 

declaring int j, then inserting j = i * 2 in the loop after the putchar) also has no effect. 

 

If I insert a call to sched_yield() after the putchar, I get: 

(for SCHED_RR) 

11121212123123123412341234123412341234123412341234123412341234123423423434343444 

(SCHED_OTHER is slightly different) 

12123412341234123412341234123412341234123412341234123412341234123412341234123434 

 

If I replace the sched_yield() call with usleep(1), I get (regardless of policy): 

12341234123412341234123412341234123412341234123412341234123412341234123412341234 

 

Maybe there&#39;s something I&#39;m not understanding about pre-emption. Is it possible that the 

scheduler isn&#39;t being called because the first thread is in the kernel with interrupts off (because 

of the putchar call) every time the interval timer goes off? Seems far fetched to me. 

 

At any rate, I&#39;m further along than I was, so I appreciate the suggestion.
0 Kudos
Altera_Forum
Honored Contributor II
346 Views

I&#39;ve no direct experience of uLinux, so take what I say with a pinch of salt. But the principles are likely to be the same from other OSes. 

 

1: Round robin scheduling won&#39;t switch between tasks except at system "clock tick" boundaries. which are typically about 100Hz. So to see RR scheduling happening, you need to make your task busy for at least 10Millisecs. This is more than just a little bit of maths and declaring an int. Try calculating PI to 1000 places with floating point math http://forum.niosforum.com/work2/style_emoticons/<#EMO_DIR#>/cool.gif ? You only need RR scheduling if you have more than one *CPU-bound* task at the same priority level. 

 

2: Putchar and buffering. Even if you&#39;re using a slow serial port, putchar will likely put some buffering in the way, so your output will happen quicker than it appears. This can distort what you see. 

 

2: Beware the priorities of your spawned tasks vs. the task spawning them! Make sure your spawned tasks don&#39;t start running until all of them are ready to go, otherwise you&#39;ll get additional confusion. This is why you see the slightly odd starting and ending sequences with the &#39;yield&#39; inserted. 

 

Hope that helps... 

 

- Roddy
0 Kudos
Altera_Forum
Honored Contributor II
346 Views

<div class='quotetop'>QUOTE </div> 

--- Quote Start ---  

Apparently, one needs to pass the root process ID of 0 in order to change 

the policy. Whatever, a subsequent call to sched_getparam passing it the 

calling process returns the changed schedule policy value, and a subsequent 

sched_setparam call with getpid() also works[/b] 

--- Quote End ---  

 

Here 0 means current calling process instead of root process.  

 

<div class='quotetop'>QUOTE </div> 

--- Quote Start ---  

...so linux is not preempting the first thread to run the second, and so on, which indicates 

to me that the scheduling policy change didn&#39;t work[/b] 

--- Quote End ---  

 

why do you expect the second to preempt the first one? All the five thread you have are of the same scheduler policy and the same priority.
0 Kudos
Altera_Forum
Honored Contributor II
346 Views

Thanks for the input, everyone. I&#39;m experimenting with round robin scheduling as a quick way to see preemption at work in uClinux. I&#39;ve worked with vxWorks in the past so I&#39;m pretty familiar with the basics but haven&#39;t been under the hood on a Unix derivative and haven&#39;t used POSIX threads either, so before diving in to the real project I wanted to familiarize myself further. 

 

roddy says: 

<div class='quotetop'>QUOTE </div> 

--- Quote Start ---  

1: Round robin scheduling won&#39;t switch between tasks except at system "clock tick" boundaries. which are typically about 100Hz. So to see RR scheduling happening, you need to make your task busy for at least 10Millisecs. This is more than just a little bit of maths and declaring an int. Try calculating PI to 1000 places with floating point math cool.gif ? You only need RR scheduling if you have more than one *CPU-bound* task at the same priority level.[/b] 

--- Quote End ---  

 

 

That did the trick! (well, I didn&#39;t calculate PI but inserted a loop of floating point math to slow things down) Not only was I underestimating the processor speed, but I also hadn&#39;t checked the actual time a single process is allowed to run before being preempted by a process of the same priority (sched_get_rr_interval() return value). On our system it&#39;s 100 milliseconds, ten times the clock tick. 

 

<div class='quotetop'>QUOTE </div> 

--- Quote Start ---  

2: Putchar and buffering. Even if you&#39;re using a slow serial port, putchar will likely put some buffering in the way, so your output will happen quicker than it appears. This can distort what you see.[/b] 

--- Quote End ---  

 

 

Indeed, and as a result I haven&#39;t concerned myself about how soon the output appears but just its order. Since stdout has a single buffer to which all four threads are writing (threads share file descriptors), buffering shouldn&#39;t affect the order. 

 

<div class='quotetop'>QUOTE </div> 

--- Quote Start ---  

2: Beware the priorities of your spawned tasks vs. the task spawning them! Make sure your spawned tasks don&#39;t start running until all of them are ready to go, otherwise you&#39;ll get additional confusion. This is why you see the slightly odd starting and ending sequences with the &#39;yield&#39; inserted.[/b] 

--- Quote End ---  

 

 

Threads inherit their parent&#39;s priority, and pthread_create starts running the thread right away, so the eccentricity of the ordering at the beginning and end didn&#39;t surprise or alarm me. Putting a barrier at the start of the thread processes would fix it. 

 

wentao says: 

<div class='quotetop'>QUOTE </div> 

--- Quote Start ---  

Here [in sched_setscheduler()] 0 means current calling process instead of root process.[/b] 

--- Quote End ---  

 

 

Oops. I missed that sentence in the man page, but now see it. Thanks, and I see the same is true for sched_getparam(), sched_getscheduler() and so on. 

 

<div class='quotetop'>QUOTE </div> 

--- Quote Start ---  

why do you expect the second to preempt the first one? All the five thread you have are of the same scheduler policy and the same priority.[/b] 

--- Quote End ---  

 

 

I expect it because that what&#39;s SCHED_RR (round robin) scheduling is supposed to do: enable time sharing between processes of the same priority. SCHED_FIFO, on the other hand, does not timeslice between processes of like priority. 

 

Again, thanks for all the help. On to the next thing.
0 Kudos
Reply