aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBenoit Germain <bnt.germain@gmail.com>2013-12-02 14:40:08 +0100
committerBenoit Germain <bnt.germain@gmail.com>2013-12-02 14:40:08 +0100
commit370494d2e260e717990427180c6ab16d3746607e (patch)
treeb4b855be3de324acf00fcf0f028506613f8649a8 /src
parent6d124b90b637b0a85341646a68fdb11dc9079abf (diff)
downloadlanes-370494d2e260e717990427180c6ab16d3746607e.tar.gz
lanes-370494d2e260e717990427180c6ab16d3746607e.tar.bz2
lanes-370494d2e260e717990427180c6ab16d3746607e.zip
pthread thread priority refacto: threading.c
Diffstat (limited to 'src')
-rw-r--r--src/threading.c428
1 files changed, 212 insertions, 216 deletions
diff --git a/src/threading.c b/src/threading.c
index d50207e..18eef87 100644
--- a/src/threading.c
+++ b/src/threading.c
@@ -525,7 +525,8 @@ bool_t THREAD_WAIT_IMPL( THREAD_T *ref, double secs)
525 // 525 //
526 #include <errno.h> 526 #include <errno.h>
527 527
528# if ((defined(__MINGW32__) || defined(__MINGW64__)) && pthread_attr_setschedpolicy( A, S) == ENOTSUP) 528# if (defined(__MINGW32__) || defined(__MINGW64__)) && defined pthread_attr_setschedpolicy
529# if pthread_attr_setschedpolicy( A, S) == ENOTSUP
529 // from the mingw-w64 team: 530 // from the mingw-w64 team:
530 // Well, we support pthread_setschedparam by which you can specify 531 // Well, we support pthread_setschedparam by which you can specify
531 // threading-policy. Nevertheless, yes we lack this function. In 532 // threading-policy. Nevertheless, yes we lack this function. In
@@ -540,6 +541,7 @@ bool_t THREAD_WAIT_IMPL( THREAD_T *ref, double secs)
540 } 541 }
541 return 0; 542 return 0;
542 } 543 }
544# endif // pthread_attr_setschedpolicy()
543# endif // defined(__MINGW32__) || defined(__MINGW64__) 545# endif // defined(__MINGW32__) || defined(__MINGW64__)
544 546
545 static void _PT_FAIL( int rc, const char *name, const char *file, uint_t line ) { 547 static void _PT_FAIL( int rc, const char *name, const char *file, uint_t line ) {
@@ -593,245 +595,239 @@ bool_t THREAD_WAIT_IMPL( THREAD_T *ref, double secs)
593 void SIGNAL_ALL( SIGNAL_T *ref ) { 595 void SIGNAL_ALL( SIGNAL_T *ref ) {
594 PT_CALL( pthread_cond_broadcast(ref) ); // wake up ALL waiting threads 596 PT_CALL( pthread_cond_broadcast(ref) ); // wake up ALL waiting threads
595 } 597 }
596 //
597 void THREAD_CREATE( THREAD_T* ref,
598 THREAD_RETURN_T (*func)( void * ),
599 void *data, int prio /* -2..+2 */ ) {
600 pthread_attr_t _a;
601 pthread_attr_t *a= &_a;
602 struct sched_param sp;
603 bool_t normal;
604 598
605 PT_CALL( pthread_attr_init(a) ); 599// array of 7 thread priority values, hand-tuned by platform so that we offer a uniform [-3,+3] public priority range
600static int const gs_prio_remap[] =
601{
602 // NB: PThreads priority handling is about as twisty as one can get it
603 // (and then some). DON*T TRUST ANYTHING YOU READ ON THE NET!!!
606 604
607#ifndef PTHREAD_TIMEDJOIN 605 //---
608 // We create a NON-JOINABLE thread. This is mainly due to the lack of 606 // "Select the scheduling policy for the thread: one of SCHED_OTHER
609 // 'pthread_timedjoin()', but does offer other benefits (s.a. earlier 607 // (regular, non-real-time scheduling), SCHED_RR (real-time,
610 // freeing of the thread's resources). 608 // round-robin) or SCHED_FIFO (real-time, first-in first-out)."
611 // 609 //
612 PT_CALL( pthread_attr_setdetachstate(a,PTHREAD_CREATE_DETACHED) ); 610 // "Using the RR policy ensures that all threads having the same
613#endif 611 // priority level will be scheduled equally, regardless of their activity."
612 //
613 // "For SCHED_FIFO and SCHED_RR, the only required member of the
614 // sched_param structure is the priority sched_priority. For SCHED_OTHER,
615 // the affected scheduling parameters are implementation-defined."
616 //
617 // "The priority of a thread is specified as a delta which is added to
618 // the priority of the process."
619 //
620 // ".. priority is an integer value, in the range from 1 to 127.
621 // 1 is the least-favored priority, 127 is the most-favored."
622 //
623 // "Priority level 0 cannot be used: it is reserved for the system."
624 //
625 // "When you use specify a priority of -99 in a call to
626 // pthread_setschedparam(), the priority of the target thread is
627 // lowered to the lowest possible value."
628 //
629 // ...
614 630
615 // Use this to find a system's default stack size (DEBUG) 631 // ** CONCLUSION **
616#if 0 632 //
617 { size_t n; pthread_attr_getstacksize( a, &n ); 633 // PThread priorities are _hugely_ system specific, and we need at
618 fprintf( stderr, "Getstack: %u\n", (unsigned int)n ); } 634 // least OS specific settings. Hopefully, Linuxes and OS X versions
619 // 524288 on OS X 635 // are uniform enough, among each other...
620 // 2097152 on Linux x86 (Ubuntu 7.04) 636 //
621 // 1048576 on FreeBSD 6.2 SMP i386 637# if defined PLATFORM_OSX
622#endif 638 // AK 10-Apr-07 (OS X PowerPC 10.4.9):
639 //
640 // With SCHED_RR, 26 seems to be the "normal" priority, where setting
641 // it does not seem to affect the order of threads processed.
642 //
643 // With SCHED_OTHER, the range 25..32 is normal (maybe the same 26,
644 // but the difference is not so clear with OTHER).
645 //
646 // 'sched_get_priority_min()' and '..max()' give 15, 47 as the
647 // priority limits. This could imply, user mode applications won't
648 // be able to use values outside of that range.
649 //
650# define _PRIO_MODE SCHED_OTHER
651
652 // OS X 10.4.9 (PowerPC) gives ENOTSUP for process scope
653 //#define _PRIO_SCOPE PTHREAD_SCOPE_PROCESS
654
655# define _PRIO_HI 32 // seems to work (_carefully_ picked!)
656# define _PRIO_0 26 // detected
657# define _PRIO_LO 1 // seems to work (tested)
658
659# elif defined PLATFORM_LINUX
660 // (based on Ubuntu Linux 2.6.15 kernel)
661 //
662 // SCHED_OTHER is the default policy, but does not allow for priorities.
663 // SCHED_RR allows priorities, all of which (1..99) are higher than
664 // a thread with SCHED_OTHER policy.
665 //
666 // <http://kerneltrap.org/node/6080>
667 // <http://en.wikipedia.org/wiki/Native_POSIX_Thread_Library>
668 // <http://www.net.in.tum.de/~gregor/docs/pthread-scheduling.html>
669 //
670 // Manuals suggest checking #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING,
671 // but even Ubuntu does not seem to define it.
672 //
673# define _PRIO_MODE SCHED_RR
623 674
624#if (defined _THREAD_STACK_SIZE) && (_THREAD_STACK_SIZE > 0) 675 // NTLP 2.5: only system scope allowed (being the basic reason why
625 PT_CALL( pthread_attr_setstacksize( a, _THREAD_STACK_SIZE ) ); 676 // root privileges are required..)
626#endif 677 //#define _PRIO_SCOPE PTHREAD_SCOPE_PROCESS
627
628 normal=
629#if defined(PLATFORM_LINUX) && defined(LINUX_SCHED_RR)
630 !sudo; // with sudo, even normal thread must use SCHED_RR
631#else
632 prio == 0; // create a default thread if
633#endif
634 if (!normal) {
635 // NB: PThreads priority handling is about as twisty as one can get it
636 // (and then some). DON*T TRUST ANYTHING YOU READ ON THE NET!!!
637 678
638 // "The specified scheduling parameters are only used if the scheduling 679# define _PRIO_HI 99
639 // parameter inheritance attribute is PTHREAD_EXPLICIT_SCHED." 680# define _PRIO_0 50
640 // 681# define _PRIO_LO 1
641 PT_CALL( pthread_attr_setinheritsched( a, PTHREAD_EXPLICIT_SCHED ) );
642 682
643 //--- 683# elif defined(PLATFORM_BSD)
644 // "Select the scheduling policy for the thread: one of SCHED_OTHER 684 //
645 // (regular, non-real-time scheduling), SCHED_RR (real-time, 685 // <http://www.net.in.tum.de/~gregor/docs/pthread-scheduling.html>
646 // round-robin) or SCHED_FIFO (real-time, first-in first-out)." 686 //
647 // 687 // "When control over the thread scheduling is desired, then FreeBSD
648 // "Using the RR policy ensures that all threads having the same 688 // with the libpthread implementation is by far the best choice .."
649 // priority level will be scheduled equally, regardless of their activity." 689 //
650 // 690# define _PRIO_MODE SCHED_OTHER
651 // "For SCHED_FIFO and SCHED_RR, the only required member of the 691# define _PRIO_SCOPE PTHREAD_SCOPE_PROCESS
652 // sched_param structure is the priority sched_priority. For SCHED_OTHER, 692# define _PRIO_HI 31
653 // the affected scheduling parameters are implementation-defined." 693# define _PRIO_0 15
654 // 694# define _PRIO_LO 1
655 // "The priority of a thread is specified as a delta which is added to
656 // the priority of the process."
657 //
658 // ".. priority is an integer value, in the range from 1 to 127.
659 // 1 is the least-favored priority, 127 is the most-favored."
660 //
661 // "Priority level 0 cannot be used: it is reserved for the system."
662 //
663 // "When you use specify a priority of -99 in a call to
664 // pthread_setschedparam(), the priority of the target thread is
665 // lowered to the lowest possible value."
666 //
667 // ...
668 695
669 // ** CONCLUSION ** 696# elif defined(PLATFORM_CYGWIN)
670 // 697 //
671 // PThread priorities are _hugely_ system specific, and we need at 698 // TBD: Find right values for Cygwin
672 // least OS specific settings. Hopefully, Linuxes and OS X versions 699 //
673 // are uniform enough, among each other... 700# elif defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC)
674 // 701 // any other value not supported by win32-pthread as of version 2.9.1
675#ifdef PLATFORM_OSX 702# define _PRIO_MODE SCHED_OTHER
676 // AK 10-Apr-07 (OS X PowerPC 10.4.9):
677 //
678 // With SCHED_RR, 26 seems to be the "normal" priority, where setting
679 // it does not seem to affect the order of threads processed.
680 //
681 // With SCHED_OTHER, the range 25..32 is normal (maybe the same 26,
682 // but the difference is not so clear with OTHER).
683 //
684 // 'sched_get_priority_min()' and '..max()' give 15, 47 as the
685 // priority limits. This could imply, user mode applications won't
686 // be able to use values outside of that range.
687 //
688 #define _PRIO_MODE SCHED_OTHER
689
690 // OS X 10.4.9 (PowerPC) gives ENOTSUP for process scope
691 //#define _PRIO_SCOPE PTHREAD_SCOPE_PROCESS
692 703
693 #define _PRIO_HI 32 // seems to work (_carefully_ picked!) 704 // PTHREAD_SCOPE_PROCESS not supported by win32-pthread as of version 2.9.1
694 #define _PRIO_0 26 // detected 705 //#define _PRIO_SCOPE PTHREAD_SCOPE_SYSTEM // but do we need this at all to start with?
695 #define _PRIO_LO 1 // seems to work (tested) 706 THREAD_PRIORITY_IDLE, THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_BELOW_NORMAL, THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL, THREAD_PRIORITY_HIGHEST, THREAD_PRIORITY_TIME_CRITICAL
696 707
697#elif defined(PLATFORM_LINUX) 708# else
698 // (based on Ubuntu Linux 2.6.15 kernel) 709# error "Unknown OS: not implemented!"
699 // 710# endif
700 // SCHED_OTHER is the default policy, but does not allow for priorities.
701 // SCHED_RR allows priorities, all of which (1..99) are higher than
702 // a thread with SCHED_OTHER policy.
703 //
704 // <http://kerneltrap.org/node/6080>
705 // <http://en.wikipedia.org/wiki/Native_POSIX_Thread_Library>
706 // <http://www.net.in.tum.de/~gregor/docs/pthread-scheduling.html>
707 //
708 // Manuals suggest checking #ifdef _POSIX_THREAD_PRIORITY_SCHEDULING,
709 // but even Ubuntu does not seem to define it.
710 //
711 #define _PRIO_MODE SCHED_RR
712
713 // NTLP 2.5: only system scope allowed (being the basic reason why
714 // root privileges are required..)
715 //#define _PRIO_SCOPE PTHREAD_SCOPE_PROCESS
716 711
717 #define _PRIO_HI 99 712#if defined _PRIO_0
718 #define _PRIO_0 50 713# define _PRIO_AN (_PRIO_0 + ((_PRIO_HI-_PRIO_0)/2) )
719 #define _PRIO_LO 1 714# define _PRIO_BN (_PRIO_LO + ((_PRIO_0-_PRIO_LO)/2) )
720 715
721#elif defined(PLATFORM_BSD) 716 _PRIO_LO, _PRIO_LO, _PRIO_BN, _PRIO_0, _PRIO_AN, _PRIO_HI, _PRIO_HI
722 // 717#endif // _PRIO_0
723 // <http://www.net.in.tum.de/~gregor/docs/pthread-scheduling.html> 718};
724 //
725 // "When control over the thread scheduling is desired, then FreeBSD
726 // with the libpthread implementation is by far the best choice .."
727 //
728 #define _PRIO_MODE SCHED_OTHER
729 #define _PRIO_SCOPE PTHREAD_SCOPE_PROCESS
730 #define _PRIO_HI 31
731 #define _PRIO_0 15
732 #define _PRIO_LO 1
733 719
734#elif defined(PLATFORM_CYGWIN) 720//
735 // 721void THREAD_CREATE( THREAD_T* ref, THREAD_RETURN_T (*func)( void * ), void *data, int prio /* -2..+2 */)
736 // TBD: Find right values for Cygwin 722{
737 // 723 pthread_attr_t a;
738#elif defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC) 724 bool_t const normal =
739 // any other value not supported by win32-pthread as of version 2.9.1 725#if defined(PLATFORM_LINUX) && defined(LINUX_SCHED_RR)
740 #define _PRIO_MODE SCHED_OTHER 726 !sudo; // with sudo, even normal thread must use SCHED_RR
741
742 // PTHREAD_SCOPE_PROCESS not supported by win32-pthread as of version 2.9.1
743 //#define _PRIO_SCOPE PTHREAD_SCOPE_SYSTEM // but do we need this at all to start with?
744
745#if defined __WINPTHREADS_VERSION
746 // see http://sourceforge.net/p/mingw-w64/code/6370/tree/trunk/mingw-w64-libraries/winpthreads/src/sched.c#l128
747 #define _PRIO_HI (+15)
748 #define _PRIO_0 (0)
749 #define _PRIO_LO (-15)
750#else
751 // win32-pthread seems happy with direct -2..+2 instead of some other remapping
752 #define _PRIO_HI (+2)
753 #define _PRIO_0 (0)
754 #define _PRIO_LO (-2)
755#endif
756#else 727#else
757 #error "Unknown OS: not implemented!" 728 (prio == 0);
758#endif 729#endif
759 730
760#ifdef _PRIO_SCOPE 731 PT_CALL( pthread_attr_init( &a));
761 PT_CALL( pthread_attr_setscope( a, _PRIO_SCOPE ) );
762#endif
763 PT_CALL( pthread_attr_setschedpolicy( a, _PRIO_MODE ) );
764 732
765#define _PRIO_AN (_PRIO_0 + ((_PRIO_HI-_PRIO_0)/2) ) 733#ifndef PTHREAD_TIMEDJOIN
766#define _PRIO_BN (_PRIO_LO + ((_PRIO_0-_PRIO_LO)/2) ) 734 // We create a NON-JOINABLE thread. This is mainly due to the lack of
735 // 'pthread_timedjoin()', but does offer other benefits (s.a. earlier
736 // freeing of the thread's resources).
737 //
738 PT_CALL( pthread_attr_setdetachstate( &a, PTHREAD_CREATE_DETACHED));
739#endif // PTHREAD_TIMEDJOIN
767 740
768 sp.sched_priority= 741 // Use this to find a system's default stack size (DEBUG)
769 (prio == +2) ? _PRIO_HI : 742#if 0
770 (prio == +1) ? _PRIO_AN : 743 {
771#if defined(PLATFORM_LINUX) && defined(LINUX_SCHED_RR) 744 size_t n;
772 (prio == 0) ? _PRIO_0 : 745 pthread_attr_getstacksize( &a, &n);
746 fprintf( stderr, "Getstack: %u\n", (unsigned int)n);
747 }
748 // 524288 on OS X
749 // 2097152 on Linux x86 (Ubuntu 7.04)
750 // 1048576 on FreeBSD 6.2 SMP i386
751#endif // 0
752
753#if defined _THREAD_STACK_SIZE && _THREAD_STACK_SIZE > 0
754 PT_CALL( pthread_attr_setstacksize( &a, _THREAD_STACK_SIZE));
773#endif 755#endif
774 (prio == -1) ? _PRIO_BN : _PRIO_LO;
775 756
776 PT_CALL( pthread_attr_setschedparam( a, &sp ) ); 757 if( !normal)
777 } 758 {
759 struct sched_param sp;
760 // "The specified scheduling parameters are only used if the scheduling
761 // parameter inheritance attribute is PTHREAD_EXPLICIT_SCHED."
762 //
763 PT_CALL( pthread_attr_setinheritsched( &a, PTHREAD_EXPLICIT_SCHED));
778 764
779 //---
780 // Seems on OS X, _POSIX_THREAD_THREADS_MAX is some kind of system
781 // thread limit (not userland thread). Actual limit for us is way higher.
782 // PTHREAD_THREADS_MAX is not defined (even though man page refers to it!)
783 //
784# ifndef THREAD_CREATE_RETRIES_MAX
785 // Don't bother with retries; a failure is a failure
786 //
787 {
788 int rc= pthread_create( ref, a, func, data );
789 if (rc) _PT_FAIL( rc, "pthread_create()", __FILE__, __LINE__-1 );
790 }
791# else
792# error "This code deprecated"
793/*
794 // Wait slightly if thread creation has exchausted the system
795 //
796 { uint_t retries;
797 for( retries=0; retries<THREAD_CREATE_RETRIES_MAX; retries++ ) {
798
799 int rc= pthread_create( ref, a, func, data );
800 //
801 // OS X / Linux:
802 // EAGAIN: ".. lacked the necessary resources to create
803 // another thread, or the system-imposed limit on the
804 // total number of threads in a process
805 // [PTHREAD_THREADS_MAX] would be exceeded."
806 // EINVAL: attr is invalid
807 // Linux:
808 // EPERM: no rights for given parameters or scheduling (no sudo)
809 // ENOMEM: (known to fail with this code, too - not listed in man)
810
811 if (rc==0) break; // ok!
812
813 // In practise, exhaustion seems to be coming from memory, not a
814 // maximum number of threads. Keep tuning... ;)
815 //
816 if (rc==EAGAIN) {
817//fprintf( stderr, "Looping (retries=%d) ", retries ); // DEBUG
818 765
819 // Try again, later. 766#ifdef _PRIO_SCOPE
767 PT_CALL( pthread_attr_setscope( &a, _PRIO_SCOPE));
768#endif // _PRIO_SCOPE
820 769
821 Yield(); 770 PT_CALL( pthread_attr_setschedpolicy( &a, _PRIO_MODE));
822 } else { 771
823 _PT_FAIL( rc, "pthread_create()", __FILE__, __LINE__ ); 772 // prio range [-3,+3] was checked by the caller
824 } 773 sp.sched_priority = gs_prio_remap[ prio + 3];
825 } 774 PT_CALL( pthread_attr_setschedparam( &a, &sp));
826 } 775 }
827*/ 776
777 //---
778 // Seems on OS X, _POSIX_THREAD_THREADS_MAX is some kind of system
779 // thread limit (not userland thread). Actual limit for us is way higher.
780 // PTHREAD_THREADS_MAX is not defined (even though man page refers to it!)
781 //
782# ifndef THREAD_CREATE_RETRIES_MAX
783 // Don't bother with retries; a failure is a failure
784 //
785 {
786 int rc = pthread_create( ref, &a, func, data);
787 if( rc) _PT_FAIL( rc, "pthread_create()", __FILE__, __LINE__ - 1);
788 }
789# else
790# error "This code deprecated"
791 /*
792 // Wait slightly if thread creation has exchausted the system
793 //
794 { uint_t retries;
795 for( retries=0; retries<THREAD_CREATE_RETRIES_MAX; retries++ ) {
796
797 int rc= pthread_create( ref, &a, func, data );
798 //
799 // OS X / Linux:
800 // EAGAIN: ".. lacked the necessary resources to create
801 // another thread, or the system-imposed limit on the
802 // total number of threads in a process
803 // [PTHREAD_THREADS_MAX] would be exceeded."
804 // EINVAL: attr is invalid
805 // Linux:
806 // EPERM: no rights for given parameters or scheduling (no sudo)
807 // ENOMEM: (known to fail with this code, too - not listed in man)
808
809 if (rc==0) break; // ok!
810
811 // In practise, exhaustion seems to be coming from memory, not a
812 // maximum number of threads. Keep tuning... ;)
813 //
814 if (rc==EAGAIN) {
815 //fprintf( stderr, "Looping (retries=%d) ", retries ); // DEBUG
816
817 // Try again, later.
818
819 Yield();
820 } else {
821 _PT_FAIL( rc, "pthread_create()", __FILE__, __LINE__ );
822 }
823 }
824 }
825 */
828# endif 826# endif
829 827
830 if (a) { 828 PT_CALL( pthread_attr_destroy( &a));
831 PT_CALL( pthread_attr_destroy(a) ); 829}
832 } 830
833 }
834 //
835 /* 831 /*
836 * Wait for a thread to finish. 832 * Wait for a thread to finish.
837 * 833 *