Hi all,
The following test program intends to implement periodic threads based on POSIX API.
According to a POSIX recommendation found in clock_nanosleep() man page (3p), this system call is prefered to POSIX timers. I used the absolute time version of clock_nanosleep.
Scenario is the following: a high priority (p=50) thread executes a clock_nanosleep. At the timespec clock_nanosleep() is supposed to return, a low priority (p=1) CPU-intensive thread may be executing (this happens on a regular basis since the low priority periodic thread performs a +1 second busy wait). Unfortunately, although the high priority thread becomes eligible, the low priority CPU-intensive thread is not preemted.
Behavior is the same with both SCHED_FIFO and SCHED_RR.
Kernel is 2.6.12.
Can anyone tell me whether I am misusing the API, or if this is a known pitfall of linux's POSIX port (or - who knows ? - if this is behavior is conformant with POSIX ?)
If my kernel is too old, could you recommend a release / patch ?
I would very much appreciate your help.
Gregory Haik
--
Compile with g++ test.c -lm -lrt
Run as root.
test.c :
#define ONE_MILLION 1000000
#define ONE_BILLION 1000000000
#include <time.h> // clock_nanosleep()
#include <sys/time.h> // gettimeofday() in busy wait implem
#include <pthread.h>
#include <errno.h>
#include <math.h>
#include <iostream>
using namespace std;
int nb_iters_loop = 100000;
float duration_loop;
void calibrate_busy_wait()
{
nb_iters_loop = 100000;
struct timeval begin;
struct timeval end;
gettimeofday( &begin, 0 );
double value;
for( int ct = 0; ct < nb_iters_loop; ct++ )
{
value +=
value + log( 10 + value + log( 10 + value + log( 10 + value ) ) );
}
gettimeofday( &end, 0 );
duration_loop =
( end.tv_sec - begin.tv_sec ) + 1e-6 * ( end.tv_usec - begin.tv_usec );
}
void do_busy_wait( float seconds )
{
int nb_iterations_to_do = nb_iters_loop * ( seconds / duration_loop );
float value;
for( int ct = 0; ct < nb_iterations_to_do; ct++ )
{
value +=
value + log( 10 + value + log( 10 + value + log( 10 + value ) ) );
}
}
void * main_thread_high (void * arg)
{
int c = 0;
struct timespec ts;
int period = 10; // ms
int status = clock_gettime(CLOCK_REALTIME, &ts);
if (status != 0)
{
perror("clock_gettime");
exit(123);
}
unsigned long period_ms_ulong = (unsigned long) period;
unsigned long one_million_ulong = (unsigned long) ONE_MILLION;
unsigned long period_ns_ulong = (unsigned long) (period_ms_ulong * one_million_ulong);
unsigned long one_billion_ulong = (unsigned long) ONE_BILLION;
unsigned long additional_nanoseconds = (unsigned long) (period_ns_ulong % one_billion_ulong);
time_t additional_seconds = period / 1000;
while (true)
{
int status = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &ts, NULL);
if (status != 0)
{
switch (status)
{
case EINTR:
perror("clock_nanosleep() returned EINTR");
break;
case EINVAL:
perror("clock_nanosleep() returned EINVAL");
break;
case ENOTSUP:
perror("clock_nanosleep() returned ENOTSUP");
}
exit(1243);
}
ts.tv_nsec += additional_nanoseconds;
ts.tv_sec += additional_seconds;
if (ts.tv_nsec >= one_billion_ulong)
{
ts.tv_sec++;
ts.tv_nsec -= one_billion_ulong;
}
do_busy_wait((float) (period / 2000));
{ int sched_policy;
sched_param sp;
pthread_getschedparam(pthread_self(), &sched_policy, &sp);
cerr << __FILE__ << " : " << __LINE__ << " busy wait done, prio = " << sp.sched_priority << ", " << c++ << endl;
}
}
}
void * main_thread_low (void * arg)
{
int c = 0;
struct timespec ts;
int period = 2050; // ms
int status = clock_gettime(CLOCK_REALTIME, &ts);
if (status != 0)
{
perror("clock_gettime");
exit(123);
}
unsigned long period_ms_ulong = (unsigned long) period;
unsigned long one_million_ulong = (unsigned long) ONE_MILLION;
unsigned long period_ns_ulong = (unsigned long) (period_ms_ulong * one_million_ulong);
unsigned long one_billion_ulong = (unsigned long) ONE_BILLION;
unsigned long additional_nanoseconds = (unsigned long) (period_ns_ulong % one_billion_ulong);
time_t additional_seconds = period / 1000;
while (true)
{
int status = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &ts, NULL);
if (status != 0)
{
switch (status)
{
case EINTR:
perror("clock_nanosleep() returned EINTR");
break;
case EINVAL:
perror("clock_nanosleep() returned EINVAL");
break;
case ENOTSUP:
perror("clock_nanosleep() returned ENOTSUP");
}
exit(1243);
}
ts.tv_nsec += additional_nanoseconds;
ts.tv_sec += additional_seconds;
if (ts.tv_nsec >= one_billion_ulong)
{
ts.tv_sec++;
ts.tv_nsec -= one_billion_ulong;
}
do_busy_wait((float) (period / 2000));
{ int sched_policy;
sched_param sp;
pthread_getschedparam(pthread_self(), &sched_policy, &sp);
cerr << __FILE__ << " : " << __LINE__ << " busy wait done, prio = " << sp.sched_priority << ", " << c++ << endl;
}
}
}
int main()
{
calibrate_busy_wait();
pthread_t periodic_thread_high;
{
pthread_attr_t thread_attributes;
int status;
pthread_attr_init(&thread_attributes);
if (status != 0) perror("pthread_attr_init failed ");
status = pthread_attr_setschedpolicy(&thread_attributes, SCHED_FIFO);
if (status != 0) perror("pthread_set_schedpolicy failed ");
struct sched_param sched_parameter;
sched_parameter.sched_priority = 50;
status = pthread_attr_setschedparam(&thread_attributes, &sched_parameter);
if (status != 0) perror("pthread_setschedparam falied ");
status = pthread_attr_setinheritsched(&thread_attributes, PTHREAD_EXPLICIT_SCHED);
if (status != 0) perror("pthread_attr_setinheritsched failed");
status = pthread_attr_setscope( &thread_attributes, PTHREAD_SCOPE_SYSTEM );
if (status != 0) perror("pthread_attr_setscope failed ");
status = pthread_create(&periodic_thread_high, &thread_attributes, main_thread_high, NULL);
if (status != 0) perror("pthread_create failed ");
}
pthread_t periodic_thread_low;
{
pthread_attr_t thread_attributes;
int status;
pthread_attr_init(&thread_attributes);
if (status != 0) perror("pthread_attr_init failed ");
status = pthread_attr_setschedpolicy(&thread_attributes, SCHED_FIFO);
if (status != 0) perror("pthread_set_schedpolicy failed ");
struct sched_param sched_parameter;
sched_parameter.sched_priority = 1;
status = pthread_attr_setschedparam(&thread_attributes, &sched_parameter);
if (status != 0) perror("pthread_setschedparam falied ");
status = pthread_attr_setinheritsched(&thread_attributes, PTHREAD_EXPLICIT_SCHED);
if (status != 0) perror("pthread_attr_setinheritsched failed");
status = pthread_attr_setscope( &thread_attributes, PTHREAD_SCOPE_SYSTEM );
if (status != 0) perror("pthread_attr_setscope failed ");
status = pthread_create(&periodic_thread_low, &thread_attributes, main_thread_low, NULL);
if (status != 0) perror("pthread_create failed ");
}
pthread_join(periodic_thread_high, NULL);
pthread_join(periodic_thread_low, NULL);
cout << "Hopefully this message will never be issued." << endl;
}
/// sorry for the Yoohoo ad below...
___________________________________________________________________________
D?couvrez une nouvelle fa?on d'obtenir des r?ponses ? toutes vos questions !
Profitez des connaissances, des opinions et des exp?riences des internautes sur Yahoo! Questions/R?ponses
http://fr.answers.yahoo.com