Move CONFIG_MAX_TASKS check at earlier stage of task/thread creation
authorpradeep.ns <pradeep.ns@samsung.com>
Mon, 19 Jun 2017 17:08:13 +0000 (22:38 +0530)
committerpradeep.ns <pradeep.ns@samsung.com>
Thu, 29 Jun 2017 07:01:54 +0000 (12:31 +0530)
Existing overhead:
-----------------
Currently following steps involved before returning error.
1) Allocates the kernel memory for tcb struct
2) Allocates the user/kernel stack memory
3) Allocates the memory for group using group_allocate()
4) Associates file descriptors with the new task
5) Try to assign the pid for the new task
6) task_assignpid() does a check and returns error if already CONFIG_MAX_TASKS are alive in the system.
7) Once the error is returned, OS calles sched_release_tcb to deallocate/freeup the tcb, stack and group memory.

This feature address above concern as follows.
1) Tracks the number of tasks alive in the system at any point of time
2) Makes the early check, whether CONFIG_MAX_TASKS are already alive in the system, before proceeding further
3) If already CONFIG_MAX_TASKS are alive in the system, just return with ERROR

This avoids the overhead in the OS which is mentioned in the top 1 to 7

Signed-off-by: pradeep.ns <pradeep.ns@samsung.com>
os/kernel/init/os_start.c
os/kernel/sched/sched.h
os/kernel/sched/sched_releasetcb.c
os/kernel/task/task_create.c
os/kernel/task/task_setup.c

index 9a5a003..b5daaa9 100644 (file)
@@ -176,6 +176,12 @@ volatile sq_queue_t g_delayed_kufree;
 volatile sq_queue_t g_delayed_kfree;
 #endif
 
+/* This gives number of alive tasks at any point of time in the system.
+ * If the system is already running CONFIG_MAX_TASKS, Creating new
+ * task is not supported.
+ */
+volatile uint8_t g_alive_taskcount;
+
 /* This is the value of the last process ID assigned to a task */
 
 volatile pid_t g_lastpid;
@@ -305,6 +311,9 @@ void os_start(void)
        g_pidhash[PIDHASH(0)].tcb = &g_idletcb.cmn;
        g_pidhash[PIDHASH(0)].pid = 0;
 
+       /* Increment the g_alive_taskcount as first task "idle task" is created */
+       g_alive_taskcount++;
+
        /* Initialize the IDLE task TCB *******************************************/
        /* Initialize a TCB for this thread of execution.  NOTE:  The default
         * value for most components of the g_idletcb are zero.  The entire
index 0ad892c..5d8ed0f 100644 (file)
@@ -192,6 +192,12 @@ extern volatile dq_queue_t g_waitingforfill;
 
 extern volatile dq_queue_t g_inactivetasks;
 
+/* This gives number of alive tasks at any point of time in the system.
+ * If the system is already running CONFIG_MAX_TASKS, Creating new
+ * task is not supported.
+ */
+extern volatile uint8_t g_alive_taskcount;
+
 /* These are lists of dayed memory deallocations that need to be handled
  * within the IDLE loop or worker thread.  These deallocations get queued
  * by sched_kufree and sched_kfree() if the OS needs to deallocate memory
index aa18e15..5adb943 100644 (file)
@@ -102,6 +102,8 @@ static void sched_releasepid(pid_t pid)
        g_cpuload_total -= g_pidhash[hash_ndx].ticks;
        g_pidhash[hash_ndx].ticks = 0;
 #endif
+       /* Decrement the alive task count as task is exiting */
+       g_alive_taskcount--;
 }
 
 /************************************************************************
index d513cb7..89f50de 100644 (file)
  *                parameters are required, argv may be NULL.
  *
  * Return Value:
- *   Returns the non-zero process ID of the new task or ERROR if memory is
- *   insufficient or the task cannot be created.  The errno will be set to
- *   indicate the nature of the error (always ENOMEM).
+ *   Returns the non-zero process ID of the new task on success
+ *   ERROR on failure. The errno will be set to indicate the nature of the error.
+ *
+ *   This function can fail for three reasons.
+ *   1) If the memory is insufficient, errno = ENOMEM
+ *   2) If requested priority is beyond the allowed range, errno = EINVAL
+ *   3) If it is unable to assign a new, unique task ID to the TCB. errno = EBUSY
  *
  ****************************************************************************/
 
@@ -127,6 +131,13 @@ static int thread_create(FAR const char *name, uint8_t ttype, int priority, int
 
        trace_begin(TTRACE_TAG_TASK, "thread_create");
 
+       /* Check whether we are allowed to create new task ? */
+       if (g_alive_taskcount == CONFIG_MAX_TASKS) {
+               sdbg("ERROR: CONFIG_MAX_TASKS(%d) count reached\n",CONFIG_MAX_TASKS);
+               errcode = EBUSY;
+               goto errout;
+       }
+
        /* Allocate a TCB for the new task. */
 
        tcb = (FAR struct task_tcb_s *)kmm_zalloc(sizeof(struct task_tcb_s));
@@ -247,9 +258,13 @@ errout:
  *                parameters are required, argv may be NULL.
  *
  * Return Value:
- *   Returns the non-zero process ID of the new task or ERROR if memory is
- *   insufficient or the task cannot be created.  The errno will be set to
- *   indicate the nature of the error (always ENOMEM).
+ *   Returns the non-zero process ID of the new task on success
+ *   ERROR on failure. The errno will be set to indicate the nature of the error.
+ *
+ *   This function can fail for three reasons.
+ *   1) If the memory is insufficient, errno = ENOMEM
+ *   2) If requested priority is beyond the allowed range, errno = EINVAL
+ *   3) If it is unable to assign a new, unique task ID to the TCB. errno = EBUSY
  *
  ****************************************************************************/
 
index ea88767..b4dad45 100644 (file)
@@ -166,6 +166,9 @@ static int task_assignpid(FAR struct tcb_s *tcb)
 #endif
                        tcb->pid = next_pid;
 
+                       /* Increment the task count */
+                       g_alive_taskcount++;
+
                        (void)sched_unlock();
                        trace_end(TTRACE_TAG_TASK);
                        return OK;