diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Kconfig | 14 | ||||
| -rw-r--r-- | src/SConscript | 13 | ||||
| -rw-r--r-- | src/clock.c | 31 | ||||
| -rw-r--r-- | src/components.c | 9 | ||||
| -rw-r--r-- | src/device.c | 33 | ||||
| -rw-r--r-- | src/idle.c | 79 | ||||
| -rwxr-xr-x[-rw-r--r--] | src/ipc.c | 249 | ||||
| -rw-r--r-- | src/kservice.c | 29 | ||||
| -rw-r--r-- | src/memheap.c | 121 | ||||
| -rw-r--r-- | src/mempool.c | 12 | ||||
| -rw-r--r-- | src/object.c | 14 | ||||
| -rw-r--r-- | src/scheduler.c | 42 | ||||
| -rw-r--r-- | src/thread.c | 209 | ||||
| -rw-r--r-- | src/timer.c | 111 |
14 files changed, 636 insertions, 330 deletions
diff --git a/src/Kconfig b/src/Kconfig index 63a7a67887..803c827e51 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -270,6 +270,18 @@ menu "Memory Management" config RT_USING_MEMHEAP_AS_HEAP bool "Use all of memheap objects as heap" endif + + config RT_USING_USERHEAP + bool "Use user heap" + help + If this option is selected, please implement these functions: + rt_malloc(), rt_malloc_sethook() + rt_free(), rt_free_sethook() + rt_calloc(), rt_realloc() + rt_system_heap_init() + + And if FinSH is used at the same time, please implement list_mem() + endchoice if RT_USING_SMALL_MEM @@ -294,7 +306,7 @@ menu "Memory Management" default y if RT_USING_SMALL_MEM default y if RT_USING_SLAB default y if RT_USING_MEMHEAP_AS_HEAP - + default y if RT_USING_USERHEAP endmenu menu "Kernel Device Object" diff --git a/src/SConscript b/src/SConscript index 82c3b8aaf1..68523978d6 100644 --- a/src/SConscript +++ b/src/SConscript @@ -6,9 +6,6 @@ src = Glob('*.c') CPPPATH = [RTT_ROOT + '/include'] -if GetDepend('RT_USING_MODULE') == False: - SrcRemove(src, ['module.c']) - if GetDepend('RT_USING_HEAP') == False or GetDepend('RT_USING_SMALL_MEM') == False: SrcRemove(src, ['mem.c']) @@ -23,12 +20,20 @@ if GetDepend('RT_USING_MEMHEAP') == False: if GetDepend('RT_USING_MEMHEAP_AS_HEAP'): SrcRemove(src, ['mem.c']) +if GetDepend('RT_USING_USERHEAP'): + SrcRemove(src, ['mem.c', 'slab.c']) + +if GetDepend('RT_USING_SIGNALS') == False: + SrcRemove(src, ['signal.c']) + if GetDepend('RT_USING_DEVICE') == False: SrcRemove(src, ['device.c']) if GetDepend('RT_USING_SMP') == False: SrcRemove(src, ['cpu.c']) -group = DefineGroup('Kernel', src, depend = [''], CPPPATH = CPPPATH) +CPPDEFINES = ['__RTTHREAD__'] + +group = DefineGroup('Kernel', src, depend = [''], CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES) Return('group') diff --git a/src/clock.c b/src/clock.c index 97a09ddeaf..66923e5c00 100644 --- a/src/clock.c +++ b/src/clock.c @@ -13,6 +13,7 @@ * 2010-07-13 Bernard fix rt_tick_from_millisecond issue found by kuronca * 2011-06-26 Bernard add rt_tick_set function. * 2018-11-22 Jesven add per cpu tick + * 2020-12-29 Meco Man add function rt_tick_get_millisecond() */ #include <rthw.h> @@ -25,17 +26,6 @@ static rt_tick_t rt_tick = 0; #endif /** - * This function will initialize system tick and set it to zero. - * @ingroup SystemInit - * - * @deprecated since 1.1.0, this function does not need to be invoked - * in the system initialization. - */ -void rt_system_tick_init(void) -{ -} - -/** * @addtogroup Clock */ @@ -91,8 +81,7 @@ void rt_tick_increase(void) thread->stat |= RT_THREAD_STAT_YIELD; - /* yield */ - rt_thread_yield(); + rt_schedule(); } /* check timer */ @@ -128,5 +117,21 @@ rt_tick_t rt_tick_from_millisecond(rt_int32_t ms) } RTM_EXPORT(rt_tick_from_millisecond); +/** + * This function will provide the passed millisecond from boot. + * + * @return passed millisecond from boot + */ +RT_WEAK rt_tick_t rt_tick_get_millisecond(void) +{ +#if 1000 % RT_TICK_PER_SECOND == 0u + return rt_tick_get() * (1000u / RT_TICK_PER_SECOND); +#else + #warning "rt-thread cannot provide a correct 1ms-based tick any longer,\ + please redefine this function in another file by using a high-precision hard-timer." + return 0; +#endif +} + /**@}*/ diff --git a/src/components.c b/src/components.c index e7824b65ef..8ea5654d0c 100644 --- a/src/components.c +++ b/src/components.c @@ -173,19 +173,22 @@ struct rt_thread main_thread; void main_thread_entry(void *parameter) { extern int main(void); - extern int $Super$$main(void); #ifdef RT_USING_COMPONENTS_INIT /* RT-Thread components initialization */ rt_components_init(); #endif + #ifdef RT_USING_SMP rt_hw_secondary_cpu_up(); #endif /* invoke system main function */ #if defined(__CC_ARM) || defined(__CLANG_ARM) - $Super$$main(); /* for ARMCC. */ -#elif defined(__ICCARM__) || defined(__GNUC__) + { + extern int $Super$$main(void); + $Super$$main(); /* for ARMCC. */ + } +#elif defined(__ICCARM__) || defined(__GNUC__) || defined(__TASKING__) main(); #endif } diff --git a/src/device.c b/src/device.c index 32c06b380c..a4f004fb69 100644 --- a/src/device.c +++ b/src/device.c @@ -111,38 +111,7 @@ rt_err_t rt_device_init_all(void) */ rt_device_t rt_device_find(const char *name) { - struct rt_object *object; - struct rt_list_node *node; - struct rt_object_information *information; - - /* enter critical */ - if (rt_thread_self() != RT_NULL) - rt_enter_critical(); - - /* try to find device object */ - information = rt_object_get_information(RT_Object_Class_Device); - RT_ASSERT(information != RT_NULL); - for (node = information->object_list.next; - node != &(information->object_list); - node = node->next) - { - object = rt_list_entry(node, struct rt_object, list); - if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0) - { - /* leave critical */ - if (rt_thread_self() != RT_NULL) - rt_exit_critical(); - - return (rt_device_t)object; - } - } - - /* leave critical */ - if (rt_thread_self() != RT_NULL) - rt_exit_critical(); - - /* not found */ - return RT_NULL; + return (rt_device_t)rt_object_find(name, RT_Object_Class_Device); } RTM_EXPORT(rt_device_find); diff --git a/src/idle.c b/src/idle.c index 99db64f571..aa14552a49 100644 --- a/src/idle.c +++ b/src/idle.c @@ -150,82 +150,37 @@ void rt_thread_idle_excute(void) { /* Loop until there is no dead thread. So one call to rt_thread_idle_excute * will do all the cleanups. */ - while (_has_defunct_thread()) + /* disable interrupt */ + + RT_DEBUG_NOT_IN_INTERRUPT; + +#ifdef RT_USING_HEAP + while (1) { rt_base_t lock; rt_thread_t thread; -#ifdef RT_USING_MODULE - struct rt_dlmodule *module = RT_NULL; -#endif - RT_DEBUG_NOT_IN_INTERRUPT; - /* disable interrupt */ lock = rt_hw_interrupt_disable(); - /* re-check whether list is empty */ - if (_has_defunct_thread()) - { - /* get defunct thread */ - thread = rt_list_entry(rt_thread_defunct.next, - struct rt_thread, - tlist); -#ifdef RT_USING_MODULE - module = (struct rt_dlmodule*)thread->module_id; - if (module) - { - dlmodule_destroy(module); - } -#endif - /* remove defunct thread */ - rt_list_remove(&(thread->tlist)); - - /* lock scheduler to prevent scheduling in cleanup function. */ - rt_enter_critical(); - - /* invoke thread cleanup */ - if (thread->cleanup != RT_NULL) - thread->cleanup(thread); - -#ifdef RT_USING_SIGNALS - rt_thread_free_sig(thread); -#endif - - /* if it's a system object, not delete it */ - if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE) - { - /* detach this object */ - rt_object_detach((rt_object_t)thread); - /* unlock scheduler */ - rt_exit_critical(); - - /* enable interrupt */ - rt_hw_interrupt_enable(lock); - - return; - } - - /* unlock scheduler */ - rt_exit_critical(); - } - else + /* check whether list is empty */ + if (!_has_defunct_thread()) { - /* enable interrupt */ rt_hw_interrupt_enable(lock); - - /* may the defunct thread list is removed by others, just return */ - return; + break; } - - /* enable interrupt */ - rt_hw_interrupt_enable(lock); - -#ifdef RT_USING_HEAP + /* get defunct thread */ + thread = rt_list_entry(rt_thread_defunct.next, + struct rt_thread, + tlist); + /* remove defunct thread */ + rt_list_remove(&(thread->tlist)); /* release thread's stack */ RT_KERNEL_FREE(thread->stack_addr); /* delete thread object */ rt_object_delete((rt_object_t)thread); -#endif + rt_hw_interrupt_enable(lock); } +#endif } extern void rt_system_power_manager(void); diff --git a/src/ipc.c b/src/ipc.c index 8e8c4db842..37b05b9ae3 100644..100755 --- a/src/ipc.c +++ b/src/ipc.c @@ -34,6 +34,11 @@ * 2013-09-14 Grissiom add an option check in rt_event_recv * 2018-10-02 Bernard add 64bit support for mailbox * 2019-09-16 tyx add send wait support for message queue + * 2020-07-29 Meco Man fix thread->event_set/event_info when received an + * event without pending + * 2020-10-11 Meco Man add value overflow-check code + * 2021-01-03 Meco Man add rt_mb_urgent() + * 2021-01-20 hupu fix priority inversion bug of mutex */ #include <rtthread.h> @@ -117,6 +122,9 @@ rt_inline rt_err_t rt_ipc_list_suspend(rt_list_t *list, rt_list_insert_before(list, &(thread->tlist)); } break; + + default: + break; } return RT_EOK; @@ -184,6 +192,31 @@ rt_inline rt_err_t rt_ipc_list_resume_all(rt_list_t *list) return RT_EOK; } +/** + * This function will get the highest priority from the specified + * list of threads + * + * @param list of the threads + * + * @return the highest priority + */ +rt_uint8_t rt_ipc_get_highest_priority(rt_list_t *list) +{ + struct rt_list_node *n; + struct rt_thread *sthread; + rt_uint8_t priority = RT_THREAD_PRIORITY_MAX - 1; + + for (n = list->next; n != list; n = n->next) + { + sthread = rt_list_entry(n, struct rt_thread, tlist); + + priority = priority < sthread->current_priority ? + priority : + sthread->current_priority; + } + return priority; +} + #ifdef RT_USING_SEMAPHORE /** * This function will initialize a semaphore and put it under control of @@ -458,7 +491,17 @@ rt_err_t rt_sem_release(rt_sem_t sem) need_schedule = RT_TRUE; } else - sem->value ++; /* increase value */ + { + if(sem->value < RT_SEM_VALUE_MAX) + { + sem->value ++; /* increase value */ + } + else + { + rt_hw_interrupt_enable(temp); /* enable interrupt */ + return -RT_EFULL; /* value overflowed */ + } + } /* enable interrupt */ rt_hw_interrupt_enable(temp); @@ -680,12 +723,22 @@ rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t time) if (mutex->owner == thread) { - /* it's the same thread */ - mutex->hold ++; + if(mutex->hold < RT_MUTEX_HOLD_MAX) + { + /* it's the same thread */ + mutex->hold ++; + } + else + { + rt_hw_interrupt_enable(temp); /* enable interrupt */ + return -RT_EFULL; /* value overflowed */ + } } else { +#ifdef RT_USING_SIGNALS __again: +#endif /* end of RT_USING_SIGNALS */ /* The value of mutex is 1 in initial status. Therefore, if the * value is great than 0, it indicates the mutex is avaible. */ @@ -697,7 +750,15 @@ __again: /* set mutex owner and original priority */ mutex->owner = thread; mutex->original_priority = thread->current_priority; - mutex->hold ++; + if(mutex->hold < RT_MUTEX_HOLD_MAX) + { + mutex->hold ++; + } + else + { + rt_hw_interrupt_enable(temp); /* enable interrupt */ + return -RT_EFULL; /* value overflowed */ + } } else { @@ -754,8 +815,10 @@ __again: if (thread->error != RT_EOK) { +#ifdef RT_USING_SIGNALS /* interrupt by signal, try it again */ if (thread->error == -RT_EINTR) goto __again; +#endif /* end of RT_USING_SIGNALS */ /* return error */ return thread->error; @@ -792,6 +855,7 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex) register rt_base_t temp; struct rt_thread *thread; rt_bool_t need_schedule; + rt_uint8_t max_priority_in_queue = RT_THREAD_PRIORITY_MAX - 1; /* parameter check */ RT_ASSERT(mutex != RT_NULL); @@ -852,7 +916,31 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex) /* set new owner and priority */ mutex->owner = thread; mutex->original_priority = thread->current_priority; - mutex->hold ++; + + /* Priority adjustment occurs only when the following conditions + * are met simultaneously: + * 1.The type of mutex is RT_IPC_FLAG_FIFO; + * 2.The priority of the thread to be resumed is not equal to the + * highest priority in the queue; + */ + max_priority_in_queue = rt_ipc_get_highest_priority(&mutex->parent.suspend_thread); + if (mutex->parent.parent.flag == RT_IPC_FLAG_FIFO && + thread->current_priority != max_priority_in_queue) + { + rt_thread_control(thread, + RT_THREAD_CTRL_CHANGE_PRIORITY, + &(max_priority_in_queue)); + } + + if(mutex->hold < RT_MUTEX_HOLD_MAX) + { + mutex->hold ++; + } + else + { + rt_hw_interrupt_enable(temp); /* enable interrupt */ + return -RT_EFULL; /* value overflowed */ + } /* resume thread */ rt_ipc_list_resume(&(mutex->parent.suspend_thread)); @@ -861,9 +949,17 @@ rt_err_t rt_mutex_release(rt_mutex_t mutex) } else { - /* increase value */ - mutex->value ++; - + if(mutex->value < RT_MUTEX_VALUE_MAX) + { + /* increase value */ + mutex->value ++; + } + else + { + rt_hw_interrupt_enable(temp); /* enable interrupt */ + return -RT_EFULL; /* value overflowed */ + } + /* clear owner */ mutex->owner = RT_NULL; mutex->original_priority = 0xff; @@ -1080,6 +1176,13 @@ rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set) status = RT_EOK; } } + else + { + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + return -RT_EINVAL; + } /* move node to the next */ n = n->next; @@ -1177,7 +1280,11 @@ rt_err_t rt_event_recv(rt_event_t event, /* set received event */ if (recved) *recved = (event->set & set); - + + /* fill thread event info */ + thread->event_set = (event->set & set); + thread->event_info = option; + /* received event */ if (option & RT_EVENT_FLAG_CLEAR) event->set &= ~set; @@ -1186,10 +1293,10 @@ rt_err_t rt_event_recv(rt_event_t event, { /* no waiting */ thread->error = -RT_ETIMEOUT; - + /* enable interrupt */ rt_hw_interrupt_enable(level); - + return -RT_ETIMEOUT; } else @@ -1470,7 +1577,6 @@ rt_err_t rt_mb_send_wait(rt_mailbox_t mb, if (mb->entry == mb->size && timeout == 0) { rt_hw_interrupt_enable(temp); - return -RT_EFULL; } @@ -1543,9 +1649,18 @@ rt_err_t rt_mb_send_wait(rt_mailbox_t mb, ++ mb->in_offset; if (mb->in_offset >= mb->size) mb->in_offset = 0; - /* increase message entry */ - mb->entry ++; - + + if(mb->entry < RT_MB_ENTRY_MAX) + { + /* increase message entry */ + mb->entry ++; + } + else + { + rt_hw_interrupt_enable(temp); /* enable interrupt */ + return -RT_EFULL; /* value overflowed */ + } + /* resume suspended thread */ if (!rt_list_isempty(&mb->parent.suspend_thread)) { @@ -1583,6 +1698,71 @@ rt_err_t rt_mb_send(rt_mailbox_t mb, rt_ubase_t value) RTM_EXPORT(rt_mb_send); /** + * This function will send an urgent mail to mailbox object, if there are threads + * suspended on mailbox object, it will be waked up. This function will return + * immediately. + * + * @param mb the mailbox object + * @param value the mail + * + * @return the error code + */ +rt_err_t rt_mb_urgent(rt_mailbox_t mb, rt_ubase_t value) +{ + register rt_ubase_t temp; + + /* parameter check */ + RT_ASSERT(mb != RT_NULL); + RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox); + + RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mb->parent.parent))); + + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + if (mb->entry == mb->size) + { + rt_hw_interrupt_enable(temp); + return -RT_EFULL; + } + + /* rewind to the previous position */ + if (mb->out_offset > 0) + { + mb->out_offset --; + } + else + { + mb->out_offset = mb->size - 1; + } + + /* set ptr */ + mb->msg_pool[mb->out_offset] = value; + + /* increase message entry */ + mb->entry ++; + + /* resume suspended thread */ + if (!rt_list_isempty(&mb->parent.suspend_thread)) + { + rt_ipc_list_resume(&(mb->parent.suspend_thread)); + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + rt_schedule(); + + return RT_EOK; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + return RT_EOK; +} +RTM_EXPORT(rt_mb_urgent); + +/** * This function will receive a mail from mailbox object, if there is no mail * in mailbox object, the thread shall wait for a specified time. * @@ -1692,8 +1872,12 @@ rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout) ++ mb->out_offset; if (mb->out_offset >= mb->size) mb->out_offset = 0; + /* decrease message entry */ - mb->entry --; + if(mb->entry > 0) + { + mb->entry --; + } /* resume suspended thread */ if (!rt_list_isempty(&(mb->suspend_sender_thread))) @@ -2019,7 +2203,7 @@ rt_err_t rt_mq_send_wait(rt_mq_t mq, } /* message queue is full */ - while ((msg = mq->msg_queue_free) == RT_NULL) + while ((msg = (struct rt_mq_message *)mq->msg_queue_free) == RT_NULL) { /* reset error number in thread */ thread->error = RT_EOK; @@ -2107,8 +2291,16 @@ rt_err_t rt_mq_send_wait(rt_mq_t mq, if (mq->msg_queue_head == RT_NULL) mq->msg_queue_head = msg; - /* increase message entry */ - mq->entry ++; + if(mq->entry < RT_MQ_ENTRY_MAX) + { + /* increase message entry */ + mq->entry ++; + } + else + { + rt_hw_interrupt_enable(temp); /* enable interrupt */ + return -RT_EFULL; /* value overflowed */ + } /* resume suspended thread */ if (!rt_list_isempty(&mq->parent.suspend_thread)) @@ -2207,9 +2399,17 @@ rt_err_t rt_mq_urgent(rt_mq_t mq, const void *buffer, rt_size_t size) if (mq->msg_queue_tail == RT_NULL) mq->msg_queue_tail = msg; - /* increase message entry */ - mq->entry ++; - + if(mq->entry < RT_MQ_ENTRY_MAX) + { + /* increase message entry */ + mq->entry ++; + } + else + { + rt_hw_interrupt_enable(temp); /* enable interrupt */ + return -RT_EFULL; /* value overflowed */ + } + /* resume suspended thread */ if (!rt_list_isempty(&mq->parent.suspend_thread)) { @@ -2351,7 +2551,10 @@ rt_err_t rt_mq_recv(rt_mq_t mq, mq->msg_queue_tail = RT_NULL; /* decrease message entry */ - mq->entry --; + if(mq->entry > 0) + { + mq->entry --; + } /* enable interrupt */ rt_hw_interrupt_enable(temp); diff --git a/src/kservice.c b/src/kservice.c index 1705ce5283..423fe3ddb3 100644 --- a/src/kservice.c +++ b/src/kservice.c @@ -123,7 +123,7 @@ RTM_EXPORT(_rt_errno); * * @return the address of source memory */ -void *rt_memset(void *s, int c, rt_ubase_t count) +RT_WEAK void *rt_memset(void *s, int c, rt_ubase_t count) { #ifdef RT_USING_TINY_SIZE char *xs = (char *)s; @@ -207,7 +207,7 @@ RTM_EXPORT(rt_memset); * * @return the address of destination memory */ -void *rt_memcpy(void *dst, const void *src, rt_ubase_t count) +RT_WEAK void *rt_memcpy(void *dst, const void *src, rt_ubase_t count) { #ifdef RT_USING_TINY_SIZE char *tmp = (char *)dst, *s = (char *)src; @@ -321,7 +321,7 @@ RTM_EXPORT(rt_memmove); * * @return the result */ -rt_int32_t rt_memcmp(const void *cs, const void *ct, rt_ubase_t count) +RT_WEAK rt_int32_t rt_memcmp(const void *cs, const void *ct, rt_ubase_t count) { const unsigned char *su1, *su2; int res = 0; @@ -456,7 +456,10 @@ RTM_EXPORT(rt_strncmp); rt_int32_t rt_strcmp(const char *cs, const char *ct) { while (*cs && *cs == *ct) - cs++, ct++; + { + cs++; + ct++; + } return (*cs - *ct); } @@ -538,12 +541,12 @@ void rt_show_version(void) rt_kprintf("- RT - Thread Operating System\n"); rt_kprintf(" / | \\ %d.%d.%d build %s\n", RT_VERSION, RT_SUBVERSION, RT_REVISION, __DATE__); - rt_kprintf(" 2006 - 2020 Copyright by rt-thread team\n"); + rt_kprintf(" 2006 - 2021 Copyright by rt-thread team\n"); } RTM_EXPORT(rt_show_version); /* private function */ -#define isdigit(c) ((unsigned)((c) - '0') < 10) +#define _ISDIGIT(c) ((unsigned)((c) - '0') < 10) #ifdef RT_PRINTF_LONGLONG rt_inline int divide(long long *n, int base) @@ -588,7 +591,7 @@ rt_inline int divide(long *n, int base) rt_inline int skip_atoi(const char **s) { register int i = 0; - while (isdigit(**s)) + while (_ISDIGIT(**s)) i = i * 10 + *((*s)++) - '0'; return i; @@ -834,7 +837,7 @@ rt_int32_t rt_vsnprintf(char *buf, /* get field width */ field_width = -1; - if (isdigit(*fmt)) field_width = skip_atoi(&fmt); + if (_ISDIGIT(*fmt)) field_width = skip_atoi(&fmt); else if (*fmt == '*') { ++ fmt; @@ -853,7 +856,7 @@ rt_int32_t rt_vsnprintf(char *buf, if (*fmt == '.') { ++ fmt; - if (isdigit(*fmt)) precision = skip_atoi(&fmt); + if (_ISDIGIT(*fmt)) precision = skip_atoi(&fmt); else if (*fmt == '*') { ++ fmt; @@ -1113,7 +1116,7 @@ RTM_EXPORT(rt_console_get_device); * * @param name the name of new console device * - * @return the old console device handler + * @return the old console device handler on successful, or RT_NULL on failure. */ rt_device_t rt_console_set_device(const char *name) { @@ -1124,6 +1127,10 @@ rt_device_t rt_console_set_device(const char *name) /* find new console device */ new_device = rt_device_find(name); + + /* check whether it's a same device */ + if (new_device == old_device) return RT_NULL; + if (new_device != RT_NULL) { if (_console_device != RT_NULL) @@ -1180,7 +1187,7 @@ void rt_kputs(const char *str) * * @param fmt the format */ -void rt_kprintf(const char *fmt, ...) +RT_WEAK void rt_kprintf(const char *fmt, ...) { va_list args; rt_size_t length; diff --git a/src/memheap.c b/src/memheap.c index aef56e1a74..449e66e975 100644 --- a/src/memheap.c +++ b/src/memheap.c @@ -85,6 +85,10 @@ rt_err_t rt_memheap_init(struct rt_memheap *memheap, item->next_free = item; item->prev_free = item; +#ifdef RT_USING_MEMTRACE + rt_memset(item->owner_thread_name, ' ', sizeof(item->owner_thread_name)); +#endif + item->next = (struct rt_memheap_item *) ((rt_uint8_t *)item + memheap->available_size + RT_MEMHEAP_SIZE); item->prev = item->next; @@ -126,8 +130,8 @@ rt_err_t rt_memheap_detach(struct rt_memheap *heap) RT_ASSERT(heap); RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap); RT_ASSERT(rt_object_is_systemobject(&heap->parent)); - - rt_object_detach(&(heap->lock.parent.parent)); + + rt_sem_detach(&heap->lock); rt_object_detach(&(heap->parent)); /* Return a successful completion. */ @@ -206,6 +210,10 @@ void *rt_memheap_alloc(struct rt_memheap *heap, rt_size_t size) /* put the pool pointer into the new block. */ new_ptr->pool_ptr = heap; +#ifdef RT_USING_MEMTRACE + rt_memset(new_ptr->owner_thread_name, ' ', sizeof(new_ptr->owner_thread_name)); +#endif + /* break down the block list */ new_ptr->prev = header_ptr; new_ptr->next = header_ptr->next; @@ -257,6 +265,13 @@ void *rt_memheap_alloc(struct rt_memheap *heap, rt_size_t size) /* Mark the allocated block as not available. */ header_ptr->magic |= RT_MEMHEAP_USED; +#ifdef RT_USING_MEMTRACE + if (rt_thread_self()) + rt_memcpy(header_ptr->owner_thread_name, rt_thread_self()->name, sizeof(header_ptr->owner_thread_name)); + else + rt_memcpy(header_ptr->owner_thread_name, "NONE", sizeof(header_ptr->owner_thread_name)); +#endif + /* release lock */ rt_sem_release(&(heap->lock)); @@ -381,6 +396,10 @@ void *rt_memheap_realloc(struct rt_memheap *heap, void *ptr, rt_size_t newsize) /* put the pool pointer into the new block. */ next_ptr->pool_ptr = heap; +#ifdef RT_USING_MEMTRACE + rt_memset(next_ptr->owner_thread_name, ' ', sizeof(next_ptr->owner_thread_name)); +#endif + next_ptr->prev = header_ptr; next_ptr->next = header_ptr->next; header_ptr->next->prev = next_ptr; @@ -445,6 +464,10 @@ void *rt_memheap_realloc(struct rt_memheap *heap, void *ptr, rt_size_t newsize) /* put the pool pointer into the new block. */ new_ptr->pool_ptr = heap; +#ifdef RT_USING_MEMTRACE + rt_memset(new_ptr->owner_thread_name, ' ', sizeof(new_ptr->owner_thread_name)); +#endif + /* break down the block list */ new_ptr->prev = header_ptr; new_ptr->next = header_ptr->next; @@ -590,6 +613,10 @@ void rt_memheap_free(void *ptr) header_ptr->next_free, header_ptr->prev_free)); } +#ifdef RT_USING_MEMTRACE + rt_memset(header_ptr->owner_thread_name, ' ', sizeof(header_ptr->owner_thread_name)); +#endif + /* release lock */ rt_sem_release(&(heap->lock)); } @@ -712,6 +739,94 @@ void *rt_calloc(rt_size_t count, rt_size_t size) } RTM_EXPORT(rt_calloc); -#endif +void rt_memory_info(rt_uint32_t *total, + rt_uint32_t *used, + rt_uint32_t *max_used) +{ + if (total != RT_NULL) + *total = _heap.pool_size; + + if (used != RT_NULL) + *used = _heap.pool_size - _heap.available_size; + + if (max_used != RT_NULL) + *max_used = _heap.max_used_size; +} #endif + +#ifdef RT_USING_MEMTRACE + +void dump_used_memheap(struct rt_memheap *mh) +{ + struct rt_memheap_item *header_ptr; + rt_uint32_t block_size; + + + rt_kprintf("\nmemory heap address:\n"); + rt_kprintf("heap_ptr: 0x%08x\n", mh->start_addr); + rt_kprintf("free : 0x%08x\n", mh->available_size); + rt_kprintf("max_used: 0x%08x\n", mh->max_used_size); + rt_kprintf("size : 0x%08x\n", mh->pool_size); + + rt_kprintf("\n--memory used information --\n"); + + header_ptr = mh->block_list; + while (header_ptr->next != mh->block_list) + { + if ((header_ptr->magic & RT_MEMHEAP_MASK) != RT_MEMHEAP_MAGIC) + { + rt_kprintf("[0x%08x - incorrect magic: 0x%08x\n", header_ptr, header_ptr->magic); + break; + } + + /* get current memory block size */ + block_size = MEMITEM_SIZE(header_ptr); + if (block_size < 0) + break; + + if (RT_MEMHEAP_IS_USED(header_ptr)) + { + /* dump information */ + rt_kprintf("[0x%08x - %d - %c%c%c%c] used\n", header_ptr, block_size, + header_ptr->owner_thread_name[0], header_ptr->owner_thread_name[1], + header_ptr->owner_thread_name[2], header_ptr->owner_thread_name[3]); + } + else + { + /* dump information */ + rt_kprintf("[0x%08x - %d - %c%c%c%c] free\n", header_ptr, block_size, + header_ptr->owner_thread_name[0], header_ptr->owner_thread_name[1], + header_ptr->owner_thread_name[2], header_ptr->owner_thread_name[3]); + } + + /* move to next used memory block */ + header_ptr = header_ptr->next; + } +} + +void memtrace_heap() +{ + struct rt_object_information *info; + struct rt_list_node *list; + struct rt_memheap *mh; + struct rt_list_node *node; + + info = rt_object_get_information(RT_Object_Class_MemHeap); + list = &info->object_list; + + for (node = list->next; node != list; node = node->next) + { + mh = (struct rt_memheap *)rt_list_entry(node, struct rt_object, list); + dump_used_memheap(mh); + } +} + +#ifdef RT_USING_FINSH +#include <finsh.h> +MSH_CMD_EXPORT(memtrace_heap, dump memory trace for heap); +#endif /* end of RT_USING_FINSH */ + +#endif /* end of RT_USING_MEMTRACE */ + +#endif /* end of RT_USING_MEMHEAP */ diff --git a/src/mempool.c b/src/mempool.c index 00471efb35..db614032aa 100644 --- a/src/mempool.c +++ b/src/mempool.c @@ -134,7 +134,7 @@ RTM_EXPORT(rt_mp_init); rt_err_t rt_mp_detach(struct rt_mempool *mp) { struct rt_thread *thread; - register rt_ubase_t temp; + register rt_ubase_t level; /* parameter check */ RT_ASSERT(mp != RT_NULL); @@ -145,7 +145,7 @@ rt_err_t rt_mp_detach(struct rt_mempool *mp) while (!rt_list_isempty(&(mp->suspend_thread))) { /* disable interrupt */ - temp = rt_hw_interrupt_disable(); + level = rt_hw_interrupt_disable(); /* get next suspend thread */ thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist); @@ -160,7 +160,7 @@ rt_err_t rt_mp_detach(struct rt_mempool *mp) rt_thread_resume(thread); /* enable interrupt */ - rt_hw_interrupt_enable(temp); + rt_hw_interrupt_enable(level); } /* detach object */ @@ -250,7 +250,7 @@ RTM_EXPORT(rt_mp_create); rt_err_t rt_mp_delete(rt_mp_t mp) { struct rt_thread *thread; - register rt_ubase_t temp; + register rt_ubase_t level; RT_DEBUG_NOT_IN_INTERRUPT; @@ -263,7 +263,7 @@ rt_err_t rt_mp_delete(rt_mp_t mp) while (!rt_list_isempty(&(mp->suspend_thread))) { /* disable interrupt */ - temp = rt_hw_interrupt_disable(); + level = rt_hw_interrupt_disable(); /* get next suspend thread */ thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist); @@ -278,7 +278,7 @@ rt_err_t rt_mp_delete(rt_mp_t mp) rt_thread_resume(thread); /* enable interrupt */ - rt_hw_interrupt_enable(temp); + rt_hw_interrupt_enable(level); } /* release allocated room */ diff --git a/src/object.c b/src/object.c index 6866d805ca..56263618b3 100644 --- a/src/object.c +++ b/src/object.c @@ -192,18 +192,6 @@ void rt_object_put_sethook(void (*hook)(struct rt_object *object)) #endif /** - * @ingroup SystemInit - * - * This function will initialize system object management. - * - * @deprecated since 0.3.0, this function does not need to be invoked - * in the system initialization. - */ -void rt_system_object_init(void) -{ -} - -/** * @addtogroup KernelObject */ @@ -485,7 +473,7 @@ void rt_object_delete(rt_object_t object) RT_OBJECT_HOOK_CALL(rt_object_detach_hook, (object)); /* reset object type */ - object->type = 0; + object->type = RT_Object_Class_Null; /* lock interrupt */ temp = rt_hw_interrupt_disable(); diff --git a/src/scheduler.c b/src/scheduler.c index 6baaa9627a..06f305ea0b 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -33,10 +33,6 @@ #include <rtthread.h> #include <rthw.h> -#ifdef RT_USING_SMP -rt_hw_spinlock_t _rt_critical_lock; -#endif /*RT_USING_SMP*/ - rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX]; rt_uint32_t rt_thread_ready_priority_group; #if RT_THREAD_PRIORITY_MAX > 32 @@ -47,7 +43,7 @@ rt_uint8_t rt_thread_ready_table[32]; #ifndef RT_USING_SMP extern volatile rt_uint8_t rt_interrupt_nest; static rt_int16_t rt_scheduler_lock_nest; -struct rt_thread *rt_current_thread; +struct rt_thread *rt_current_thread = RT_NULL; rt_uint8_t rt_current_priority; #endif /*RT_USING_SMP*/ @@ -94,12 +90,7 @@ static void _rt_scheduler_stack_check(struct rt_thread *thread) rt_ubase_t level; rt_kprintf("thread:%s stack overflow\n", thread->name); -#ifdef RT_USING_FINSH - { - extern long list_thread(void); - list_thread(); - } -#endif + level = rt_hw_interrupt_disable(); while (level); } @@ -350,9 +341,9 @@ void rt_schedule(void) } else { - current_thread->stat &= ~RT_THREAD_STAT_YIELD_MASK; rt_schedule_insert_thread(current_thread); } + current_thread->stat &= ~RT_THREAD_STAT_YIELD_MASK; } to_thread->oncpu = cpu_id; if (to_thread != current_thread) @@ -448,9 +439,9 @@ void rt_schedule(void) } else { - rt_current_thread->stat &= ~RT_THREAD_STAT_YIELD_MASK; need_insert_from_thread = 1; } + rt_current_thread->stat &= ~RT_THREAD_STAT_YIELD_MASK; } if (to_thread != rt_current_thread) @@ -599,9 +590,9 @@ void rt_scheduler_do_irq_switch(void *context) } else { - current_thread->stat &= ~RT_THREAD_STAT_YIELD_MASK; rt_schedule_insert_thread(current_thread); } + current_thread->stat &= ~RT_THREAD_STAT_YIELD_MASK; } to_thread->oncpu = cpu_id; if (to_thread != current_thread) @@ -788,7 +779,7 @@ void rt_schedule_remove_thread(struct rt_thread *thread) { #if RT_THREAD_PRIORITY_MAX > 32 pcpu->ready_table[thread->number] &= ~thread->high_mask; - if (rt_thread_ready_table[thread->number] == 0) + if (pcpu->ready_table[thread->number] == 0) { pcpu->priority_group &= ~thread->number_mask; } @@ -851,7 +842,7 @@ void rt_enter_critical(void) if (!current_thread) { rt_hw_local_irq_enable(level); - return ; + return; } /* @@ -859,12 +850,15 @@ void rt_enter_critical(void) * enough and does not check here */ - /* lock scheduler for all cpus */ - if (current_thread->critical_lock_nest == 0) { - rt_hw_spin_lock(&_rt_critical_lock); + register rt_uint16_t lock_nest = current_thread->cpus_lock_nest; + current_thread->cpus_lock_nest++; + if (lock_nest == 0) + { + current_thread->scheduler_lock_nest ++; + rt_hw_spin_lock(&_cpus_lock); + } } - /* critical for local cpu */ current_thread->critical_lock_nest ++; @@ -910,16 +904,18 @@ void rt_exit_critical(void) if (!current_thread) { rt_hw_local_irq_enable(level); - return ; + return; } current_thread->scheduler_lock_nest --; current_thread->critical_lock_nest --; - if (current_thread->critical_lock_nest == 0) + current_thread->cpus_lock_nest--; + if (current_thread->cpus_lock_nest == 0) { - rt_hw_spin_unlock(&_rt_critical_lock); + current_thread->scheduler_lock_nest --; + rt_hw_spin_unlock(&_cpus_lock); } if (current_thread->scheduler_lock_nest <= 0) diff --git a/src/thread.c b/src/thread.c index 715596b132..2681eca59f 100644 --- a/src/thread.c +++ b/src/thread.c @@ -26,6 +26,7 @@ * bug when thread has not startup. * 2018-11-22 Jesven yield is same to rt_schedule * add support for tasks bound to cpu + * 2021-02-24 Meco Man rearrange rt_thread_control() - schedule the thread when close it */ #include <rthw.h> @@ -77,6 +78,31 @@ void rt_thread_inited_sethook(void (*hook)(rt_thread_t thread)) #endif +/* must be invoke witch rt_hw_interrupt_disable */ +static void _thread_cleanup_execute(rt_thread_t thread) +{ + register rt_base_t level; +#ifdef RT_USING_MODULE + struct rt_dlmodule *module = RT_NULL; +#endif + level = rt_hw_interrupt_disable(); +#ifdef RT_USING_MODULE + module = (struct rt_dlmodule*)thread->module_id; + if (module) + { + dlmodule_destroy(module); + } +#endif + /* invoke thread cleanup */ + if (thread->cleanup != RT_NULL) + thread->cleanup(thread); + +#ifdef RT_USING_SIGNALS + rt_thread_free_sig(thread); +#endif + rt_hw_interrupt_enable(level); +} + void rt_thread_exit(void) { struct rt_thread *thread; @@ -88,6 +114,8 @@ void rt_thread_exit(void) /* disable interrupt */ level = rt_hw_interrupt_disable(); + _thread_cleanup_execute(thread); + /* remove from schedule */ rt_schedule_remove_thread(thread); /* change stat */ @@ -96,8 +124,7 @@ void rt_thread_exit(void) /* remove it from timer list */ rt_timer_detach(&thread->thread_timer); - if ((rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE) && - thread->cleanup == RT_NULL) + if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE) { rt_object_detach((rt_object_t)thread); } @@ -347,14 +374,15 @@ rt_err_t rt_thread_detach(rt_thread_t thread) rt_schedule_remove_thread(thread); } + _thread_cleanup_execute(thread); + /* release thread timer */ rt_timer_detach(&(thread->thread_timer)); /* change stat */ thread->stat = RT_THREAD_CLOSE; - if ((rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE) && - thread->cleanup == RT_NULL) + if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE) { rt_object_detach((rt_object_t)thread); } @@ -449,6 +477,8 @@ rt_err_t rt_thread_delete(rt_thread_t thread) rt_schedule_remove_thread(thread); } + _thread_cleanup_execute(thread); + /* release thread timer */ rt_timer_detach(&(thread->thread_timer)); @@ -478,7 +508,15 @@ RTM_EXPORT(rt_thread_delete); */ rt_err_t rt_thread_yield(void) { + struct rt_thread *thread; + rt_base_t lock; + + thread = rt_thread_self(); + lock = rt_hw_interrupt_disable(); + thread->remaining_tick = thread->init_tick; + thread->stat |= RT_THREAD_STAT_YIELD; rt_schedule(); + rt_hw_interrupt_enable(lock); return RT_EOK; } @@ -561,7 +599,7 @@ rt_err_t rt_thread_delay_until(rt_tick_t *tick, rt_tick_t inc_tick) if (rt_tick_get() - *tick < inc_tick) { - *tick = rt_tick_get() - *tick + inc_tick; + *tick = *tick + inc_tick - rt_tick_get(); /* suspend thread */ rt_thread_suspend(thread); @@ -633,75 +671,93 @@ rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg) switch (cmd) { - case RT_THREAD_CTRL_CHANGE_PRIORITY: - /* disable interrupt */ - temp = rt_hw_interrupt_disable(); - - /* for ready thread, change queue */ - if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY) + case RT_THREAD_CTRL_CHANGE_PRIORITY: { - /* remove thread from schedule queue first */ - rt_schedule_remove_thread(thread); + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); - /* change thread priority */ - thread->current_priority = *(rt_uint8_t *)arg; + /* for ready thread, change queue */ + if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY) + { + /* remove thread from schedule queue first */ + rt_schedule_remove_thread(thread); - /* recalculate priority attribute */ -#if RT_THREAD_PRIORITY_MAX > 32 - thread->number = thread->current_priority >> 3; /* 5bit */ - thread->number_mask = 1 << thread->number; - thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */ -#else - thread->number_mask = 1 << thread->current_priority; -#endif + /* change thread priority */ + thread->current_priority = *(rt_uint8_t *)arg; + + /* recalculate priority attribute */ + #if RT_THREAD_PRIORITY_MAX > 32 + thread->number = thread->current_priority >> 3; /* 5bit */ + thread->number_mask = 1 << thread->number; + thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */ + #else + thread->number_mask = 1 << thread->current_priority; + #endif + + /* insert thread to schedule queue again */ + rt_schedule_insert_thread(thread); + } + else + { + thread->current_priority = *(rt_uint8_t *)arg; - /* insert thread to schedule queue again */ - rt_schedule_insert_thread(thread); + /* recalculate priority attribute */ + #if RT_THREAD_PRIORITY_MAX > 32 + thread->number = thread->current_priority >> 3; /* 5bit */ + thread->number_mask = 1 << thread->number; + thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */ + #else + thread->number_mask = 1 << thread->current_priority; + #endif + } + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + break; } - else - { - thread->current_priority = *(rt_uint8_t *)arg; - /* recalculate priority attribute */ -#if RT_THREAD_PRIORITY_MAX > 32 - thread->number = thread->current_priority >> 3; /* 5bit */ - thread->number_mask = 1 << thread->number; - thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */ -#else - thread->number_mask = 1 << thread->current_priority; -#endif + case RT_THREAD_CTRL_STARTUP: + { + return rt_thread_startup(thread); } - /* enable interrupt */ - rt_hw_interrupt_enable(temp); - break; + case RT_THREAD_CTRL_CLOSE: + { + rt_err_t rt_err; - case RT_THREAD_CTRL_STARTUP: - return rt_thread_startup(thread); + if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE) + { + rt_err = rt_thread_detach(thread); + } + #ifdef RT_USING_HEAP + else + { + rt_err = rt_thread_delete(thread); + } + #endif + rt_schedule(); + return rt_err; + } -#ifdef RT_USING_HEAP - case RT_THREAD_CTRL_CLOSE: - return rt_thread_delete(thread); -#endif + #ifdef RT_USING_SMP + case RT_THREAD_CTRL_BIND_CPU: + { + rt_uint8_t cpu; -#ifdef RT_USING_SMP - case RT_THREAD_CTRL_BIND_CPU: - { - rt_uint8_t cpu; + if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT) + { + /* we only support bind cpu before started phase. */ + return RT_ERROR; + } - if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT) - { - /* we only support bind cpu before started phase. */ - return RT_ERROR; + cpu = (rt_uint8_t)(size_t)arg; + thread->bind_cpu = cpu > RT_CPUS_NR? RT_CPUS_NR : cpu; + break; } + #endif /*RT_USING_SMP*/ - cpu = (rt_uint8_t)(size_t)arg; - thread->bind_cpu = cpu > RT_CPUS_NR? RT_CPUS_NR : cpu; - break; - } -#endif /*RT_USING_SMP*/ - default: - break; + default: + break; } return RT_EOK; @@ -846,38 +902,7 @@ RTM_EXPORT(rt_thread_timeout); */ rt_thread_t rt_thread_find(char *name) { - struct rt_object_information *information; - struct rt_object *object; - struct rt_list_node *node; - - /* enter critical */ - if (rt_thread_self() != RT_NULL) - rt_enter_critical(); - - /* try to find device object */ - information = rt_object_get_information(RT_Object_Class_Thread); - RT_ASSERT(information != RT_NULL); - for (node = information->object_list.next; - node != &(information->object_list); - node = node->next) - { - object = rt_list_entry(node, struct rt_object, list); - if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0) - { - /* leave critical */ - if (rt_thread_self() != RT_NULL) - rt_exit_critical(); - - return (rt_thread_t)object; - } - } - - /* leave critical */ - if (rt_thread_self() != RT_NULL) - rt_exit_critical(); - - /* not found */ - return RT_NULL; + return (rt_thread_t)rt_object_find(name, RT_Object_Class_Thread); } RTM_EXPORT(rt_thread_find); diff --git a/src/timer.c b/src/timer.c index 28a5a9e494..d882711151 100644 --- a/src/timer.c +++ b/src/timer.c @@ -25,6 +25,10 @@ static rt_list_t rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL]; #ifdef RT_USING_TIMER_SOFT + +#define RT_SOFT_TIMER_IDLE 1 +#define RT_SOFT_TIMER_BUSY 0 + #ifndef RT_TIMER_THREAD_STACK_SIZE #define RT_TIMER_THREAD_STACK_SIZE 512 #endif @@ -33,6 +37,8 @@ static rt_list_t rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL]; #define RT_TIMER_THREAD_PRIO 0 #endif +/* soft timer status */ +static rt_uint8_t soft_timer_status = RT_SOFT_TIMER_IDLE; /* soft timer list */ static rt_list_t rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL]; static struct rt_thread timer_thread; @@ -221,6 +227,8 @@ rt_err_t rt_timer_detach(rt_timer_t timer) level = rt_hw_interrupt_disable(); _rt_timer_remove(timer); + /* stop timer */ + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; /* enable interrupt */ rt_hw_interrupt_enable(level); @@ -284,6 +292,8 @@ rt_err_t rt_timer_delete(rt_timer_t timer) level = rt_hw_interrupt_disable(); _rt_timer_remove(timer); + /* stop timer */ + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; /* enable interrupt */ rt_hw_interrupt_enable(level); @@ -321,7 +331,6 @@ rt_err_t rt_timer_start(rt_timer_t timer) _rt_timer_remove(timer); /* change status of timer */ timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; - rt_hw_interrupt_enable(level); RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(timer->parent))); @@ -332,9 +341,6 @@ rt_err_t rt_timer_start(rt_timer_t timer) RT_ASSERT(timer->init_tick < RT_TICK_MAX / 2); timer->timeout_tick = rt_tick_get() + timer->init_tick; - /* disable interrupt */ - level = rt_hw_interrupt_disable(); - #ifdef RT_USING_TIMER_SOFT if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER) { @@ -408,7 +414,8 @@ rt_err_t rt_timer_start(rt_timer_t timer) if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER) { /* check whether timer thread is ready */ - if ((timer_thread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND) + if ((soft_timer_status == RT_SOFT_TIMER_IDLE) && + ((timer_thread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND)) { /* resume timer thread to check soft timer */ rt_thread_resume(&timer_thread); @@ -445,13 +452,12 @@ rt_err_t rt_timer_stop(rt_timer_t timer) level = rt_hw_interrupt_disable(); _rt_timer_remove(timer); + /* change status */ + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; /* enable interrupt */ rt_hw_interrupt_enable(level); - /* change stat */ - timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; - return RT_EOK; } RTM_EXPORT(rt_timer_stop); @@ -467,10 +473,13 @@ RTM_EXPORT(rt_timer_stop); */ rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg) { + register rt_base_t level; + /* timer check */ RT_ASSERT(timer != RT_NULL); RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); + level = rt_hw_interrupt_disable(); switch (cmd) { case RT_TIMER_CTRL_GET_TIME: @@ -500,8 +509,12 @@ rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg) /*timer is stop*/ *(rt_tick_t *)arg = RT_TIMER_FLAG_DEACTIVATED; } - break; + break; + + default: + break; } + rt_hw_interrupt_enable(level); return RT_EOK; } @@ -518,6 +531,7 @@ void rt_timer_check(void) struct rt_timer *t; rt_tick_t current_tick; register rt_base_t level; + rt_list_t list = RT_LIST_OBJECT_INIT(list); RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check enter\n")); @@ -541,7 +555,12 @@ void rt_timer_check(void) /* remove timer from timer list firstly */ _rt_timer_remove(t); - + if (!(t->parent.flag & RT_TIMER_FLAG_PERIODIC)) + { + t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + } + /* add timer to temporary list */ + rt_list_insert_after(&list, &(t->row[RT_TIMER_SKIP_LIST_LEVEL - 1])); /* call timeout function */ t->timeout_func(t->parameter); @@ -551,6 +570,12 @@ void rt_timer_check(void) RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t)); RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick)); + /* Check whether the timer object is detached or started again */ + if (rt_list_isempty(&list)) + { + continue; + } + rt_list_remove(&(t->row[RT_TIMER_SKIP_LIST_LEVEL - 1])); if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) && (t->parent.flag & RT_TIMER_FLAG_ACTIVATED)) { @@ -558,14 +583,8 @@ void rt_timer_check(void) t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; rt_timer_start(t); } - else - { - /* stop timer */ - t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; - } } - else - break; + else break; } /* enable interrupt */ @@ -586,26 +605,27 @@ rt_tick_t rt_timer_next_timeout_tick(void) #ifdef RT_USING_TIMER_SOFT /** - * This function will check timer list, if a timeout event happens, the + * This function will check software-timer list, if a timeout event happens, the * corresponding timeout function will be invoked. */ void rt_soft_timer_check(void) { rt_tick_t current_tick; - rt_list_t *n; struct rt_timer *t; + register rt_base_t level; + rt_list_t list = RT_LIST_OBJECT_INIT(list); RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check enter\n")); - current_tick = rt_tick_get(); - - /* lock scheduler */ - rt_enter_critical(); + /* disable interrupt */ + level = rt_hw_interrupt_disable(); - for (n = rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next; - n != &(rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]);) + while (!rt_list_isempty(&rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1])) { - t = rt_list_entry(n, struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]); + t = rt_list_entry(rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next, + struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]); + + current_tick = rt_tick_get(); /* * It supposes that the new tick shall less than the half duration of @@ -615,26 +635,35 @@ void rt_soft_timer_check(void) { RT_OBJECT_HOOK_CALL(rt_timer_enter_hook, (t)); - /* move node to the next */ - n = n->next; - /* remove timer from timer list firstly */ _rt_timer_remove(t); + if (!(t->parent.flag & RT_TIMER_FLAG_PERIODIC)) + { + t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + } + /* add timer to temporary list */ + rt_list_insert_after(&list, &(t->row[RT_TIMER_SKIP_LIST_LEVEL - 1])); + + soft_timer_status = RT_SOFT_TIMER_BUSY; + /* enable interrupt */ + rt_hw_interrupt_enable(level); - /* not lock scheduler when performing timeout function */ - rt_exit_critical(); /* call timeout function */ t->timeout_func(t->parameter); - /* re-get tick */ - current_tick = rt_tick_get(); - RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t)); RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick)); - /* lock scheduler */ - rt_enter_critical(); + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + soft_timer_status = RT_SOFT_TIMER_IDLE; + /* Check whether the timer object is detached or started again */ + if (rt_list_isempty(&list)) + { + continue; + } + rt_list_remove(&(t->row[RT_TIMER_SKIP_LIST_LEVEL - 1])); if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) && (t->parent.flag & RT_TIMER_FLAG_ACTIVATED)) { @@ -642,17 +671,11 @@ void rt_soft_timer_check(void) t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; rt_timer_start(t); } - else - { - /* stop timer */ - t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; - } } else break; /* not check anymore */ } - - /* unlock scheduler */ - rt_exit_critical(); + /* enable interrupt */ + rt_hw_interrupt_enable(level); RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check leave\n")); } |
