sched/: Fix several inappropriate accesses to get_errno() that were missed in previous changes (some going back to nuttx-.23). Add new nxsched_setscheduler() and nxsched_getaffinity() which are equivalent to their counterparts without the nx on front. These versions do not modify the errno value. Changed all calls within the OS to use these newer versions of the functions.

This commit is contained in:
Gregory Nutt 2018-01-30 16:16:41 -06:00
parent 170a50c690
commit 82982f7972
15 changed files with 279 additions and 110 deletions

14
TODO
View File

@ -170,6 +170,9 @@ o Task/Scheduler (sched/)
to make this change: Just move the pterrno field from
struct tcb_s to struct task_group_s. However, I am still not
sure if this should be done or not.
NOTE: glibc behaves this way unless __thread is defined then,
in that case, it behaves like NuttX (using TLS to save the
thread local errno).
Status: Closed. The existing solution is better (although its
incompatibilities could show up in porting some code).
Priority: Low
@ -255,13 +258,14 @@ o Task/Scheduler (sched/)
message queue used in the OS. I am keeping this issue
open because (1) there are some known remaining calls that
that will modify the errno (such as dup(), dup2(),
task_activate(), mq_open(), mq_close(), and others) and
(2) there may still be calls that create cancellation
points. Need to check things like open(), close(), read(),
write(), and possibly others.
task_create(), task_activate(), kthread_create(), exec(), mq_open(),
mq_close(), and others) and (2) there may still be calls that
create cancellation points. Need to check things like open(),
close(), read(), write(), and possibly others.
2018-01-30: This change has been completed for the case of
scheduler functions used within the OS: sched_getparam(),
sched_setparam(), sched_getscheduler(), and sched_setaffinity(),
sched_setparam(), sched_getscheduler(), sched_setschedule(),
and sched_setaffinity(),
Status: Open
Priority: Low. Things are working OK the way they are. But the design

View File

@ -474,7 +474,7 @@ FAR struct i2s_dev_s *lc823450_i2sdev_initialize(void)
/* Backup the current affinity */
sched_getaffinity(getpid(), sizeof(cpuset0), &cpuset0);
(void)nxsched_getaffinity(getpid(), sizeof(cpuset0), &cpuset0);
/* Set the new affinity which assigns to CPU0 */

View File

