From fb146abee047c30501ea8a72ce0bb73bb29f3bc3 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Wed, 21 Dec 2016 14:04:09 -0600 Subject: [PATCH] All CMP platforms: Apply same fix verified on other platforms found on Xtensa. --- arch/arm/src/armv7-a/arm_releasepending.c | 124 +++++++++++++--------- arch/arm/src/armv7-m/up_releasepending.c | 118 +++++++++++--------- arch/sim/src/up_releasepending.c | 92 ++++++++++------ 3 files changed, 200 insertions(+), 134 deletions(-) diff --git a/arch/arm/src/armv7-a/arm_releasepending.c b/arch/arm/src/armv7-a/arm_releasepending.c index 7afc6989a7..364d0a883e 100644 --- a/arch/arm/src/armv7-a/arm_releasepending.c +++ b/arch/arm/src/armv7-a/arm_releasepending.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/armv7-a/arm_releasepending.c * - * Copyright (C) 2013-2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2013-2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -39,8 +39,10 @@ #include +#include #include #include + #include #include @@ -66,79 +68,99 @@ void up_release_pending(void) { struct tcb_s *rtcb = this_task(); +#ifdef CONFIG_SMP + static bool busy = false; +#endif sinfo("From TCB=%p\n", rtcb); - /* Merge the g_pendingtasks list into the ready-to-run task list */ + /* In SMP configurations, this function will be called as part of leaving + * the critical section. In that case, it may be re-entered as part of + * the sched_addreadytorun() processing. We have to guard against that + * case. + */ - /* sched_lock(); */ - if (sched_mergepending()) +#ifdef CONFIG_SMP + if (!busy) { - /* The currently active task has changed! We will need to - * switch contexts. - */ + busy = true; +#endif - /* Update scheduler parameters */ + /* Merge the g_pendingtasks list into the ready-to-run task list */ - sched_suspend_scheduler(rtcb); - - /* Are we operating in interrupt context? */ - - if (CURRENT_REGS) + /* sched_lock(); */ + if (sched_mergepending()) { - /* Yes, then we have to do things differently. - * Just copy the CURRENT_REGS into the OLD rtcb. + /* The currently active task has changed! We will need to + * switch contexts. */ - up_savestate(rtcb->xcp.regs); - - /* Restore the exception context of the rtcb at the (new) head - * of the ready-to-run task list. - */ - - rtcb = this_task(); - /* Update scheduler parameters */ - sched_resume_scheduler(rtcb); + sched_suspend_scheduler(rtcb); - /* Then switch contexts. Any necessary address environment - * changes will be made when the interrupt returns. + /* Are we operating in interrupt context? */ + + if (CURRENT_REGS) + { + /* Yes, then we have to do things differently. + * Just copy the CURRENT_REGS into the OLD rtcb. + */ + + up_savestate(rtcb->xcp.regs); + + /* Restore the exception context of the rtcb at the (new) head + * of the ready-to-run task list. + */ + + rtcb = this_task(); + + /* Update scheduler parameters */ + + sched_resume_scheduler(rtcb); + + /* Then switch contexts. Any necessary address environment + * changes will be made when the interrupt returns. + */ + + up_restorestate(rtcb->xcp.regs); + } + + /* Copy the exception context into the TCB of the task that + * was currently active. if up_saveusercontext returns a non-zero + * value, then this is really the previously running task + * restarting! */ - up_restorestate(rtcb->xcp.regs); - } + else if (!up_saveusercontext(rtcb->xcp.regs)) + { + /* Restore the exception context of the rtcb at the (new) head + * of the ready-to-run task list. + */ - /* Copy the exception context into the TCB of the task that - * was currently active. if up_saveusercontext returns a non-zero - * value, then this is really the previously running task - * restarting! - */ - - else if (!up_saveusercontext(rtcb->xcp.regs)) - { - /* Restore the exception context of the rtcb at the (new) head - * of the ready-to-run task list. - */ - - rtcb = this_task(); + rtcb = this_task(); #ifdef CONFIG_ARCH_ADDRENV - /* Make sure that the address environment for the previously - * running task is closed down gracefully (data caches dump, - * MMU flushed) and set up the address environment for the new - * thread at the head of the ready-to-run list. - */ + /* Make sure that the address environment for the previously + * running task is closed down gracefully (data caches dump, + * MMU flushed) and set up the address environment for the new + * thread at the head of the ready-to-run list. + */ - (void)group_addrenv(rtcb); + (void)group_addrenv(rtcb); #endif - /* Update scheduler parameters */ + /* Update scheduler parameters */ - sched_resume_scheduler(rtcb); + sched_resume_scheduler(rtcb); - /* Then switch contexts */ + /* Then switch contexts */ - up_fullcontextrestore(rtcb->xcp.regs); + up_fullcontextrestore(rtcb->xcp.regs); + } } + +#ifdef CONFIG_SMP + busy = false; } +#endif } diff --git a/arch/arm/src/armv7-m/up_releasepending.c b/arch/arm/src/armv7-m/up_releasepending.c index 83be88094e..bb70243991 100644 --- a/arch/arm/src/armv7-m/up_releasepending.c +++ b/arch/arm/src/armv7-m/up_releasepending.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/armv7-m/up_releasepending.c * - * Copyright (C) 2007-2009, 2012, 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2012, 2015-2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -39,8 +39,10 @@ #include +#include #include #include + #include #include @@ -65,68 +67,88 @@ void up_release_pending(void) { struct tcb_s *rtcb = this_task(); +#ifdef CONFIG_SMP + static bool busy = false; +#endif sinfo("From TCB=%p\n", rtcb); - /* Merge the g_pendingtasks list into the ready-to-run task list */ + /* In SMP configurations, this function will be called as part of leaving + * the critical section. In that case, it may be re-entered as part of + * the sched_addreadytorun() processing. We have to guard against that + * case. + */ - /* sched_lock(); */ - if (sched_mergepending()) +#ifdef CONFIG_SMP + if (!busy) { - /* The currently active task has changed! We will need to switch - * contexts. - */ + busy = true; +#endif - /* Update scheduler parameters */ + /* Merge the g_pendingtasks list into the ready-to-run task list */ - sched_suspend_scheduler(rtcb); - - /* Are we operating in interrupt context? */ - - if (CURRENT_REGS) + /* sched_lock(); */ + if (sched_mergepending()) { - /* Yes, then we have to do things differently. Just copy the - * CURRENT_REGS into the OLD rtcb. + /* The currently active task has changed! We will need to switch + * contexts. */ - up_savestate(rtcb->xcp.regs); - - /* Restore the exception context of the rtcb at the (new) head - * of the ready-to-run task list. - */ - - rtcb = this_task(); - /* Update scheduler parameters */ - sched_resume_scheduler(rtcb); + sched_suspend_scheduler(rtcb); - /* Then switch contexts */ + /* Are we operating in interrupt context? */ - up_restorestate(rtcb->xcp.regs); + if (CURRENT_REGS) + { + /* Yes, then we have to do things differently. Just copy the + * CURRENT_REGS into the OLD rtcb. + */ + + up_savestate(rtcb->xcp.regs); + + /* Restore the exception context of the rtcb at the (new) head + * of the ready-to-run task list. + */ + + rtcb = this_task(); + + /* Update scheduler parameters */ + + sched_resume_scheduler(rtcb); + + /* Then switch contexts */ + + up_restorestate(rtcb->xcp.regs); + } + + /* No, then we will need to perform the user context switch */ + + else + { + struct tcb_s *nexttcb = this_task(); + + /* Update scheduler parameters */ + + sched_resume_scheduler(nexttcb); + + /* Switch context to the context of the task at the head of the + * ready to run list. + */ + + up_switchcontext(rtcb->xcp.regs, nexttcb->xcp.regs); + + /* up_switchcontext forces a context switch to the task at the + * head of the ready-to-run list. It does not 'return' in the + * normal sense. When it does return, it is because the blocked + * task is again ready to run and has execution priority. + */ + } } - /* No, then we will need to perform the user context switch */ - - else - { - struct tcb_s *nexttcb = this_task(); - - /* Update scheduler parameters */ - - sched_resume_scheduler(nexttcb); - - /* Switch context to the context of the task at the head of the - * ready to run list. - */ - - up_switchcontext(rtcb->xcp.regs, nexttcb->xcp.regs); - - /* up_switchcontext forces a context switch to the task at the - * head of the ready-to-run list. It does not 'return' in the - * normal sense. When it does return, it is because the blocked - * task is again ready to run and has execution priority. - */ - } +#ifdef CONFIG_SMP + busy = false; } +#endif } diff --git a/arch/sim/src/up_releasepending.c b/arch/sim/src/up_releasepending.c index 7a1df74827..19d52a0ac7 100644 --- a/arch/sim/src/up_releasepending.c +++ b/arch/sim/src/up_releasepending.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/sim/src/up_releasepending.c * - * Copyright (C) 2007-2009, 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2015-2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -39,8 +39,10 @@ #include +#include #include #include + #include #include @@ -65,55 +67,75 @@ void up_release_pending(void) { FAR struct tcb_s *rtcb = this_task(); +#ifdef CONFIG_SMP + static bool busy = false; +#endif sinfo("From TCB=%p\n", rtcb); - /* Merge the g_pendingtasks list into the ready-to-run task list */ + /* In SMP configurations, this function will be called as part of leaving + * the critical section. In that case, it may be re-entered as part of + * the sched_addreadytorun() processing. We have to guard against that + * case. + */ - /* sched_lock(); */ - if (sched_mergepending()) +#ifdef CONFIG_SMP + if (!busy) { - /* The currently active task has changed! We will need to switch - * contexts. - * - * Update scheduler parameters. - */ + busy = true; +#endif - sched_suspend_scheduler(rtcb); + /* Merge the g_pendingtasks list into the ready-to-run task list */ - /* Copy the exception context into the TCB of the task that was - * currently active. if up_setjmp returns a non-zero value, then - * this is really the previously running task restarting! - */ - - if (!up_setjmp(rtcb->xcp.regs)) + /* sched_lock(); */ + if (sched_mergepending()) { - /* Restore the exception context of the rtcb at the (new) head - * of the ready-to-run task list. + /* The currently active task has changed! We will need to switch + * contexts. + * + * Update scheduler parameters. */ - rtcb = this_task(); - sinfo("New Active Task TCB=%p\n", rtcb); + sched_suspend_scheduler(rtcb); - /* The way that we handle signals in the simulation is kind of - * a kludge. This would be unsafe in a truly multi-threaded, interrupt - * driven environment. + /* Copy the exception context into the TCB of the task that was + * currently active. if up_setjmp returns a non-zero value, then + * this is really the previously running task restarting! */ - if (rtcb->xcp.sigdeliver) + if (!up_setjmp(rtcb->xcp.regs)) { - sinfo("Delivering signals TCB=%p\n", rtcb); - ((sig_deliver_t)rtcb->xcp.sigdeliver)(rtcb); - rtcb->xcp.sigdeliver = NULL; + /* Restore the exception context of the rtcb at the (new) head + * of the ready-to-run task list. + */ + + rtcb = this_task(); + sinfo("New Active Task TCB=%p\n", rtcb); + + /* The way that we handle signals in the simulation is kind of + * a kludge. This would be unsafe in a truly multi-threaded, interrupt + * driven environment. + */ + + if (rtcb->xcp.sigdeliver) + { + sinfo("Delivering signals TCB=%p\n", rtcb); + ((sig_deliver_t)rtcb->xcp.sigdeliver)(rtcb); + rtcb->xcp.sigdeliver = NULL; + } + + /* Update scheduler parameters */ + + sched_resume_scheduler(rtcb); + + /* Then switch contexts */ + + up_longjmp(rtcb->xcp.regs, 1); } - - /* Update scheduler parameters */ - - sched_resume_scheduler(rtcb); - - /* Then switch contexts */ - - up_longjmp(rtcb->xcp.regs, 1); } + +#ifdef CONFIG_SMP + busy = false; } +#endif }