summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Kconfig22
-rw-r--r--src/SConscript3
-rw-r--r--src/cpu.c28
-rw-r--r--src/device.c83
-rw-r--r--src/driver.c113
-rw-r--r--src/ipc.c350
-rw-r--r--src/kservice.c87
-rw-r--r--src/object.c78
-rw-r--r--src/scheduler.c69
-rw-r--r--src/signal.c10
-rw-r--r--src/thread.c234
-rw-r--r--src/timer.c30
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')
diff --git a/src/cpu.c b/src/cpu.c
index 2371ec2e5b..5ac6ce82ca 100644
--- a/src/cpu.c
+++ b/src/cpu.c
@@ -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
+
diff --git a/src/ipc.c b/src/ipc.c
index 15853ff463..fa25ce73a1 100644
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -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