@ -191,19 +191,23 @@
*/
#if defined(CONFIG_BUILD_FLAT) || defined(__KERNEL__)
# define _SCHED_GETPARAM(t,p) nxsched_getparam(t,p)
# define _SCHED_SETPARAM(t,p) nxsched_setparam(t,p)
# define _SCHED_GETSCHEDULER(t) nxsched_getscheduler(t)
# define _SCHED_SETAFFINITY(t,c,m) nxsched_setaffinity(t,c,m)
# define _SCHED_ERRNO(r) (-(r))
# define _SCHED_ERRVAL(r) (r)
# define _SCHED_GETPARAM(t,p) nxsched_getparam(t,p)
# define _SCHED_SETPARAM(t,p) nxsched_setparam(t,p)
# define _SCHED_GETSCHEDULER(t) nxsched_getscheduler(t)
# define _SCHED_SETSCHEDULER(t,s,p) nxsched_setscheduler(t,s,p)
# define _SCHED_GETAFFINITY(t,c,m) nxsched_getaffinity(t,c,m)
# define _SCHED_SETAFFINITY(t,c,m) nxsched_setaffinity(t,c,m)
# define _SCHED_ERRNO(r) (-(r))
# define _SCHED_ERRVAL(r) (r)
#else
# define _SCHED_GETPARAM(t,p) sched_getparam(t,p)
# define _SCHED_SETPARAM(t,p) sched_setparam(t,p)
# define _SCHED_GETSCHEDULER(t) sched_getscheduler(t)
# define _SCHED_SETAFFINITY(t,c,m) sched_setaffinity(t,c,m)
# define _SCHED_ERRNO(r) errno
# define _SCHED_ERRVAL(r) (-errno)
# define _SCHED_GETPARAM(t,p) sched_getparam(t,p)
# define _SCHED_SETPARAM(t,p) sched_setparam(t,p)
# define _SCHED_GETSCHEDULER(t) sched_getscheduler(t)
# define _SCHED_SETSCHEDULER(t,s,p) sched_setscheduler(t,s,p)
# define _SCHED_GETAFFINITY(t,c,m) sched_getaffinity(t,c,m)
# define _SCHED_SETAFFINITY(t,c,m) sched_setaffinity(t,c,m)
# define _SCHED_ERRNO(r) errno
# define _SCHED_ERRVAL(r) (-errno)
#endif
/********************************************************************************
@ -1006,6 +1010,76 @@ int nxsched_setparam(pid_t pid, FAR const struct sched_param *param);
int nxsched_getscheduler(pid_t pid);
/****************************************************************************
* Name: nxsched_setscheduler
*
* Description:
* nxsched_setscheduler() sets both the scheduling policy and the priority
* for the task identified by pid. If pid equals zero, the scheduler of
* the calling task will be set. The parameter 'param' holds the priority
* of the thread under the new policy.
*
* nxsched_setscheduler() is identical to the function sched_getparam(),
* differing only in its return value: This function does not modify the
* errno variable.
*
* This is a non-standard, internal OS function and is not intended for
* use by application logic. Applications should use the standard
* sched_getparam().
*
* Input Parameters:
* pid - the task ID of the task to modify. If pid is zero, the calling
* task is modified.
* policy - Scheduling policy requested (either SCHED_FIFO or SCHED_RR)
* param - A structure whose member sched_priority is the new priority.
* The range of valid priority numbers is from SCHED_PRIORITY_MIN
* through SCHED_PRIORITY_MAX.
*
* Returned Value:
* On success, nxsched_setscheduler() returns OK (zero). On error, a
* negated errno value is returned:
*
* EINVAL The scheduling policy is not one of the recognized policies.
* ESRCH The task whose ID is pid could not be found.
*
****************************************************************************/
int nxsched_setscheduler(pid_t pid, int policy,
FAR const struct sched_param *param);
/****************************************************************************
* Name: nxsched_getaffinity
*
* Description:
* nxsched_getaffinity() writes the affinity mask of the thread whose ID
* is pid into the cpu_set_t pointed to by mask. The cpusetsize
* argument specifies the size (in bytes) of mask. If pid is zero, then
* the mask of the calling thread is returned.
*
* nxsched_getaffinity() is identical to the function sched_getaffinity(),
* differing only in its return value: This function does not modify the
* errno variable.
*
* This is a non-standard, internal OS function and is not intended for
* use by application logic. Applications should use the standard
* sched_getparam().
*
* Input Parameters:
* pid - The ID of thread whose affinity set will be retrieved.
* cpusetsize - Size of mask. MUST be sizeofcpu_set_t().
* mask - The location to return the thread's new affinity set.
*
* Returned Value:
* Zero (OK) if successful. Otherwise, a negated errno value is returned:
*
* ESRCH The task whose ID is pid could not be found.
*
****************************************************************************/
#ifdef CONFIG_SMP
int nxsched_getaffinity(pid_t pid, size_t cpusetsize, FAR cpu_set_t *mask);
#endif
/****************************************************************************
* Name: nxsched_setaffinity
*
@ -1027,15 +1101,14 @@ int nxsched_getscheduler(pid_t pid);
* use the standard sched_setparam().
*
* Inputs:
* pid - The ID of thread whose affinity set will be modified.
* cpusetsize - Size of cpuset. MUST be sizeofcpu_set_t().
* pid - The ID of thread whose affinity set will be modified.
* cpusetsize - Size of mask. MUST be sizeofcpu_set_t().
* mask - The location to return the thread's new affinity set.
*
* Return Value:
* 0 if successful. Otherwise, ERROR (-1) is returned, and errno is
* set appropriately:
* Zero (OK) if successful. Otherwise, a negated errno value is returned:
*
* ESRCH The task whose ID is pid could not be found.
* ESRCH The task whose ID is pid could not be found.
*
****************************************************************************/

View File

@ -529,7 +529,7 @@ int pthread_create(FAR pthread_t *thread, FAR const pthread_attr_t *attr,
if (ret < 0)
{
ret = get_errno();
ret = -ret;
}
}

