kernel/os/src/os_task.c (149 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include <assert.h> #include <string.h> #include "os/mynewt.h" #include "os_priv.h" uint8_t g_task_id; struct os_task_stailq g_os_task_list; static void _clear_stack(os_stack_t *stack_bottom, int size) { int i; for (i = 0; i < size; i++) { stack_bottom[i] = OS_STACK_PATTERN; } } static inline uint8_t os_task_next_id(void) { uint8_t rc; os_sr_t sr; OS_ENTER_CRITICAL(sr); rc = g_task_id; g_task_id++; OS_EXIT_CRITICAL(sr); return (rc); } uint8_t os_task_count(void) { return (g_task_id); } int os_task_init(struct os_task *t, const char *name, os_task_func_t func, void *arg, uint8_t prio, os_time_t sanity_itvl, os_stack_t *stack_bottom, uint16_t stack_size) { struct os_sanity_check *sc; int rc; struct os_task *task; memset(t, 0, sizeof(*t)); t->t_func = func; t->t_arg = arg; t->t_taskid = os_task_next_id(); t->t_prio = prio; t->t_state = OS_TASK_READY; t->t_name = name; t->t_next_wakeup = 0; rc = os_sanity_check_init(&t->t_sanity_check); if (rc != OS_OK) { goto err; } if (sanity_itvl != OS_WAIT_FOREVER) { sc = (struct os_sanity_check *) &t->t_sanity_check; sc->sc_checkin_itvl = sanity_itvl; rc = os_sanity_check_register(sc); if (rc != OS_OK) { goto err; } } _clear_stack(stack_bottom, stack_size); t->t_stackbottom = stack_bottom; t->t_stacksize = stack_size; t->t_stackptr = os_arch_task_stack_init(t, os_task_stacktop_get(t), t->t_stacksize); STAILQ_FOREACH(task, &g_os_task_list, t_os_task_list) { assert(t->t_prio != task->t_prio); } /* insert this task into the task list */ STAILQ_INSERT_TAIL(&g_os_task_list, t, t_os_task_list); /* insert this task into the scheduler list */ rc = os_sched_insert(t); if (rc != OS_OK) { goto err; } os_trace_task_create(t); os_trace_task_info(t); /* Allow a preemption in case the new task has a higher priority than the * current one. */ if (os_started()) { os_sched(NULL); } return (0); err: return (rc); } os_stack_t * os_task_stacktop_get(struct os_task *t) { return &t->t_stackbottom[t->t_stacksize]; } int os_task_remove(struct os_task *t) { int rc; os_sr_t sr; /* * Can't suspend yourself */ if (t == os_sched_get_current_task()) { return OS_INVALID_PARM; } /* * If state is not READY or SLEEP, assume task has not been initialized */ if (t->t_state != OS_TASK_READY && t->t_state != OS_TASK_SLEEP) { return OS_NOT_STARTED; } /* * Disallow suspending tasks which are waiting on a lock */ if (t->t_flags & (OS_TASK_FLAG_SEM_WAIT | OS_TASK_FLAG_MUTEX_WAIT | OS_TASK_FLAG_EVQ_WAIT)) { return OS_EBUSY; } /* * Disallowing suspending tasks which are holding a mutex */ if (t->t_lockcnt) { return OS_EBUSY; } OS_ENTER_CRITICAL(sr); rc = os_sched_remove(t); OS_EXIT_CRITICAL(sr); return rc; } void os_task_info_get(const struct os_task *task, struct os_task_info *oti) { os_stack_t *bottom; os_stack_t *top; oti->oti_prio = task->t_prio; oti->oti_taskid = task->t_taskid; oti->oti_state = task->t_state; bottom = task->t_stackbottom; top = bottom + task->t_stacksize; while (bottom < top) { if (*bottom != OS_STACK_PATTERN) { break; } ++bottom; } oti->oti_stkusage = (uint16_t) (top - bottom); oti->oti_stksize = task->t_stacksize; oti->oti_cswcnt = task->t_ctx_sw_cnt; oti->oti_runtime = task->t_run_time; oti->oti_last_checkin = task->t_sanity_check.sc_checkin_last; oti->oti_next_checkin = task->t_sanity_check.sc_checkin_last + task->t_sanity_check.sc_checkin_itvl; oti->oti_name[0] = '\0'; strncat(oti->oti_name, task->t_name, sizeof(oti->oti_name) - 1); } struct os_task * os_task_info_get_next(const struct os_task *prev, struct os_task_info *oti) { struct os_task *next; if (prev != NULL) { next = STAILQ_NEXT(prev, t_os_task_list); } else { next = STAILQ_FIRST(&g_os_task_list); } if (next) { os_task_info_get(next, oti); } return next; }