summaryrefslogtreecommitdiff
path: root/sched.c
diff options
context:
space:
mode:
authorrpj <rpj>2001-07-01 13:23:10 +0000
committerrpj <rpj>2001-07-01 13:23:10 +0000
commita311086d622d3c778e1da57cfae167c0ab1c0fb4 (patch)
tree760a76a351c18331ff92239366804bd4b866dea6 /sched.c
parent528fccade9ca5f90db376e08b2cb85b3fc822a45 (diff)
2001-06-25 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
* create.c (pthread_create): Add priority inheritance attributes. * mutex.c (pthread_mutex_lock): Remove some overhead for PTHREAD_MUTEX_NORMAL mutex types. Specifically, avoid calling pthread_self() and pthread_equal() to check/set the mutex owner. Introduce a new pseudo owner for this type. Test results suggest increases in speed of up to 90% for non-blocking locks. This is the default type of mutex used internally by other synchronising objects, ie. condition variables and read-write locks. The test rwlock7.c shows about a 30-35% speed increase over snapshot 2001-06-06. The price of this is that the application developer must ensure correct behaviour, or explicitly set the mutex to a safer type such as PTHREAD_MUTEX_ERRORCHECK. For example, PTHREAD_MUTEX_NORMAL (or PTHREAD_MUTEX_DEFAULT) type mutexes will not return an error if a thread which is not the owner calls pthread_mutex_unlock. The call will succeed in unlocking the mutex if it is currently locked, but a subsequent unlock by the true owner will then fail with EPERM. This is however consistent with some other implementations. (pthread_mutex_unlock): Likewise. (pthread_mutex_trylock): Likewise. (pthread_mutex_destroy): Likewise. * attr.c (pthread_attr_init): PTHREAD_EXPLICIT_SCHED is the default inheritance attribute; THREAD_PRIORITY_NORMAL is the default priority for new threads. * sched.c (pthread_attr_setschedpolicy): Added routine. (pthread_attr_getschedpolicy): Added routine. (pthread_attr_setinheritsched): Added routine. (pthread_attr_getinheritsched): Added routine. * pthread.h (sched_rr_set_interval): Added as a macro; returns -1 with errno set to ENOSYS. 2001-06-23 Ross Johnson <rpj@setup1.ise.canberra.edu.au> *sched.c (pthread_attr_setschedparam): Add priority range check. (sched_setscheduler): New function; checks for a valid pid and policy; checks for permission to set information in the target process; expects pid to be a Win32 process ID, not a process handle; the only scheduler policy allowed is SCHED_OTHER. (sched_getscheduler): Likewise, but checks for permission to query. * pthread.h (SCHED_*): Moved to sched.h as defined in the POSIX standard. * sched.h (SCHED_*): Moved from pthread.h. (pid_t): Defined if necessary. (sched_setscheduler): Defined. (sched_getscheduler): Defined. * pthread.def (sched_setscheduler): Exported. (sched_getscheduler): Likewise. 2001-06-23 Ross Johnson <rpj@setup1.ise.canberra.edu.au> Contributed by - Ralf Brese <Ralf.Brese@pdb4.siemens.de> * create.c (pthread_create): Set thread priority from thread attributes.
Diffstat (limited to 'sched.c')
-rw-r--r--sched.c410
1 files changed, 391 insertions, 19 deletions
diff --git a/sched.c b/sched.c
index 0f83a43..6f558ab 100644
--- a/sched.c
+++ b/sched.c
@@ -23,8 +23,6 @@
* MA 02111-1307, USA
*/
-#define ENOSUP 0
-
#include "pthread.h"
#include "implement.h"
#include "sched.h"
@@ -37,19 +35,78 @@ is_attr(const pthread_attr_t *attr)
(*attr)->valid != PTW32_ATTR_VALID) ? 1 : 0;
}
+
+int
+pthread_attr_setschedpolicy(pthread_attr_t *attr,
+ int policy)
+{
+ if (is_attr(attr) != 0)
+ {
+ return EINVAL;
+ }
+
+ if (policy != SCHED_OTHER)
+ {
+ return ENOTSUP;
+ }
+
+ return 0;
+}
+
+
+int
+pthread_attr_getschedpolicy(pthread_attr_t *attr,
+ int * policy)
+{
+ if (is_attr(attr) != 0 || policy == NULL)
+ {
+ return EINVAL;
+ }
+
+ /*
+ * Validate the policy arg.
+ * Check that a policy constant wasn't passed rather than &policy.
+ */
+ if (policy <= (int *) SCHED_MAX)
+ {
+ return EINVAL;
+ }
+
+ *policy = SCHED_OTHER;
+
+ return 0;
+}
+
+
int
pthread_attr_setschedparam(pthread_attr_t *attr,
const struct sched_param *param)
{
+ int priority;
+
if (is_attr(attr) != 0 || param == NULL)
{
return EINVAL;
}
- (*attr)->priority = param->sched_priority;
+ priority = param->sched_priority;
+
+ /*
+ * Validate priority level. Don't check the
+ * return values of the function calls because
+ * we're sure they will succeed.
+ */
+ if (priority < sched_get_priority_min(SCHED_OTHER) ||
+ priority > sched_get_priority_max(SCHED_OTHER))
+ {
+ return EINVAL;
+ }
+
+ memcpy(&(*attr)->param, param, sizeof(*param));
return 0;
}
+
int
pthread_attr_getschedparam(const pthread_attr_t *attr,
struct sched_param *param)
@@ -59,11 +116,47 @@ pthread_attr_getschedparam(const pthread_attr_t *attr,
return EINVAL;
}
- param->sched_priority = (*attr)->priority;
+ memcpy(param, &(*attr)->param, sizeof(*param));
return 0;
}
-int pthread_setschedparam(pthread_t thread, int policy,
+
+int
+pthread_attr_setinheritsched(pthread_attr_t * attr,
+ int inheritsched)
+{
+ if (is_attr(attr) != 0)
+ {
+ return EINVAL;
+ }
+
+ if (PTHREAD_INHERIT_SCHED != inheritsched
+ && PTHREAD_EXPLICIT_SCHED != inheritsched)
+ {
+ return EINVAL;
+ }
+
+ (*attr)->inheritsched = inheritsched;
+ return 0;
+}
+
+
+int
+pthread_attr_getinheritsched(pthread_attr_t * attr,
+ int * inheritsched)
+{
+ if (is_attr(attr) != 0 || inheritsched == NULL)
+ {
+ return EINVAL;
+ }
+
+ *inheritsched = (*attr)->inheritsched;
+ return 0;
+}
+
+
+int
+pthread_setschedparam(pthread_t thread, int policy,
const struct sched_param *param)
{
/* Validate the thread id. */
@@ -81,12 +174,16 @@ int pthread_setschedparam(pthread_t thread, int policy,
/* Ensure the policy is SCHED_OTHER. */
if (policy != SCHED_OTHER)
{
- return ENOSUP;
+ return ENOTSUP;
}
- /* Validate priority level. */
- if (param->sched_priority < sched_get_priority_min(policy) ||
- param->sched_priority > sched_get_priority_max(policy))
+ /*
+ * Validate priority level. Don't check the
+ * return values of the function calls because
+ * we're sure they will succeed.
+ */
+ if (param->sched_priority < sched_get_priority_min(SCHED_OTHER) ||
+ param->sched_priority > sched_get_priority_max(SCHED_OTHER))
{
return EINVAL;
}
@@ -97,7 +194,9 @@ int pthread_setschedparam(pthread_t thread, int policy,
return 0;
}
-int pthread_getschedparam(pthread_t thread, int *policy,
+
+int
+pthread_getschedparam(pthread_t thread, int *policy,
struct sched_param *param)
{
int prio;
@@ -108,8 +207,11 @@ int pthread_getschedparam(pthread_t thread, int *policy,
return EINVAL;
}
- /* Validate the param structure. */
- if (param == NULL)
+ /*
+ * Validate the policy and param args.
+ * Check that a policy constant wasn't passed rather than &policy.
+ */
+ if (policy <= (int *) SCHED_MAX || param == NULL)
{
return EINVAL;
}
@@ -141,14 +243,24 @@ int pthread_getschedparam(pthread_t thread, int *policy,
* sched_get_priority_max() returns 1
*/
+
#define sched_Max(a,b) ((a)<(b)?(b):(a))
#define sched_Min(a,b) ((a)>(b)?(b):(a))
-int sched_get_priority_max(int policy)
+
+int
+sched_get_priority_max(int policy)
{
if (policy < SCHED_MIN || policy > SCHED_MAX)
{
- return EINVAL;
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (policy != SCHED_OTHER)
+ {
+ errno = ENOTSUP;
+ return -1;
}
#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL)
@@ -160,11 +272,20 @@ int sched_get_priority_max(int policy)
#endif
}
-int sched_get_priority_min(int policy)
+
+int
+sched_get_priority_min(int policy)
{
if (policy < SCHED_MIN || policy > SCHED_MAX)
{
- return EINVAL;
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (policy != SCHED_OTHER)
+ {
+ errno = ENOTSUP;
+ return -1;
}
#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL)
@@ -176,7 +297,259 @@ int sched_get_priority_min(int policy)
#endif
}
-int sched_yield(void)
+
+int
+sched_rr_get_interval(pid_t pid, struct timespec * interval)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function updates the timespec structure
+ * referenced by the interval argument to contain
+ * the current quantum for the process executing
+ * under the SCHED_RR policy. If a process, running under
+ * the round-robin scheduling policy, runs without
+ * blocking or yielding for more than this amount of
+ * time, it may be preempted by another runnable
+ * process (at the same priority).
+ *
+ * If the PID argument is zero, the current execution
+ * time limit for the calling process is returned.
+ *
+ * PARAMETERS
+ * pid Process identifier.
+ *
+ *
+ * DESCRIPTION
+ * This function updates the timespec structure
+ * referenced by the interval argument to contain
+ * the current quantum for the process executing
+ * under the SCHED_RR policy. If a process, running under
+ * the round-robin scheduling policy, runs without
+ * blocking or yielding for more than this amount of
+ * time, it may be preempted by another runnable
+ * process (at the same priority).
+ *
+ * If the PID argument is zero, the current execution
+ * time limit for the calling process is returned.
+ *
+ * RESULTS
+ * We don't support SCHED_RR so this routine always fails.
+ *
+ * NOTE: Since this is part of POSIX 1003.1b
+ * (realtime extensions), it is defined as returning
+ * -1 if an error occurs and sets errno to the actual
+ * error.
+ *
+ * errno: ESRCH Pid doesn't refer to a valid process.
+ * EPERM The process referenced by pid does
+ * not allow query access.
+ * ENOTSUP SCHED_RR is not supported.
+ *
+ * ------------------------------------------------------
+ */
+{
+ /*
+ * Provide other valid side-effects
+ * such as EPERM and ESRCH errors.
+ */
+ if (0 != pid)
+ {
+ DWORD selfPid = GetCurrentProcessId();
+
+ if (pid != selfPid)
+ {
+ HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
+
+ if (NULL == h)
+ {
+ errno = (GetLastError() == (0xFF & ERROR_ACCESS_DENIED)
+ ? EPERM
+ : ESRCH );
+
+ return -1;
+ }
+
+ (void) CloseHandle(h);
+ }
+ }
+
+ /*
+ * We can't return ENOSYS and stay strictly compliant with the
+ * standard. We don't support round-robin scheduling so
+ * we return ENOTSUP instead. This is consistent with
+ * routines which return ENOTSUP if SCHED_RR is given
+ * as the policy parameter.
+ */
+ errno = ENOTSUP;
+ return -1;
+}
+
+
+int
+sched_setscheduler(pid_t pid, int policy)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function returns sets the scheduling policy and
+ * scheduling parameters of the process specified by pid
+ * to policy and the parameters specified in the
+ * sched_param structure pointed to by param, respectively.
+ * The value of the sched_priority member in the sched_param
+ * structure is any integer within the inclusive priority
+ * range for the scheduling policy specified by policy.
+ * If the value of pid is negative, the behaviour of the
+ * sched_setscheduler() function is unspecified.
+ *
+ * PARAMETERS
+ * pid Identifier of the process in which the
+ * policy will be set.
+ * policy The new policy value.
+ *
+ *
+ * DESCRIPTION
+ * This function returns sets the scheduling policy and
+ * scheduling parameters of the process specified by pid
+ * to policy and the parameters specified in the
+ * sched_param structure pointed to by param, respectively.
+ * The value of the sched_priority member in the sched_param
+ * structure is any integer within the inclusive priority
+ * range for the scheduling policy specified by policy.
+ * If the value of pid is negative, the behaviour of the
+ * sched_setscheduler() function is unspecified.
+ *
+ * RESULTS
+ * SCHED_OTHER on success this is the only possible
+ * value that can be returned.
+ *
+ * NOTE: Since this is part of POSIX 1003.1b
+ * (realtime extensions), it is defined as returning
+ * -1 if an error occurs and sets errno to the actual
+ * error.
+ *
+ * errno: ESRCH 'pid' doesn't refer to an existing
+ * process.
+ * EPERM The process referenced by pid does
+ * not allow set access.
+ * EINVAL 'policy' is not a valid policy value.
+ * ENOSYS the policy specified is not supported.
+ *
+ * ------------------------------------------------------
+ */
+{
+ /*
+ * Win32 only has one policy which we call SCHED_OTHER.
+ * However, we try to provide other valid side-effects
+ * such as EPERM and ESRCH errors.
+ */
+ if (0 != pid)
+ {
+ DWORD selfPid = GetCurrentProcessId();
+
+ if (pid != selfPid)
+ {
+ HANDLE h = OpenProcess(PROCESS_SET_INFORMATION, FALSE, pid);
+
+ if (NULL == h)
+ {
+ errno = (GetLastError() == (0xFF & ERROR_ACCESS_DENIED)
+ ? EPERM
+ : ESRCH );
+
+ return -1;
+ }
+
+ (void) CloseHandle(h);
+ }
+ }
+
+ if (policy < SCHED_MIN || policy > SCHED_MAX)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (SCHED_OTHER != policy)
+ {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ /*
+ * Don't set anything because there is nothing to set.
+ * Just return the current (the only possible) value.
+ */
+ return SCHED_OTHER;
+}
+
+
+int
+sched_getscheduler(pid_t pid)
+ /*
+ * ------------------------------------------------------
+ * DOCPUBLIC
+ * This function returns the scheduling policy of the
+ * process specified by pid. If the value of pid is
+ * negative, the behaviour of the sched_getscheduler()
+ * function is unspecified.
+ *
+ * PARAMETERS
+ * pid Process identifier.
+ *
+ *
+ * DESCRIPTION
+ * This function returns the scheduling policy of the
+ * process specified by pid. If the value of pid is
+ * negative, the behaviour of the sched_getscheduler()
+ * function is unspecified.
+ *
+ * RESULTS
+ * SCHED_OTHER on success this is the only possible
+ * value that can be returned.
+ *
+ * NOTE: Since this is part of POSIX 1003.1b
+ * (realtime extensions), it is defined as returning
+ * -1 if an error occurs and sets errno to the actual
+ * error.
+ *
+ * errno: ESRCH Pid doesn't refer to a valid process.
+ * EPERM The process referenced by pid does
+ * not allow query access.
+ *
+ * ------------------------------------------------------
+ */
+{
+ /*
+ * Win32 only has one policy which we call SCHED_OTHER.
+ * However, we try to provide other valid side-effects
+ * such as EPERM and ESRCH errors.
+ */
+ if (0 != pid)
+ {
+ DWORD selfPid = GetCurrentProcessId();
+
+ if (pid != selfPid)
+ {
+ HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
+
+ if (NULL == h)
+ {
+ errno = (GetLastError() == (0xFF & ERROR_ACCESS_DENIED)
+ ? EPERM
+ : ESRCH );
+
+ return -1;
+ }
+
+ (void) CloseHandle(h);
+ }
+ }
+
+ return SCHED_OTHER;
+}
+
+
+int
+sched_yield(void)
/*
* ------------------------------------------------------
* DOCPUBLIC
@@ -196,8 +569,7 @@ int sched_yield(void)
* error.
*
* RESULTS
- * 0 successfully created semaphore,
- * ENOSYS sched_yield not supported,
+ * 0 always succeeds
*
* ------------------------------------------------------
*/