View File

@ -1,7 +1,7 @@
/****************************************************************************
* sched/pthread/pthread_getaffinity.c
*
* Copyright (C) 2016 Gregory Nutt. All rights reserved.
* Copyright (C) 2016, 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -45,6 +45,8 @@
#include <errno.h>
#include <debug.h>
#include <nuttx/sched.h>
#include "pthread/pthread.h"
#ifdef CONFIG_SMP
@ -86,15 +88,14 @@ int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize,
DEBUGASSERT(thread > 0 && cpusetsize == sizeof(cpu_set_t) &&
cpuset != NULL);
/* Let sched_getaffinity do all of the work */
/* Let nxsched_getaffinity do all of the work */
ret = sched_getaffinity((pid_t)thread, cpusetsize, cpuset);
ret = nxsched_getaffinity((pid_t)thread, cpusetsize, cpuset);
if (ret < 0)
{
/* If sched_getaffinity() fails, return the errno */
/* If nxsched_getaffinity() fails, return the positive errno */
ret = get_errno();
DEBUGASSERT(ret > 0);
ret = -ret;
}
return ret;

View File

@ -164,6 +164,8 @@ int pthread_sem_trytake(sem_t *sem)
int pthread_sem_give(sem_t *sem)
{
int ret;
/* Verify input parameters */
@ -172,16 +174,13 @@ int pthread_sem_give(sem_t *sem)
{
/* Give the semaphore */
if (nxsem_post(sem) == OK)
ret = nxsem_post(sem);
if (ret < 0)
{
return OK;
return -ret;
}
else
{
/* nxsem_post() reported an error */
return get_errno();
}
return OK;
}
else
{

View File

@ -129,7 +129,14 @@ int pthread_mutex_consistent(FAR pthread_mutex_t *mutex)
*/
status = nxsem_reset((FAR sem_t *)&mutex->sem, 1);
ret = (status != OK) ? get_errno() : OK;
if (status < 0)
{
ret = -status;
}
else
{
ret = OK;
}
}
/* Otherwise the mutex is held by some active thread. Let's not

View File

@ -119,18 +119,18 @@ int pthread_mutex_init(FAR pthread_mutex_t *mutex,
/* Initialize the mutex like a semaphore with initial count = 1 */
status = nxsem_init((FAR sem_t *)&mutex->sem, pshared, 1);
if (status != OK)
if (status < 0)
{
ret = get_errno();
ret = -ret;
}
#ifdef CONFIG_PRIORITY_INHERITANCE
/* Initialize the semaphore protocol */
status = nxsem_setprotocol((FAR sem_t *)&mutex->sem, proto);
if (status != OK)
if (status < 0)
{
ret = get_errno();
ret = -status;
}
#endif

View File

@ -38,12 +38,16 @@
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <pthread.h>
#include <sched.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/sched.h>
#include "pthread/pthread.h"
/****************************************************************************
@ -95,8 +99,6 @@
* specified.
* ESRCH The value specified by thread does not refer to a existing thread.
*
* Assumptions:
*
****************************************************************************/
int pthread_setschedparam(pthread_t thread, int policy,
@ -106,14 +108,14 @@ int pthread_setschedparam(pthread_t thread, int policy,
sinfo("thread ID=%d policy=%d param=0x%p\n", thread, policy, param);
/* Let sched_setscheduler do all of the work */
/* Let nxsched_setscheduler do all of the work */
ret = sched_setscheduler((pid_t)thread, policy, param);
if (ret != OK)
ret = nxsched_setscheduler((pid_t)thread, policy, param);
if (ret < 0)
{
/* If sched_setscheduler() fails, return the errno */
/* If nxsched_setscheduler() fails, return the positive errno value */
ret = get_errno();
ret = -ret;
}
return ret;

View File

@ -171,7 +171,7 @@ extern volatile dq_queue_t g_readytorun;
* and
* - Tasks/threads that have not been assigned to a CPU.
*
* Otherwise, the TCB will be reatined in an assigned task list,
* Otherwise, the TCB will be retained in an assigned task list,
* g_assignedtasks. As its name suggests, on 'g_assignedtasks queue for CPU
* 'n' would contain only tasks/threads that are assigned to CPU 'n'. Tasks/
* threads would be assigned a particular CPU by one of two mechanisms:
@ -285,7 +285,7 @@ extern struct pidhash_s g_pidhash[CONFIG_MAX_TASKS];
/* This is a table of task lists. This table is indexed by the task stat
* enumeration type (tstate_t) and provides a pointer to the associated
* static task list (if there is one) as well as a a set of attribute flags
* indicating properities of the list, for example, if the list is an
* indicating properties of the list, for example, if the list is an
* ordered list or not.
*/

View File

@ -53,37 +53,45 @@
****************************************************************************/
/****************************************************************************
* Name: sched_getaffinity
* Name: nxsched_getaffinity
*
* Description:
* sched_getaffinity() writes the affinity mask of the thread whose ID
* nxsched_getaffinity() writes the affinity mask of the thread whose ID
* is pid into the cpu_set_t pointed to by mask. The cpusetsize
* argument specifies the size (in bytes) of mask. If pid is zero, then
* the mask of the calling thread is returned.
*
* Inputs:
* pid - The ID of thread whose affinity set will be retrieved.
* cpusetsize - Size of cpuset. MUST be sizeofcpu_set_t().
* cpuset - The location to return the thread's new affinity set.
* nxsched_getaffinity() is identical to the function sched_getaffinity(),
* differing only in its return value: This function does not modify the
* errno variable.
*
* Return Value:
* 0 if successful. Otherwise, ERROR (-1) is returned, and errno is
* set appropriately:
* This is a non-standard, internal OS function and is not intended for
* use by application logic. Applications should use the standard
* sched_getparam().
*
* Input Parameters:
* pid - The ID of thread whose affinity set will be retrieved.
* cpusetsize - Size of mask. MUST be sizeofcpu_set_t().
* mask - The location to return the thread's new affinity set.
*
* Returned Value:
* Zero (OK) if successful. Otherwise, a negated errno value is returned:
*
* ESRCH The task whose ID is pid could not be found.
*
****************************************************************************/
int sched_getaffinity(pid_t pid, size_t cpusetsize, FAR cpu_set_t *mask)
int nxsched_getaffinity(pid_t pid, size_t cpusetsize, FAR cpu_set_t *mask)
{
FAR struct tcb_s *tcb;
int ret;
DEBUGASSERT(cpusetsize == sizeof(cpu_set_t) && mask != NULL);
/* Verify that the PID corresponds to a real task */
sched_lock();
if (!pid)
if (pid == 0)
{
tcb = this_task();
}
@ -94,13 +102,53 @@ int sched_getaffinity(pid_t pid, size_t cpusetsize, FAR cpu_set_t *mask)
if (tcb == NULL)
{
set_errno(ESRCH);
return ERROR;
ret = -ESRCH;
}
else
{
/* Return the affinity mask from the TCB. */
*mask = tcb->affinity;
ret = OK;
}
/* Return the affinity mask from the TCB. */
*mask = tcb->affinity;
sched_unlock();
return OK;
return ret;
}
/****************************************************************************
* Name: sched_getaffinity
*
* Description:
* sched_getaffinity() writes the affinity mask of the thread whose ID
* is pid into the cpu_set_t pointed to by mask. The cpusetsize
* argument specifies the size (in bytes) of mask. If pid is zero, then
* the mask of the calling thread is returned.
*
* This function is a simply wrapper around nxsched_getaffinity() that
* sets the errno value in the event of an error.
*
* Input Parameters:
* pid - The ID of thread whose affinity set will be retrieved.
* cpusetsize - Size of mask. MUST be sizeofcpu_set_t().
* mask - The location to return the thread's new affinity set.
*
* Returned Value:
* 0 if successful. Otherwise, ERROR (-1) is returned, and errno is
* set appropriately:
*
* ESRCH The task whose ID is pid could not be found.
*
****************************************************************************/
int sched_getaffinity(pid_t pid, size_t cpusetsize, FAR cpu_set_t *mask)
{
int ret = nxsched_getaffinity(pid, cpusetsize, mask);
if (ret < 0)
{
set_errno(-ret);
ret = ERROR;
}
return ret;
}

View File

@ -192,4 +192,3 @@ int sched_getparam (pid_t pid, FAR struct sched_param *param)
return ret;
}

View File

@ -73,15 +73,14 @@
* use the standard sched_setparam().
*
* Inputs:
* pid - The ID of thread whose affinity set will be modified.
* cpusetsize - Size of cpuset. MUST be sizeofcpu_set_t().
* pid - The ID of thread whose affinity set will be modified.
* cpusetsize - Size of mask. MUST be sizeofcpu_set_t().
* mask - The location to return the thread's new affinity set.
*
* Return Value:
* 0 if successful. Otherwise, ERROR (-1) is returned, and errno is
* set appropriately:
* Zero (OK) if successful. Otherwise, a negated errno value is returned:
*
* ESRCH The task whose ID is pid could not be found.
* ESRCH The task whose ID is pid could not be found.
*
****************************************************************************/
@ -182,15 +181,15 @@ errout_with_lock:
* the errno value in the event of an error.
*
* Inputs:
* pid - The ID of thread whose affinity set will be modified.
* cpusetsize - Size of cpuset. MUST be sizeofcpu_set_t().
* pid - The ID of thread whose affinity set will be modified.
* cpusetsize - Size of mask. MUST be sizeofcpu_set_t().
* mask - The location to return the thread's new affinity set.
*
* Return Value:
* 0 if successful. Otherwise, ERROR (-1) is returned, and errno is
* set appropriately:
*
* ESRCH The task whose ID is pid could not be found.
* ESRCH The task whose ID is pid could not be found.
*
****************************************************************************/

View File

@ -46,6 +46,7 @@
#include <assert.h>
#include <errno.h>
#include <nuttx/sched.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
@ -57,15 +58,23 @@
****************************************************************************/
/****************************************************************************
* Name: sched_setscheduler
* Name: nxsched_setscheduler
*
* Description:
* sched_setscheduler() sets both the scheduling policy and the priority
* nxsched_setscheduler() sets both the scheduling policy and the priority
* for the task identified by pid. If pid equals zero, the scheduler of
* the calling task will be set. The parameter 'param' holds the priority
* of the thread under the new policy.
*
* Inputs:
* nxsched_setscheduler() is identical to the function sched_getparam(),
* differing only in its return value: This function does not modify the
* errno variable.
*
* This is a non-standard, internal OS function and is not intended for
* use by application logic. Applications should use the standard
* sched_getparam().
*
* Input Parameters:
* pid - the task ID of the task to modify. If pid is zero, the calling
* task is modified.
* policy - Scheduling policy requested (either SCHED_FIFO or SCHED_RR)
@ -73,23 +82,20 @@
* The range of valid priority numbers is from SCHED_PRIORITY_MIN
* through SCHED_PRIORITY_MAX.
*
* Return Value:
* On success, sched_setscheduler() returns OK (zero). On error, ERROR
* (-1) is returned, and errno is set appropriately:
* Returned Value:
* On success, nxsched_setscheduler() returns OK (zero). On error, a
* negated errno value is returned:
*
* EINVAL The scheduling policy is not one of the recognized policies.
* ESRCH The task whose ID is pid could not be found.
*
* Assumptions:
*
****************************************************************************/
int sched_setscheduler(pid_t pid, int policy,
FAR const struct sched_param *param)
int nxsched_setscheduler(pid_t pid, int policy,
FAR const struct sched_param *param)
{
FAR struct tcb_s *tcb;
irqstate_t flags;
int errcode;
int ret;
/* Check for supported scheduling policy */
@ -103,8 +109,7 @@ int sched_setscheduler(pid_t pid, int policy,
#endif
)
{
set_errno(EINVAL);
return ERROR;
return -EINVAL;
}
/* Check if the task to modify the calling task */
@ -119,8 +124,7 @@ int sched_setscheduler(pid_t pid, int policy,
tcb = sched_gettcb(pid);
if (!tcb)
{
set_errno(ESRCH);
return ERROR;
return -ESRCH;
}
/* Prohibit any context switches while we muck with priority and scheduler
@ -137,6 +141,7 @@ int sched_setscheduler(pid_t pid, int policy,
{
default:
DEBUGPANIC();
case SCHED_FIFO:
{
#ifdef CONFIG_SCHED_SPORADIC
@ -185,7 +190,7 @@ int sched_setscheduler(pid_t pid, int policy,
if (param->sched_ss_max_repl < 1 ||
param->sched_ss_max_repl > CONFIG_SCHED_SPORADIC_MAXREPL)
{
errcode = EINVAL;
ret = -EINVAL;
goto errout_with_irq;
}
@ -219,7 +224,7 @@ int sched_setscheduler(pid_t pid, int policy,
if (repl_ticks < budget_ticks)
#endif
{
errcode = EINVAL;
ret = -EINVAL;
goto errout_with_irq;
}
@ -259,7 +264,6 @@ int sched_setscheduler(pid_t pid, int policy,
if (ret < 0)
{
errcode = -ret;
goto errout_with_irq;
}
}
@ -278,22 +282,55 @@ int sched_setscheduler(pid_t pid, int policy,
/* Set the new priority */
ret = nxsched_reprioritize(tcb, param->sched_priority);
if (ret < 0)
{
errcode = -ret;
goto errout_with_lock;
}
sched_unlock();
return OK;
return ret;
#ifdef CONFIG_SCHED_SPORADIC
errout_with_irq:
leave_critical_section(flags);
#endif
errout_with_lock:
set_errno(errcode);
sched_unlock();
return ERROR;
return ret;
#endif
}
/****************************************************************************
* Name: sched_setscheduler
*
* Description:
* sched_setscheduler() sets both the scheduling policy and the priority
* for the task identified by pid. If pid equals zero, the scheduler of
* the calling task will be set. The parameter 'param' holds the priority
* of the thread under the new policy.
*
* This function is a simply wrapper around nxsched_getparam() that
* sets the errno value in the event of an error.
*
* Input Parameters:
* pid - the task ID of the task to modify. If pid is zero, the calling
* task is modified.
* policy - Scheduling policy requested (either SCHED_FIFO or SCHED_RR)
* param - A structure whose member sched_priority is the new priority.
* The range of valid priority numbers is from SCHED_PRIORITY_MIN
* through SCHED_PRIORITY_MAX.
*
* Returned Value:
* On success, sched_setscheduler() returns OK (zero). On error, ERROR
* (-1) is returned, and errno is set appropriately:
*
* EINVAL The scheduling policy is not one of the recognized policies.
* ESRCH The task whose ID is pid could not be found.
*
****************************************************************************/
int sched_setscheduler(pid_t pid, int policy,
FAR const struct sched_param *param)
{
int ret = nxsched_setscheduler(pid, policy, param);
if (ret < 0)
{
set_errno(-ret);
ret = ERROR;
}
return ret;
}

View File

@ -240,7 +240,7 @@ int spawn_execattrs(pid_t pid, FAR const posix_spawnattr_t *attr)
param.sched_priority = attr->priority;
/* If we are setting *both* the priority and the scheduler,
* then we will call sched_setscheduler() below.
* then we will call nxsched_setscheduler() below.
*/
if ((attr->flags & POSIX_SPAWN_SETSCHEDULER) == 0)
@ -258,7 +258,7 @@ int spawn_execattrs(pid_t pid, FAR const posix_spawnattr_t *attr)
/* If we are only changing the scheduling policy, then reset
* the priority to the default value (the same as this thread) in
* preparation for the sched_setscheduler() call below.
* preparation for the nxsched_setscheduler() call below.
*/
else if ((attr->flags & POSIX_SPAWN_SETSCHEDULER) != 0)
@ -289,7 +289,7 @@ int spawn_execattrs(pid_t pid, FAR const posix_spawnattr_t *attr)
param.sched_ss_init_budget.tv_sec = attr->budget.tv_sec;
param.sched_ss_init_budget.tv_nsec = attr->budget.tv_nsec;
#endif
(void)sched_setscheduler(pid, attr->policy, &param);
(void)nxsched_setscheduler(pid, attr->policy, &param);
}
return OK;