diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Kconfig | 22 | ||||
| -rw-r--r-- | src/SConscript | 3 | ||||
| -rw-r--r-- | src/cpu.c | 28 | ||||
| -rw-r--r-- | src/device.c | 83 | ||||
| -rw-r--r-- | src/driver.c | 113 | ||||
| -rw-r--r-- | src/ipc.c | 350 | ||||
| -rw-r--r-- | src/kservice.c | 87 | ||||
| -rw-r--r-- | src/object.c | 78 | ||||
| -rw-r--r-- | src/scheduler.c | 69 | ||||
| -rw-r--r-- | src/signal.c | 10 | ||||
| -rw-r--r-- | src/thread.c | 234 | ||||
| -rw-r--r-- | src/timer.c | 30 |
12 files changed, 979 insertions, 128 deletions
diff --git a/src/Kconfig b/src/Kconfig index 9e1a0eafc4..9007831c6f 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -17,6 +17,13 @@ config RT_USING_ARCH_DATA_TYPE Please re-define these data types in rtconfig_project.h file. +config RT_USING_SMART + bool "Enable RT-Thread Smart (microkernel on kernel/userland)" + default n + select RT_USING_LWP + help + RT-Thread Smart is a microkernel based operating system on RT-Thread. + config RT_USING_SMP bool "Enable SMP(Symmetric multiprocessing)" default n @@ -407,6 +414,21 @@ menu "Kernel Device Object" bool "Using ops for each device object" default n + config RT_USING_DM + bool "Enable device driver model with device tree" + default n + help + Enable device driver model with device tree (FDT). It will use more memory + to parse and support device tree feature. + + config RT_USING_DM_FDT + bool "Enablie builtin libfdt" + depends on RT_USING_DM + default y + help + libfdt - Flat Device Tree manipulation. If your code already contains the + libfdt, you can cancel this built-in libfdt to avoid link issue. + config RT_USING_INTERRUPT_INFO bool "Enable additional interrupt trace information" default n diff --git a/src/SConscript b/src/SConscript index b53708adf9..c2d849670f 100644 --- a/src/SConscript +++ b/src/SConscript @@ -27,6 +27,9 @@ if GetDepend('RT_USING_DEVICE') == False: if GetDepend('RT_USING_SMP') == False: SrcRemove(src, ['cpu.c']) +if GetDepend('RT_USING_DM') == False: + SrcRemove(src, ['driver.c']) + group = DefineGroup('Kernel', src, depend = [''], CPPPATH = inc, CPPDEFINES = ['__RTTHREAD__']) Return('group') @@ -10,6 +10,10 @@ #include <rthw.h> #include <rtthread.h> +#ifdef RT_USING_USERSPACE +#include <lwp.h> +#endif + #ifdef RT_USING_SMP static struct rt_cpu _cpus[RT_CPUS_NR]; rt_hw_spinlock_t _cpus_lock; @@ -64,6 +68,7 @@ static void _cpu_preempt_enable(void) /* enable interrupt */ rt_hw_local_irq_enable(level); } +#endif /* RT_USING_SMP */ /** * @brief Initialize a static spinlock object. @@ -72,7 +77,9 @@ static void _cpu_preempt_enable(void) */ void rt_spin_lock_init(struct rt_spinlock *lock) { +#ifdef RT_USING_SMP rt_hw_spin_lock_init(&lock->lock); +#endif } RTM_EXPORT(rt_spin_lock_init) @@ -86,8 +93,12 @@ RTM_EXPORT(rt_spin_lock_init) */ void rt_spin_lock(struct rt_spinlock *lock) { +#ifdef RT_USING_SMP _cpu_preempt_disable(); rt_hw_spin_lock(&lock->lock); +#else + rt_enter_critical(); +#endif } RTM_EXPORT(rt_spin_lock) @@ -98,8 +109,12 @@ RTM_EXPORT(rt_spin_lock) */ void rt_spin_unlock(struct rt_spinlock *lock) { +#ifdef RT_USING_SMP rt_hw_spin_unlock(&lock->lock); _cpu_preempt_enable(); +#else + rt_exit_critical(); +#endif } RTM_EXPORT(rt_spin_unlock) @@ -115,6 +130,7 @@ RTM_EXPORT(rt_spin_unlock) */ rt_base_t rt_spin_lock_irqsave(struct rt_spinlock *lock) { +#ifdef RT_USING_SMP unsigned long level; _cpu_preempt_disable(); @@ -123,6 +139,9 @@ rt_base_t rt_spin_lock_irqsave(struct rt_spinlock *lock) rt_hw_spin_lock(&lock->lock); return level; +#else + return rt_hw_interrupt_disable(); +#endif } RTM_EXPORT(rt_spin_lock_irqsave) @@ -135,10 +154,14 @@ RTM_EXPORT(rt_spin_lock_irqsave) */ void rt_spin_unlock_irqrestore(struct rt_spinlock *lock, rt_base_t level) { +#ifdef RT_USING_SMP rt_hw_spin_unlock(&lock->lock); rt_hw_local_irq_enable(level); _cpu_preempt_enable(); +#else + rt_hw_interrupt_enable(level); +#endif } RTM_EXPORT(rt_spin_unlock_irqrestore) @@ -223,6 +246,9 @@ void rt_cpus_lock_status_restore(struct rt_thread *thread) { struct rt_cpu* pcpu = rt_cpu_self(); +#ifdef RT_USING_USERSPACE + lwp_mmu_switch(thread); +#endif pcpu->current_thread = thread; if (!thread->cpus_lock_nest) { @@ -230,5 +256,3 @@ void rt_cpus_lock_status_restore(struct rt_thread *thread) } } RTM_EXPORT(rt_cpus_lock_status_restore); - -#endif /* RT_USING_SMP */ diff --git a/src/device.c b/src/device.c index 1079e2c38f..beba062952 100644 --- a/src/device.c +++ b/src/device.c @@ -457,4 +457,87 @@ rt_err_t rt_device_set_tx_complete(rt_device_t dev, } RTM_EXPORT(rt_device_set_tx_complete); +#ifdef RT_USING_DM +/** + * This function bind drvier and device + * + * @param driver the pointer of driver structure + * @param device the pointer of device structure + * @param node the pointer of fdt node structure + * + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_device_bind_driver(rt_device_t device, rt_driver_t driver, void *node) +{ + if((!driver) || (!device)) + { + return -RT_EINVAL; + } + + device->drv = driver; +#ifdef RT_USING_DEVICE_OPS + device->ops = driver->dev_ops; +#endif + device->dtb_node = node; + + return RT_EOK; +} +RTM_EXPORT(rt_device_bind_driver); + +/** + * This function create rt_device according to driver infomation + * + * @param drv the pointer of driver structure + * @param device_id specify the ID of the rt_device + * + * @return the error code, RT_EOK on successfully. + */ +rt_device_t rt_device_create_since_driver(rt_driver_t drv,int device_id) +{ + rt_device_t device; + if (!drv) + { + return RT_NULL; + } + + device = (rt_device_t)rt_calloc(1,drv->device_size); + if(device == RT_NULL) + { + return RT_NULL; + } + device->device_id = device_id; + rt_snprintf(device->parent.name, sizeof(device->parent.name), "%s%d", drv->name, device_id); + return device; +} +RTM_EXPORT(rt_device_create_since_driver); + +/** + * This function rt_device probe and init + * + * @param device the pointer of rt_device structure + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_device_probe_and_init(rt_device_t device) +{ + int ret = -RT_ERROR; + if (!device) + { + return -RT_EINVAL; + } + if(!device->drv) + { + return -RT_ERROR; + } + if(device->drv->probe) + { + ret = device->drv->probe((rt_device_t)device); + } + if(device->drv->probe_init) + { + ret = device->drv->probe_init((rt_device_t)device); + } + return ret; +} +RTM_EXPORT(rt_device_probe_and_init); +#endif /* RT_USING_DM */ #endif /* RT_USING_DEVICE */ diff --git a/src/driver.c b/src/driver.c new file mode 100644 index 0000000000..c402249720 --- /dev/null +++ b/src/driver.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include <rtthread.h> +#ifdef RT_USING_FDT +#include <dtb_node.h> +#endif +#if defined(RT_USING_POSIX_DEVIO) +#include <rtdevice.h> /* for wqueue_init */ +#endif + +/** + * This function driver device match with id + * + * @param drv the pointer of driver structure + * @param device_id the id of the device + * + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_driver_match_with_id(const rt_driver_t drv,int device_id) +{ + rt_device_t device; + int ret; + if (!drv) + { + return -RT_EINVAL; + } + device = rt_device_create_since_driver(drv,device_id); + if(!device) + { + return -RT_ERROR; + } + ret = rt_device_bind_driver(device,drv,RT_NULL); + if(ret != 0) + { + return -RT_ERROR; + } + ret = rt_device_probe_and_init(device); + if(ret != 0) + { + return -RT_ERROR; + } + return ret; +} + +RTM_EXPORT(rt_driver_match_with_id); + +#ifdef RT_USING_FDT +/** + * This function driver device match with dtb_node + * + * @param drv the pointer of driver structure + * @param from_node dtb node entry + * @param max_dev_num the max device support + * + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_driver_match_with_dtb(const rt_driver_t drv,void *from_node,int max_dev_num) +{ + struct dtb_node** node_list; + rt_device_t device; + int ret,i; + int total_dev_num = 0; + if ((!drv)||(!drv->dev_match)||(!drv->dev_match->compatible)||(!from_node)||(!drv->device_size)) + { + return -RT_EINVAL; + } + + node_list = rt_calloc(max_dev_num,sizeof(void *)); + if(!node_list) + { + return -RT_ERROR; + } + + ret = dtb_node_find_all_compatible_node(from_node,drv->dev_match->compatible,node_list,max_dev_num,&total_dev_num); + if((ret != 0) || (!total_dev_num)) + { + return -RT_ERROR; + } + + for(i = 0; i < total_dev_num; i ++) + { + if (!dtb_node_device_is_available(node_list[i])) + { + continue; + } + device = rt_device_create_since_driver(drv,i); + if(!device) + { + continue; + } + + ret = rt_device_bind_driver(device,drv,node_list[i]); + if(ret != 0) + { + continue; + } + ret = rt_device_probe_and_init(device); + if(ret != 0) + { + continue; + } + } + rt_free(node_list); + return ret; +} + +RTM_EXPORT(rt_driver_match_with_dtb); +#endif + @@ -122,11 +122,17 @@ rt_inline rt_err_t _ipc_object_init(struct rt_ipc_object *ipc) * rt_mb_recv(), rt_mq_recv(), rt_mq_send_wait() */ rt_inline rt_err_t _ipc_list_suspend(rt_list_t *list, - struct rt_thread *thread, - rt_uint8_t flag) + struct rt_thread *thread, + rt_uint8_t flag, + int suspend_flag) { + rt_err_t ret = rt_thread_suspend_with_flag(thread, suspend_flag); + /* suspend thread */ - rt_thread_suspend(thread); + if (ret != RT_EOK) + { + return ret; + } switch (flag) { @@ -197,6 +203,8 @@ rt_inline rt_err_t _ipc_list_resume(rt_list_t *list) /* get thread entry */ thread = rt_list_entry(list->next, struct rt_thread, tlist); + thread->error = RT_EOK; + RT_DEBUG_LOG(RT_DEBUG_IPC, ("resume thread:%s\n", thread->name)); /* resume it */ @@ -483,10 +491,11 @@ RTM_EXPORT(rt_sem_delete); * * @warning This function can ONLY be called in the thread context. It MUST NOT BE called in interrupt context. */ -rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t timeout) +static rt_err_t _rt_sem_take(rt_sem_t sem, rt_int32_t timeout, int suspend_flag) { rt_base_t level; struct rt_thread *thread; + rt_err_t ret; /* parameter check */ RT_ASSERT(sem != RT_NULL); @@ -529,15 +538,21 @@ rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t timeout) thread = rt_thread_self(); /* reset thread error number */ - thread->error = RT_EOK; + thread->error = -RT_EINTR; RT_DEBUG_LOG(RT_DEBUG_IPC, ("sem take: suspend thread - %s\n", thread->name)); /* suspend thread */ - _ipc_list_suspend(&(sem->parent.suspend_thread), + ret = _ipc_list_suspend(&(sem->parent.suspend_thread), thread, - sem->parent.parent.flag); + sem->parent.parent.flag, + suspend_flag); + if (ret != RT_EOK) + { + rt_hw_interrupt_enable(level); + return ret; + } /* has waiting time, start thread timer */ if (timeout > 0) @@ -569,8 +584,24 @@ rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t timeout) return RT_EOK; } + +rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time) +{ + return _rt_sem_take(sem, time, RT_UNINTERRUPTIBLE); +} RTM_EXPORT(rt_sem_take); +rt_err_t rt_sem_take_interruptible(rt_sem_t sem, rt_int32_t time) +{ + return _rt_sem_take(sem, time, RT_INTERRUPTIBLE); +} +RTM_EXPORT(rt_sem_take_interruptible); + +rt_err_t rt_sem_take_killable(rt_sem_t sem, rt_int32_t time) +{ + return _rt_sem_take(sem, time, RT_KILLABLE); +} +RTM_EXPORT(rt_sem_take_killable); /** * @brief This function will try to take a semaphore, if the semaphore is unavailable, the thread returns immediately. @@ -745,8 +776,9 @@ rt_inline rt_uint8_t _thread_get_mutex_priority(struct rt_thread* thread) return priority; } -rt_inline void _thread_update_priority(struct rt_thread *thread, rt_uint8_t priority) -{ +rt_inline void _thread_update_priority(struct rt_thread *thread, rt_uint8_t priority, int suspend_flag) +{ + rt_err_t ret; RT_DEBUG_LOG(RT_DEBUG_IPC, ("thread:%s priority -> %d\n", thread->name, priority)); @@ -755,7 +787,7 @@ rt_inline void _thread_update_priority(struct rt_thread *thread, rt_uint8_t prio RT_THREAD_CTRL_CHANGE_PRIORITY, &priority); - if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND) + if ((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK) { /* whether change the priority of taken mutex */ struct rt_object* pending_obj = thread->pending_object; @@ -767,9 +799,16 @@ rt_inline void _thread_update_priority(struct rt_thread *thread, rt_uint8_t prio /* re-insert thread to suspended thread list */ rt_list_remove(&(thread->tlist)); - _ipc_list_suspend(&(pending_mutex->parent.suspend_thread), + + ret = _ipc_list_suspend(&(pending_mutex->parent.suspend_thread), thread, - pending_mutex->parent.parent.flag); + pending_mutex->parent.parent.flag, + suspend_flag); + if (ret != RT_EOK) + { + /* TODO */ + return ; + } /* update priority */ _mutex_update_priority(pending_mutex); @@ -781,7 +820,7 @@ rt_inline void _thread_update_priority(struct rt_thread *thread, rt_uint8_t prio mutex_priority = _thread_get_mutex_priority(pending_mutex->owner); if (mutex_priority != pending_mutex->owner->current_priority) { - _thread_update_priority(pending_mutex->owner, mutex_priority); + _thread_update_priority(pending_mutex->owner, mutex_priority, suspend_flag); } } } @@ -930,7 +969,7 @@ void rt_mutex_drop_thread(rt_mutex_t mutex, rt_thread_t thread) priority = _thread_get_mutex_priority(mutex->owner); if (priority != mutex->owner->current_priority) { - _thread_update_priority(mutex->owner, priority); + _thread_update_priority(mutex->owner, priority, RT_UNINTERRUPTIBLE); } } } @@ -1102,10 +1141,11 @@ RTM_EXPORT(rt_mutex_delete); * * @warning This function can ONLY be called in the thread context. It MUST NOT BE called in interrupt context. */ -rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout) +static rt_err_t _rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout, int suspend_flag) { rt_base_t level; struct rt_thread *thread; + rt_err_t ret; /* this function must not be used in interrupt even if time = 0 */ /* current context checking */ @@ -1157,7 +1197,7 @@ rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout) { /* set the priority of thread to the ceiling priority */ if (mutex->ceiling_priority < mutex->owner->current_priority) - _thread_update_priority(mutex->owner, mutex->ceiling_priority); + _thread_update_priority(mutex->owner, mutex->ceiling_priority, suspend_flag); } else { @@ -1187,9 +1227,16 @@ rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout) thread->name)); /* suspend current thread */ - _ipc_list_suspend(&(mutex->parent.suspend_thread), + ret = _ipc_list_suspend(&(mutex->parent.suspend_thread), thread, - mutex->parent.parent.flag); + mutex->parent.parent.flag, + suspend_flag); + if (ret != RT_EOK) + { + rt_hw_interrupt_enable(level); + return ret; + } + /* set pending object in thread to this mutex */ thread->pending_object = &(mutex->parent.parent); @@ -1199,7 +1246,7 @@ rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout) mutex->priority = priority; if (mutex->priority < mutex->owner->current_priority) { - _thread_update_priority(mutex->owner, priority); + _thread_update_priority(mutex->owner, priority, RT_UNINTERRUPTIBLE); /* TODO */ } } @@ -1265,7 +1312,7 @@ rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout) priority = _thread_get_mutex_priority(mutex->owner); if (priority != mutex->owner->current_priority) { - _thread_update_priority(mutex->owner, priority); + _thread_update_priority(mutex->owner, priority, RT_UNINTERRUPTIBLE); } } @@ -1286,8 +1333,24 @@ rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t timeout) return RT_EOK; } + +rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t time) +{ + return _rt_mutex_take(mutex, time, RT_UNINTERRUPTIBLE); +} RTM_EXPORT(rt_mutex_take); +rt_err_t rt_mutex_take_interruptible(rt_mutex_t mutex, rt_int32_t time) +{ + return _rt_mutex_take(mutex, time, RT_INTERRUPTIBLE); +} +RTM_EXPORT(rt_mutex_take_interruptible); + +rt_err_t rt_mutex_take_killable(rt_mutex_t mutex, rt_int32_t time) +{ + return _rt_mutex_take(mutex, time, RT_KILLABLE); +} +RTM_EXPORT(rt_mutex_take_killable); /** * @brief This function will try to take a mutex, if the mutex is unavailable, the thread returns immediately. @@ -1757,6 +1820,7 @@ rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set) /* resume thread, and thread list breaks out */ rt_thread_resume(thread); + thread->error = RT_EOK; /* need do a scheduling */ need_schedule = RT_TRUE; @@ -1808,15 +1872,17 @@ RTM_EXPORT(rt_event_send); * @return Return the operation status. When the return value is RT_EOK, the operation is successful. * If the return value is any other values, it means that the semaphore release failed. */ -rt_err_t rt_event_recv(rt_event_t event, +static rt_err_t _rt_event_recv(rt_event_t event, rt_uint32_t set, rt_uint8_t option, rt_int32_t timeout, - rt_uint32_t *recved) + rt_uint32_t *recved, + int suspend_flag) { struct rt_thread *thread; rt_base_t level; rt_base_t status; + rt_err_t ret; /* parameter check */ RT_ASSERT(event != RT_NULL); @@ -1833,7 +1899,7 @@ rt_err_t rt_event_recv(rt_event_t event, /* get current thread */ thread = rt_thread_self(); /* reset thread error */ - thread->error = RT_EOK; + thread->error = -RT_EINTR; RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(event->parent.parent))); @@ -1859,6 +1925,8 @@ rt_err_t rt_event_recv(rt_event_t event, if (status == RT_EOK) { + thread->error = RT_EOK; + /* set received event */ if (recved) *recved = (event->set & set); @@ -1888,9 +1956,15 @@ rt_err_t rt_event_recv(rt_event_t event, thread->event_info = option; /* put thread to suspended thread list */ - _ipc_list_suspend(&(event->parent.suspend_thread), + ret = _ipc_list_suspend(&(event->parent.suspend_thread), thread, - event->parent.parent.flag); + event->parent.parent.flag, + suspend_flag); + if (ret != RT_EOK) + { + rt_hw_interrupt_enable(level); + return ret; + } /* if there is a waiting timeout, active thread timer */ if (timeout > 0) @@ -1929,9 +2003,36 @@ rt_err_t rt_event_recv(rt_event_t event, return thread->error; } + +rt_err_t rt_event_recv(rt_event_t event, + rt_uint32_t set, + rt_uint8_t option, + rt_int32_t timeout, + rt_uint32_t *recved) +{ + return _rt_event_recv(event, set, option, timeout, recved, RT_UNINTERRUPTIBLE); +} RTM_EXPORT(rt_event_recv); +rt_err_t rt_event_recv_interruptible(rt_event_t event, + rt_uint32_t set, + rt_uint8_t option, + rt_int32_t timeout, + rt_uint32_t *recved) +{ + return _rt_event_recv(event, set, option, timeout, recved, RT_INTERRUPTIBLE); +} +RTM_EXPORT(rt_event_recv_interruptible); +rt_err_t rt_event_recv_killable(rt_event_t event, + rt_uint32_t set, + rt_uint8_t option, + rt_int32_t timeout, + rt_uint32_t *recved) +{ + return _rt_event_recv(event, set, option, timeout, recved, RT_KILLABLE); +} +RTM_EXPORT(rt_event_recv_killable); /** * @brief This function will set some extra attributions of an event object. * @@ -2234,13 +2335,15 @@ RTM_EXPORT(rt_mb_delete); * * @warning This function can be called in interrupt context and thread context. */ -rt_err_t rt_mb_send_wait(rt_mailbox_t mb, +static rt_err_t _rt_mb_send_wait(rt_mailbox_t mb, rt_ubase_t value, - rt_int32_t timeout) + rt_int32_t timeout, + int suspend_flag) { struct rt_thread *thread; rt_base_t level; rt_uint32_t tick_delta; + rt_err_t ret; /* parameter check */ RT_ASSERT(mb != RT_NULL); @@ -2270,7 +2373,7 @@ rt_err_t rt_mb_send_wait(rt_mailbox_t mb, while (mb->entry == mb->size) { /* reset error number in thread */ - thread->error = RT_EOK; + thread->error = -RT_EINTR; /* no waiting, return timeout */ if (timeout == 0) @@ -2282,9 +2385,16 @@ rt_err_t rt_mb_send_wait(rt_mailbox_t mb, } /* suspend current thread */ - _ipc_list_suspend(&(mb->suspend_sender_thread), + ret = _ipc_list_suspend(&(mb->suspend_sender_thread), thread, - mb->parent.parent.flag); + mb->parent.parent.flag, + suspend_flag); + + if (ret != RT_EOK) + { + rt_hw_interrupt_enable(level); + return ret; + } /* has waiting time, start thread timer */ if (timeout > 0) @@ -2364,9 +2474,30 @@ rt_err_t rt_mb_send_wait(rt_mailbox_t mb, return RT_EOK; } + +rt_err_t rt_mb_send_wait(rt_mailbox_t mb, + rt_ubase_t value, + rt_int32_t timeout) +{ + return _rt_mb_send_wait(mb, value, timeout, RT_UNINTERRUPTIBLE); +} RTM_EXPORT(rt_mb_send_wait); +rt_err_t rt_mb_send_wait_interruptible(rt_mailbox_t mb, + rt_ubase_t value, + rt_int32_t timeout) +{ + return _rt_mb_send_wait(mb, value, timeout, RT_INTERRUPTIBLE); +} +RTM_EXPORT(rt_mb_send_wait_interruptible); +rt_err_t rt_mb_send_wait_killable(rt_mailbox_t mb, + rt_ubase_t value, + rt_int32_t timeout) +{ + return _rt_mb_send_wait(mb, value, timeout, RT_KILLABLE); +} +RTM_EXPORT(rt_mb_send_wait_killable); /** * @brief This function will send an mail to the mailbox object. If there is a thread suspended on the mailbox, * the thread will be resumed. @@ -2390,6 +2521,17 @@ rt_err_t rt_mb_send(rt_mailbox_t mb, rt_ubase_t value) } RTM_EXPORT(rt_mb_send); +rt_err_t rt_mb_send_interruptible(rt_mailbox_t mb, rt_ubase_t value) +{ + return rt_mb_send_wait_interruptible(mb, value, 0); +} +RTM_EXPORT(rt_mb_send_interruptible); + +rt_err_t rt_mb_send_killable(rt_mailbox_t mb, rt_ubase_t value) +{ + return rt_mb_send_wait_killable(mb, value, 0); +} +RTM_EXPORT(rt_mb_send_killable); /** * @brief This function will send an urgent mail to the mailbox object. @@ -2488,11 +2630,12 @@ RTM_EXPORT(rt_mb_urgent); * @return Return the operation status. When the return value is RT_EOK, the operation is successful. * If the return value is any other values, it means that the mailbox release failed. */ -rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout) +static rt_err_t _rt_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout, int suspend_flag) { struct rt_thread *thread; rt_base_t level; rt_uint32_t tick_delta; + rt_err_t ret; /* parameter check */ RT_ASSERT(mb != RT_NULL); @@ -2523,7 +2666,7 @@ rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout) while (mb->entry == 0) { /* reset error number in thread */ - thread->error = RT_EOK; + thread->error = -RT_EINTR; /* no waiting, return timeout */ if (timeout == 0) @@ -2537,9 +2680,15 @@ rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout) } /* suspend current thread */ - _ipc_list_suspend(&(mb->parent.suspend_thread), + ret = _ipc_list_suspend(&(mb->parent.suspend_thread), thread, - mb->parent.parent.flag); + mb->parent.parent.flag, + suspend_flag); + if (ret != RT_EOK) + { + rt_hw_interrupt_enable(level); + return ret; + } /* has waiting time, start thread timer */ if (timeout > 0) @@ -2619,8 +2768,24 @@ rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout) return RT_EOK; } + +rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout) +{ + return _rt_mb_recv(mb, value, timeout, RT_UNINTERRUPTIBLE); +} RTM_EXPORT(rt_mb_recv); +rt_err_t rt_mb_recv_interruptibale(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout) +{ + return _rt_mb_recv(mb, value, timeout, RT_INTERRUPTIBLE); +} +RTM_EXPORT(rt_mb_recv_interruptibale); + +rt_err_t rt_mb_recv_killable(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout) +{ + return _rt_mb_recv(mb, value, timeout, RT_KILLABLE); +} +RTM_EXPORT(rt_mb_recv_killable); /** * @brief This function will set some extra attributions of a mailbox object. @@ -2738,6 +2903,7 @@ rt_err_t rt_mq_init(rt_mq_t mq, { struct rt_mq_message *head; rt_base_t temp; + register rt_size_t msg_align_size; /* parameter check */ RT_ASSERT(mq != RT_NULL); @@ -2756,8 +2922,14 @@ rt_err_t rt_mq_init(rt_mq_t mq, mq->msg_pool = msgpool; /* get correct message size */ - mq->msg_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE); - mq->max_msgs = (rt_uint16_t)(pool_size / (mq->msg_size + sizeof(struct rt_mq_message))); + msg_align_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE); + mq->msg_size = msg_size; + mq->max_msgs = pool_size / (msg_align_size + sizeof(struct rt_mq_message)); + + if (0 == mq->max_msgs) + { + return -RT_EINVAL; + } /* initialize message list */ mq->msg_queue_head = RT_NULL; @@ -2768,7 +2940,7 @@ rt_err_t rt_mq_init(rt_mq_t mq, for (temp = 0; temp < mq->max_msgs; temp ++) { head = (struct rt_mq_message *)((rt_uint8_t *)mq->msg_pool + - temp * (mq->msg_size + sizeof(struct rt_mq_message))); + temp * (msg_align_size + sizeof(struct rt_mq_message))); head->next = (struct rt_mq_message *)mq->msg_queue_free; mq->msg_queue_free = head; } @@ -2862,6 +3034,7 @@ rt_mq_t rt_mq_create(const char *name, struct rt_messagequeue *mq; struct rt_mq_message *head; rt_base_t temp; + register rt_size_t msg_align_size; RT_ASSERT((flag == RT_IPC_FLAG_FIFO) || (flag == RT_IPC_FLAG_PRIO)); @@ -2881,11 +3054,12 @@ rt_mq_t rt_mq_create(const char *name, /* initialize message queue */ /* get correct message size */ - mq->msg_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE); - mq->max_msgs = (rt_uint16_t)max_msgs; + msg_align_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE); + mq->msg_size = msg_size; + mq->max_msgs = max_msgs; /* allocate message pool */ - mq->msg_pool = RT_KERNEL_MALLOC((mq->msg_size + sizeof(struct rt_mq_message)) * mq->max_msgs); + mq->msg_pool = RT_KERNEL_MALLOC((msg_align_size + sizeof(struct rt_mq_message)) * mq->max_msgs); if (mq->msg_pool == RT_NULL) { rt_object_delete(&(mq->parent.parent)); @@ -2902,7 +3076,7 @@ rt_mq_t rt_mq_create(const char *name, for (temp = 0; temp < mq->max_msgs; temp ++) { head = (struct rt_mq_message *)((rt_uint8_t *)mq->msg_pool + - temp * (mq->msg_size + sizeof(struct rt_mq_message))); + temp * (msg_align_size + sizeof(struct rt_mq_message))); head->next = (struct rt_mq_message *)mq->msg_queue_free; mq->msg_queue_free = head; } @@ -2992,15 +3166,17 @@ RTM_EXPORT(rt_mq_delete); * @warning This function can be called in interrupt context and thread * context. */ -rt_err_t rt_mq_send_wait(rt_mq_t mq, +static rt_err_t _rt_mq_send_wait(rt_mq_t mq, const void *buffer, rt_size_t size, - rt_int32_t timeout) + rt_int32_t timeout, + int suspend_flag) { rt_base_t level; struct rt_mq_message *msg; rt_uint32_t tick_delta; struct rt_thread *thread; + rt_err_t ret; /* parameter check */ RT_ASSERT(mq != RT_NULL); @@ -3040,7 +3216,7 @@ rt_err_t rt_mq_send_wait(rt_mq_t mq, while ((msg = (struct rt_mq_message *)mq->msg_queue_free) == RT_NULL) { /* reset error number in thread */ - thread->error = RT_EOK; + thread->error = -RT_EINTR; /* no waiting, return timeout */ if (timeout == 0) @@ -3052,9 +3228,15 @@ rt_err_t rt_mq_send_wait(rt_mq_t mq, } /* suspend current thread */ - _ipc_list_suspend(&(mq->suspend_sender_thread), + ret = _ipc_list_suspend(&(mq->suspend_sender_thread), thread, - mq->parent.parent.flag); + mq->parent.parent.flag, + suspend_flag); + if (ret != RT_EOK) + { + rt_hw_interrupt_enable(level); + return ret; + } /* has waiting time, start thread timer */ if (timeout > 0) @@ -3153,9 +3335,33 @@ rt_err_t rt_mq_send_wait(rt_mq_t mq, return RT_EOK; } + +rt_err_t rt_mq_send_wait(rt_mq_t mq, + const void *buffer, + rt_size_t size, + rt_int32_t timeout) +{ + return _rt_mq_send_wait(mq, buffer, size, timeout, RT_UNINTERRUPTIBLE); +} RTM_EXPORT(rt_mq_send_wait) +rt_err_t rt_mq_send_wait_interruptible(rt_mq_t mq, + const void *buffer, + rt_size_t size, + rt_int32_t timeout) +{ + return _rt_mq_send_wait(mq, buffer, size, timeout, RT_INTERRUPTIBLE); +} +RTM_EXPORT(rt_mq_send_wait_interruptible) +rt_err_t rt_mq_send_wait_killable(rt_mq_t mq, + const void *buffer, + rt_size_t size, + rt_int32_t timeout) +{ + return _rt_mq_send_wait(mq, buffer, size, timeout, RT_KILLABLE); +} +RTM_EXPORT(rt_mq_send_wait_killable) /** * @brief This function will send a message to the messagequeue object. * If there is a thread suspended on the messagequeue, the thread will be resumed. @@ -3184,7 +3390,17 @@ rt_err_t rt_mq_send(rt_mq_t mq, const void *buffer, rt_size_t size) } RTM_EXPORT(rt_mq_send); +rt_err_t rt_mq_send_interrupt(rt_mq_t mq, const void *buffer, rt_size_t size) +{ + return rt_mq_send_wait_interruptible(mq, buffer, size, 0); +} +RTM_EXPORT(rt_mq_send_interrupt); +rt_err_t rt_mq_send_killable(rt_mq_t mq, const void *buffer, rt_size_t size) +{ + return rt_mq_send_wait_killable(mq, buffer, size, 0); +} +RTM_EXPORT(rt_mq_send_killable); /** * @brief This function will send an urgent message to the messagequeue object. * @@ -3311,15 +3527,17 @@ RTM_EXPORT(rt_mq_urgent); * @return Return the operation status. When the return value is RT_EOK, the operation is successful. * If the return value is any other values, it means that the mailbox release failed. */ -rt_err_t rt_mq_recv(rt_mq_t mq, +static rt_err_t _rt_mq_recv(rt_mq_t mq, void *buffer, rt_size_t size, - rt_int32_t timeout) + rt_int32_t timeout, + int suspend_flag) { struct rt_thread *thread; rt_base_t level; struct rt_mq_message *msg; rt_uint32_t tick_delta; + rt_err_t ret; /* parameter check */ RT_ASSERT(mq != RT_NULL); @@ -3351,7 +3569,7 @@ rt_err_t rt_mq_recv(rt_mq_t mq, while (mq->entry == 0) { /* reset error number in thread */ - thread->error = RT_EOK; + thread->error = -RT_EINTR; /* no waiting, return timeout */ if (timeout == 0) @@ -3365,9 +3583,15 @@ rt_err_t rt_mq_recv(rt_mq_t mq, } /* suspend current thread */ - _ipc_list_suspend(&(mq->parent.suspend_thread), + ret = _ipc_list_suspend(&(mq->parent.suspend_thread), thread, - mq->parent.parent.flag); + mq->parent.parent.flag, + suspend_flag); + if (ret != RT_EOK) + { + rt_hw_interrupt_enable(level); + return ret; + } /* has waiting time, start thread timer */ if (timeout > 0) @@ -3460,9 +3684,33 @@ rt_err_t rt_mq_recv(rt_mq_t mq, return RT_EOK; } + +rt_err_t rt_mq_recv(rt_mq_t mq, + void *buffer, + rt_size_t size, + rt_int32_t timeout) +{ + return _rt_mq_recv(mq, buffer, size, timeout, RT_UNINTERRUPTIBLE); +} RTM_EXPORT(rt_mq_recv); +rt_err_t rt_mq_recv_interruptible(rt_mq_t mq, + void *buffer, + rt_size_t size, + rt_int32_t timeout) +{ + return _rt_mq_recv(mq, buffer, size, timeout, RT_INTERRUPTIBLE); +} +RTM_EXPORT(rt_mq_recv_interruptible); +rt_err_t rt_mq_recv_killable(rt_mq_t mq, + void *buffer, + rt_size_t size, + rt_int32_t timeout) +{ + return _rt_mq_recv(mq, buffer, size, timeout, RT_KILLABLE); +} +RTM_EXPORT(rt_mq_recv_killable); /** * @brief This function will set some extra attributions of a messagequeue object. * diff --git a/src/kservice.c b/src/kservice.c index 2fd38d330e..ba93b61c7e 100644 --- a/src/kservice.c +++ b/src/kservice.c @@ -32,6 +32,12 @@ #include <dlmodule.h> #endif /* RT_USING_MODULE */ +#ifdef RT_USING_LWP +#include <lwp.h> +#include <lwp_user_mm.h> +#include <console.h> +#endif + /* use precision */ #define RT_PRINTF_PRECISION @@ -96,7 +102,7 @@ RTM_EXPORT(rt_strerror); */ rt_err_t rt_get_errno(void) { - rt_thread_t tid; + rt_thread_t tid = RT_NULL; if (rt_interrupt_get_nest() != 0) { @@ -106,7 +112,9 @@ rt_err_t rt_get_errno(void) tid = rt_thread_self(); if (tid == RT_NULL) + { return __rt_errno; + } return tid->error; } @@ -119,7 +127,7 @@ RTM_EXPORT(rt_get_errno); */ void rt_set_errno(rt_err_t error) { - rt_thread_t tid; + rt_thread_t tid = RT_NULL; if (rt_interrupt_get_nest() != 0) { @@ -148,14 +156,18 @@ RTM_EXPORT(rt_set_errno); */ int *_rt_errno(void) { - rt_thread_t tid; + rt_thread_t tid = RT_NULL; if (rt_interrupt_get_nest() != 0) + { return (int *)&__rt_errno; + } tid = rt_thread_self(); if (tid != RT_NULL) + { return (int *) & (tid->error); + } return (int *)&__rt_errno; } @@ -188,10 +200,10 @@ RT_WEAK void *rt_memset(void *s, int c, rt_ubase_t count) #define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1)) #define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE) - unsigned int i; + unsigned int i = 0; char *m = (char *)s; - unsigned long buffer; - unsigned long *aligned_addr; + unsigned long buffer = 0; + unsigned long *aligned_addr = RT_NULL; unsigned char d = (unsigned int)c & (unsigned char)(-1); /* To avoid sign extension, copy C to an unsigned variable. (unsigned)((char)(-1))=0xFF for 8bit and =0xFFFF for 16bit: word independent */ @@ -258,7 +270,7 @@ RT_WEAK void *rt_memcpy(void *dst, const void *src, rt_ubase_t count) { #ifdef RT_KSERVICE_USING_TINY_SIZE char *tmp = (char *)dst, *s = (char *)src; - rt_ubase_t len; + rt_ubase_t len = 0; if (tmp <= s || tmp > (s + count)) { @@ -282,8 +294,8 @@ RT_WEAK void *rt_memcpy(void *dst, const void *src, rt_ubase_t count) char *dst_ptr = (char *)dst; char *src_ptr = (char *)src; - long *aligned_dst; - long *aligned_src; + long *aligned_dst = RT_NULL; + long *aligned_src = RT_NULL; rt_ubase_t len = count; /* If the size is small, or either SRC or DST is unaligned, @@ -378,7 +390,7 @@ RTM_EXPORT(rt_memmove); */ rt_int32_t rt_memcmp(const void *cs, const void *ct, rt_size_t count) { - const unsigned char *su1, *su2; + const unsigned char *su1 = RT_NULL, *su2 = RT_NULL; int res = 0; for (su1 = (const unsigned char *)cs, su2 = (const unsigned char *)ct; 0 < count; ++su1, ++su2, count--) @@ -403,17 +415,23 @@ RTM_EXPORT(rt_memcmp); */ char *rt_strstr(const char *s1, const char *s2) { - int l1, l2; + int l1 = 0, l2 = 0; l2 = rt_strlen(s2); if (!l2) - return (char *)s1; + { + return (char *)s1; + } + l1 = rt_strlen(s1); while (l1 >= l2) { l1 --; if (!rt_memcmp(s1, s2, l2)) - return (char *)s1; + { + return (char *)s1; + } + s1 ++; } @@ -435,7 +453,7 @@ RTM_EXPORT(rt_strstr); */ rt_int32_t rt_strcasecmp(const char *a, const char *b) { - int ca, cb; + int ca = 0, cb = 0; do { @@ -476,7 +494,10 @@ char *rt_strncpy(char *dst, const char *src, rt_size_t n) { /* NUL pad the remaining n-1 bytes */ while (--n != 0) - *d++ = 0; + { + *d++ = 0; + } + break; } } while (--n != 0); @@ -532,7 +553,10 @@ rt_int32_t rt_strncmp(const char *cs, const char *ct, rt_size_t count) while (count) { if ((__res = *cs - *ct++) != 0 || !*cs++) - break; + { + break; + } + count --; } @@ -574,7 +598,7 @@ RTM_EXPORT(rt_strcmp); */ rt_size_t rt_strlen(const char *s) { - const char *sc; + const char *sc = RT_NULL; for (sc = s; *sc != '\0'; ++sc) /* nothing */ ; @@ -623,7 +647,9 @@ char *rt_strdup(const char *s) char *tmp = (char *)rt_malloc(len); if (!tmp) - return RT_NULL; + { + return RT_NULL; + } rt_memcpy(tmp, s, len); @@ -1230,6 +1256,28 @@ RTM_EXPORT(rt_console_get_device); */ rt_device_t rt_console_set_device(const char *name) { +#ifdef RT_USING_LWP + rt_device_t new_iodev = RT_NULL, old_iodev = RT_NULL; +extern void console_init(); + console_init(); /*add line discipline*/ + /* find new console device */ + new_iodev = rt_device_find(name); + if (new_iodev != RT_NULL) + { + if (_console_device != RT_NULL) + { + old_iodev = console_set_iodev(new_iodev); + } + else + { + console_register("console", new_iodev); + _console_device = rt_device_find("console"); + rt_device_open(_console_device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_STREAM); + } + } + + return old_iodev; +#else rt_device_t new_device, old_device; /* save old device */ @@ -1255,6 +1303,7 @@ rt_device_t rt_console_set_device(const char *name) } return old_device; +#endif } RTM_EXPORT(rt_console_set_device); #endif /* RT_USING_DEVICE */ @@ -1702,7 +1751,7 @@ RTM_EXPORT(rt_malloc_align); */ RT_WEAK void rt_free_align(void *ptr) { - void *real_ptr; + void *real_ptr = RT_NULL; /* NULL check */ if (ptr == RT_NULL) return; diff --git a/src/object.c b/src/object.c index cb177edbe6..606e4c00ff 100644 --- a/src/object.c +++ b/src/object.c @@ -23,6 +23,17 @@ #include <dlmodule.h> #endif /* RT_USING_MODULE */ +#ifdef RT_USING_LWP +#include <lwp.h> +#endif + +struct rt_custom_object +{ + struct rt_object parent; + rt_err_t (*destroy)(void *); + void *data; +}; + /* * define object_info for the number of _object_container items. */ @@ -60,6 +71,12 @@ enum rt_object_info_type #ifdef RT_USING_HEAP RT_Object_Info_Memory, /**< The object is a memory. */ #endif +#ifdef RT_USING_LWP + RT_Object_Info_Channel, /**< The object is a IPC channel */ +#endif +#ifdef RT_USING_HEAP + RT_Object_Info_Custom, /**< The object is a custom object */ +#endif RT_Object_Info_Unknown, /**< The object is unknown. */ }; @@ -112,6 +129,11 @@ static struct rt_object_information _object_container[RT_Object_Info_Unknown] = /* initialize object container - small memory */ {RT_Object_Class_Memory, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Memory), sizeof(struct rt_memory)}, #endif +#ifdef RT_USING_LWP + /* initialize object container - module */ + {RT_Object_Class_Channel, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Channel), sizeof(struct rt_channel)}, + {RT_Object_Class_Custom, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Custom), sizeof(struct rt_custom_object)}, +#endif }; #ifndef __on_rt_object_attach_hook @@ -607,4 +629,60 @@ rt_object_t rt_object_find(const char *name, rt_uint8_t type) return RT_NULL; } +#ifdef RT_USING_HEAP +/** + * This function will create a custom object + * container. + * + * @param name the specified name of object. + * @param type the type of object + * @param data the custom data + * @param data_destroy the custom object destroy callback + * + * @return the found object or RT_NULL if there is no this object + * in object container. + * + * @note this function shall not be invoked in interrupt status. + */ + +rt_object_t rt_custom_object_create(const char *name, void *data, rt_err_t (*data_destroy)(void *)) +{ + struct rt_custom_object *cobj = RT_NULL; + + cobj = (struct rt_custom_object *)rt_object_allocate(RT_Object_Class_Custom, name); + if (!cobj) + { + return RT_NULL; + } + cobj->destroy = data_destroy; + cobj->data = data; + return (struct rt_object *)cobj; +} + +/** + * This function will destroy a custom object + * container. + * + * @param obj the specified name of object. + * + * @note this function shall not be invoked in interrupt status. + */ +rt_err_t rt_custom_object_destroy(rt_object_t obj) +{ + rt_err_t ret = -1; + + struct rt_custom_object *cobj = (struct rt_custom_object *)obj; + + if (obj && obj->type == RT_Object_Class_Custom) + { + if (cobj->destroy) + { + ret = cobj->destroy(cobj->data); + } + rt_object_delete(obj); + } + return ret; +} +#endif + /**@}*/ diff --git a/src/scheduler.c b/src/scheduler.c index 8148c144a4..938f45822b 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -33,6 +33,10 @@ #include <rtthread.h> #include <rthw.h> +#ifdef RT_USING_LWP +#include <lwp.h> +#endif /* RT_USING_LWP */ + 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 @@ -94,6 +98,19 @@ static void _scheduler_stack_check(struct rt_thread *thread) { RT_ASSERT(thread != RT_NULL); +#ifdef RT_USING_LWP +#ifndef ARCH_MM_MMU + struct rt_lwp *lwp = thread ? (struct rt_lwp *)thread->lwp : 0; + + /* if stack pointer locate in user data section skip stack check. */ + if (lwp && ((rt_uint32_t)thread->sp > (rt_uint32_t)lwp->data_entry && + (rt_uint32_t)thread->sp <= (rt_uint32_t)lwp->data_entry + (rt_uint32_t)lwp->data_size)) + { + return; + } +#endif /* not defined ARCH_MM_MMU */ +#endif /* RT_USING_LWP */ + #ifdef ARCH_CPU_STACK_GROWS_UPWARD if (*((rt_uint8_t *)((rt_ubase_t)thread->stack_addr + thread->stack_size - 1)) != '#' || #else @@ -322,13 +339,17 @@ void rt_schedule(void) } #ifdef RT_USING_SIGNALS - if ((current_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND) + if ((current_thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK) { /* if current_thread signal is in pending */ if ((current_thread->stat & RT_THREAD_STAT_SIGNAL_MASK) & RT_THREAD_STAT_SIGNAL_PENDING) { +#ifdef RT_USING_LWP + rt_thread_wakeup(current_thread); +#else rt_thread_resume(current_thread); +#endif } } #endif /* RT_USING_SIGNALS */ @@ -343,13 +364,20 @@ void rt_schedule(void) current_thread->oncpu = RT_CPU_DETACHED; if ((current_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING) { - if (current_thread->current_priority < highest_ready_priority) + if (current_thread->bind_cpu == RT_CPUS_NR || current_thread->bind_cpu == cpu_id) { - to_thread = current_thread; - } - else if (current_thread->current_priority == highest_ready_priority && (current_thread->stat & RT_THREAD_STAT_YIELD_MASK) == 0) - { - to_thread = current_thread; + if (current_thread->current_priority < highest_ready_priority) + { + to_thread = current_thread; + } + else if (current_thread->current_priority == highest_ready_priority && (current_thread->stat & RT_THREAD_STAT_YIELD_MASK) == 0) + { + to_thread = current_thread; + } + else + { + rt_schedule_insert_thread(current_thread); + } } else { @@ -526,7 +554,7 @@ void rt_schedule(void) RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("switch in interrupt\n")); rt_hw_context_switch_interrupt((rt_ubase_t)&from_thread->sp, - (rt_ubase_t)&to_thread->sp); + (rt_ubase_t)&to_thread->sp, from_thread, to_thread); } } else @@ -566,13 +594,17 @@ void rt_scheduler_do_irq_switch(void *context) current_thread = pcpu->current_thread; #ifdef RT_USING_SIGNALS - if ((current_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND) + if ((current_thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK) { /* if current_thread signal is in pending */ if ((current_thread->stat & RT_THREAD_STAT_SIGNAL_MASK) & RT_THREAD_STAT_SIGNAL_PENDING) { +#ifdef RT_USING_LWP + rt_thread_wakeup(current_thread); +#else rt_thread_resume(current_thread); +#endif } } #endif /* RT_USING_SIGNALS */ @@ -596,13 +628,20 @@ void rt_scheduler_do_irq_switch(void *context) current_thread->oncpu = RT_CPU_DETACHED; if ((current_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING) { - if (current_thread->current_priority < highest_ready_priority) - { - to_thread = current_thread; - } - else if (current_thread->current_priority == highest_ready_priority && (current_thread->stat & RT_THREAD_STAT_YIELD_MASK) == 0) + if (current_thread->bind_cpu == RT_CPUS_NR || current_thread->bind_cpu == cpu_id) { - to_thread = current_thread; + if (current_thread->current_priority < highest_ready_priority) + { + to_thread = current_thread; + } + else if (current_thread->current_priority == highest_ready_priority && (current_thread->stat & RT_THREAD_STAT_YIELD_MASK) == 0) + { + to_thread = current_thread; + } + else + { + rt_schedule_insert_thread(current_thread); + } } else { diff --git a/src/signal.c b/src/signal.c index 60996a6e08..e24bb931d7 100644 --- a/src/signal.c +++ b/src/signal.c @@ -102,10 +102,14 @@ static void _signal_deliver(rt_thread_t tid) return; } - if ((tid->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND) + if ((tid->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK) { /* resume thread to handle signal */ +#ifdef RT_USING_LWP + rt_thread_wakeup(tid); +#else rt_thread_resume(tid); +#endif /* add signal state */ tid->stat |= (RT_THREAD_STAT_SIGNAL | RT_THREAD_STAT_SIGNAL_PENDING); @@ -197,7 +201,7 @@ void *rt_signal_check(void* context) rt_hw_interrupt_enable(level); sig_context = rt_hw_stack_init((void *)_signal_entry, context, - (void *)(context - 32), RT_NULL); + (void*)((char*)context - 32), RT_NULL); return sig_context; } } @@ -350,7 +354,7 @@ int rt_signal_wait(const rt_sigset_t *set, rt_siginfo_t *si, rt_int32_t timeout) } /* suspend self thread */ - rt_thread_suspend(tid); + rt_thread_suspend_with_flag(tid, RT_UNINTERRUPTIBLE); /* set thread stat as waiting for signal */ tid->stat |= RT_THREAD_STAT_SIGNAL_WAIT; diff --git a/src/thread.c b/src/thread.c index 9d37861c5a..1bc4169d30 100644 --- a/src/thread.c +++ b/src/thread.c @@ -133,7 +133,7 @@ static void _thread_timeout(void *parameter) /* parameter check */ RT_ASSERT(thread != RT_NULL); - RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND); + RT_ASSERT((thread->stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK); RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread); /* disable interrupt */ @@ -167,6 +167,10 @@ static rt_err_t _thread_init(struct rt_thread *thread, /* init thread list */ rt_list_init(&(thread->tlist)); +#ifdef RT_USING_LWP + thread->wakeup.func = RT_NULL; +#endif + thread->entry = (void *)entry; thread->parameter = parameter; @@ -253,7 +257,13 @@ static rt_err_t _thread_init(struct rt_thread *thread, #ifdef RT_USING_LWP thread->lwp = RT_NULL; -#endif /* RT_USING_LWP */ + rt_list_init(&(thread->sibling)); + rt_memset(&thread->signal, 0, sizeof(lwp_sigset_t)); + rt_memset(&thread->signal_mask, 0, sizeof(lwp_sigset_t)); + thread->signal_mask_bak = 0; + thread->signal_in_process = 0; + rt_memset(&thread->user_ctx, 0, sizeof thread->user_ctx); +#endif #ifdef RT_USING_CPU_USAGE thread->duration_tick = 0; @@ -598,6 +608,7 @@ rt_err_t rt_thread_sleep(rt_tick_t tick) { rt_base_t level; struct rt_thread *thread; + int err; if (tick == 0) { @@ -619,22 +630,31 @@ rt_err_t rt_thread_sleep(rt_tick_t tick) thread->error = RT_EOK; /* suspend thread */ - rt_thread_suspend(thread); + err = rt_thread_suspend_with_flag(thread, RT_INTERRUPTIBLE); /* reset the timeout of thread timer and start it */ - rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick); - rt_timer_start(&(thread->thread_timer)); + if (err == RT_EOK) + { + rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick); + rt_timer_start(&(thread->thread_timer)); - /* enable interrupt */ - rt_hw_interrupt_enable(level); + /* enable interrupt */ + rt_hw_interrupt_enable(level); - rt_schedule(); + thread->error = -RT_EINTR; + + rt_schedule(); - /* clear error number of this thread to RT_EOK */ - if (thread->error == -RT_ETIMEOUT) - thread->error = RT_EOK; + /* clear error number of this thread to RT_EOK */ + if (thread->error == -RT_ETIMEOUT) + thread->error = RT_EOK; + } + else + { + rt_hw_interrupt_enable(level); + } - return thread->error; + return err; } /** @@ -689,7 +709,7 @@ rt_err_t rt_thread_delay_until(rt_tick_t *tick, rt_tick_t inc_tick) left_tick = *tick - cur_tick; /* suspend thread */ - rt_thread_suspend(thread); + rt_thread_suspend_with_flag(thread, RT_UNINTERRUPTIBLE); /* reset the timeout of thread timer and start it */ rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &left_tick); @@ -734,6 +754,66 @@ rt_err_t rt_thread_mdelay(rt_int32_t ms) } RTM_EXPORT(rt_thread_mdelay); +#ifdef RT_USING_SMP +static void rt_thread_cpu_bind(rt_thread_t thread, int cpu) +{ + rt_base_t level; + + if (cpu >= RT_CPUS_NR) + { + cpu = RT_CPUS_NR; + } + + level = rt_hw_interrupt_disable(); + if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY) + { + /* unbind */ + /* remove from old ready queue */ + rt_schedule_remove_thread(thread); + /* change thread bind cpu */ + thread->bind_cpu = cpu; + /* add to new ready queue */ + rt_schedule_insert_thread(thread); + if (rt_thread_self() != RT_NULL) + { + rt_schedule(); + } + } + else + { + thread->bind_cpu = cpu; + if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING) + { + /* thread is running on a cpu */ + int current_cpu = rt_hw_cpu_id(); + + if (cpu != RT_CPUS_NR) + { + if (thread->oncpu == current_cpu) + { + /* current thread on current cpu */ + if (cpu != current_cpu) + { + /* bind to other cpu */ + rt_hw_ipi_send(RT_SCHEDULE_IPI, 1U << cpu); + /* self cpu need reschedule */ + rt_schedule(); + } + /* else do nothing */ + } + else + { + /* no running on self cpu, but dest cpu can be itself */ + rt_hw_ipi_send(RT_SCHEDULE_IPI, 1U << thread->oncpu); + } + } + /* else do nothing */ + } + } + rt_hw_interrupt_enable(level); +} +#endif + /** * @brief This function will control thread behaviors according to control command. * @@ -837,26 +917,46 @@ rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg) { 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; - } - - cpu = (rt_uint8_t)(rt_size_t)arg; - thread->bind_cpu = cpu > RT_CPUS_NR? RT_CPUS_NR : cpu; - break; - } - #endif /* RT_USING_SMP */ - - default: - break; + cpu = (rt_uint8_t)(size_t)arg; + rt_thread_cpu_bind(thread, cpu); + break; + } +#endif /*RT_USING_SMP*/ + default: + break; } return RT_EOK; } RTM_EXPORT(rt_thread_control); +#ifdef RT_USING_LWP +int lwp_suspend_sigcheck(rt_thread_t thread, int suspend_flag); +#endif + +static void rt_thread_set_suspend_state(struct rt_thread *thread, int suspend_flag) +{ + rt_uint8_t stat = RT_THREAD_SUSPEND_UNINTERRUPTIBLE; + + RT_ASSERT(thread != RT_NULL); + switch (suspend_flag) + { + case RT_INTERRUPTIBLE: + stat = RT_THREAD_SUSPEND_INTERRUPTIBLE; + break; + case RT_KILLABLE: + stat = RT_THREAD_SUSPEND_KILLABLE; + break; + case RT_UNINTERRUPTIBLE: + stat = RT_THREAD_SUSPEND_UNINTERRUPTIBLE; + break; + default: + RT_ASSERT(0); + break; + } + thread->stat = stat | (thread->stat & ~RT_THREAD_STAT_MASK); +} + /** * @brief This function will suspend the specified thread and change it to suspend state. * @@ -872,7 +972,7 @@ RTM_EXPORT(rt_thread_control); * @return Return the operation status. If the return value is RT_EOK, the function is successfully executed. * If the return value is any other values, it means this operation failed. */ -rt_err_t rt_thread_suspend(rt_thread_t thread) +rt_err_t rt_thread_suspend_with_flag(rt_thread_t thread, int suspend_flag) { rt_base_t stat; rt_base_t level; @@ -893,10 +993,24 @@ rt_err_t rt_thread_suspend(rt_thread_t thread) /* disable interrupt */ level = rt_hw_interrupt_disable(); + if (stat == RT_THREAD_RUNNING) + { + /* not suspend running status thread on other core */ + RT_ASSERT(thread == rt_thread_self()); + } +#ifdef RT_USING_LWP + if (lwp_suspend_sigcheck(thread, suspend_flag) == 0) + { + /* not to suspend */ + rt_hw_interrupt_enable(level); + rt_kprintf("-RT_EINTR\r\n"); + return -RT_EINTR; + } +#endif /* change thread stat */ rt_schedule_remove_thread(thread); - thread->stat = RT_THREAD_SUSPEND | (thread->stat & ~RT_THREAD_STAT_MASK); + rt_thread_set_suspend_state(thread, suspend_flag); /* stop thread timer anyway */ rt_timer_stop(&(thread->thread_timer)); @@ -907,6 +1021,12 @@ rt_err_t rt_thread_suspend(rt_thread_t thread) RT_OBJECT_HOOK_CALL(rt_thread_suspend_hook, (thread)); return RT_EOK; } +RTM_EXPORT(rt_thread_suspend_with_flag); + +rt_err_t rt_thread_suspend(rt_thread_t thread) +{ + return rt_thread_suspend_with_flag(thread, RT_UNINTERRUPTIBLE); +} RTM_EXPORT(rt_thread_suspend); /** @@ -927,7 +1047,7 @@ rt_err_t rt_thread_resume(rt_thread_t thread) RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: %s\n", thread->name)); - if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_SUSPEND) + if ((thread->stat & RT_THREAD_SUSPEND_MASK) != RT_THREAD_SUSPEND_MASK) { RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: thread disorder, %d\n", thread->stat)); @@ -943,17 +1063,67 @@ rt_err_t rt_thread_resume(rt_thread_t thread) rt_timer_stop(&thread->thread_timer); - /* insert to schedule ready list */ - rt_schedule_insert_thread(thread); +#ifdef RT_USING_LWP + thread->wakeup.func = RT_NULL; +#endif /* enable interrupt */ rt_hw_interrupt_enable(level); + /* insert to schedule ready list */ + rt_schedule_insert_thread(thread); + RT_OBJECT_HOOK_CALL(rt_thread_resume_hook, (thread)); return RT_EOK; } RTM_EXPORT(rt_thread_resume); +#ifdef RT_USING_LWP +/** + * This function will wakeup a thread with customized operation. + * + * @param thread the thread to be resumed + * + * @return the operation status, RT_EOK on OK, -RT_ERROR on error + */ +rt_err_t rt_thread_wakeup(rt_thread_t thread) +{ + register rt_base_t temp; + rt_err_t ret; + + RT_ASSERT(thread != RT_NULL); + RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread); + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + if (thread->wakeup.func) + { + ret = thread->wakeup.func(thread->wakeup.user_data, thread); + thread->wakeup.func = RT_NULL; + } + else + { + ret = rt_thread_resume(thread); + } + + rt_hw_interrupt_enable(temp); + return ret; +} +RTM_EXPORT(rt_thread_wakeup); + +void rt_thread_wakeup_set(struct rt_thread *thread, rt_wakeup_func_t func, void* user_data) +{ + register rt_base_t temp; + + RT_ASSERT(thread != RT_NULL); + RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread); + + temp = rt_hw_interrupt_disable(); + thread->wakeup.func = func; + thread->wakeup.user_data = user_data; + rt_hw_interrupt_enable(temp); +} +RTM_EXPORT(rt_thread_wakeup_set); +#endif /** * @brief This function will find the specified thread. * diff --git a/src/timer.c b/src/timer.c index ce11bf3518..5e200c0c95 100644 --- a/src/timer.c +++ b/src/timer.c @@ -502,7 +502,7 @@ rt_err_t rt_timer_start(rt_timer_t timer) { /* check whether timer thread is ready */ if ((_soft_timer_status == RT_SOFT_TIMER_IDLE) && - ((_timer_thread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND)) + ((_timer_thread.stat & RT_THREAD_SUSPEND_MASK) == RT_THREAD_SUSPEND_MASK)) { /* resume timer thread to check soft timer */ rt_thread_resume(&_timer_thread); @@ -534,18 +534,21 @@ rt_err_t rt_timer_stop(rt_timer_t timer) { rt_base_t level; - /* parameter check */ + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + /* timer check */ RT_ASSERT(timer != RT_NULL); RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)) + { + rt_hw_interrupt_enable(level); return -RT_ERROR; + } RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(timer->parent))); - /* disable interrupt */ - level = rt_hw_interrupt_disable(); - _timer_remove(timer); /* change status */ timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; @@ -610,6 +613,21 @@ rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg) case RT_TIMER_CTRL_GET_REMAIN_TIME: *(rt_tick_t *)arg = timer->timeout_tick; break; + case RT_TIMER_CTRL_GET_FUNC: + *(void **)arg = timer->timeout_func; + break; + + case RT_TIMER_CTRL_SET_FUNC: + timer->timeout_func = (void (*)(void*))arg; + break; + + case RT_TIMER_CTRL_GET_PARM: + *(void **)arg = timer->parameter; + break; + + case RT_TIMER_CTRL_SET_PARM: + timer->parameter = arg; + break; default: break; @@ -801,7 +819,7 @@ static void _timer_thread_entry(void *parameter) if (_timer_list_next_timeout(_soft_timer_list, &next_timeout) != RT_EOK) { /* no software timer exist, suspend self. */ - rt_thread_suspend(rt_thread_self()); + rt_thread_suspend_with_flag(rt_thread_self(), RT_UNINTERRUPTIBLE); rt_schedule(); } else |
