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 - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/