1 /* 2 * Copyright (c) 2006-2018, RT-Thread Development Team 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Change Logs: 7 * Date Author Notes 8 * 2018/06/26 Bernard Fix the wait queue issue when wakeup a soon 9 * to blocked thread. 10 */ 11 12 #include <stdint.h> 13 14 #include <rthw.h> 15 #include <rtdevice.h> 16 #include <rtservice.h> 17 18 void rt_wqueue_add(rt_wqueue_t *queue, struct rt_wqueue_node *node) 19 { 20 rt_base_t level; 21 22 level = rt_hw_interrupt_disable(); 23 rt_list_insert_before(&(queue->waiting_list), &(node->list)); 24 rt_hw_interrupt_enable(level); 25 } 26 27 void rt_wqueue_remove(struct rt_wqueue_node *node) 28 { 29 rt_base_t level; 30 31 level = rt_hw_interrupt_disable(); 32 rt_list_remove(&(node->list)); 33 rt_hw_interrupt_enable(level); 34 } 35 36 int __wqueue_default_wake(struct rt_wqueue_node *wait, void *key) 37 { 38 return 0; 39 } 40 41 void rt_wqueue_wakeup(rt_wqueue_t *queue, void *key) 42 { 43 rt_base_t level; 44 register int need_schedule = 0; 45 46 rt_list_t *queue_list; 47 struct rt_list_node *node; 48 struct rt_wqueue_node *entry; 49 50 queue_list = &(queue->waiting_list); 51 52 level = rt_hw_interrupt_disable(); 53 /* set wakeup flag in the queue */ 54 queue->flag = RT_WQ_FLAG_WAKEUP; 55 56 if (!(rt_list_isempty(queue_list))) 57 { 58 for (node = queue_list->next; node != queue_list; node = node->next) 59 { 60 entry = rt_list_entry(node, struct rt_wqueue_node, list); 61 if (entry->wakeup(entry, key) == 0) 62 { 63 rt_thread_resume(entry->polling_thread); 64 need_schedule = 1; 65 66 rt_wqueue_remove(entry); 67 break; 68 } 69 } 70 } 71 rt_hw_interrupt_enable(level); 72 73 if (need_schedule) 74 rt_schedule(); 75 } 76 77 int rt_wqueue_wait(rt_wqueue_t *queue, int condition, int msec) 78 { 79 int tick; 80 rt_thread_t tid = rt_thread_self(); 81 rt_timer_t tmr = &(tid->thread_timer); 82 struct rt_wqueue_node __wait; 83 rt_base_t level; 84 85 /* current context checking */ 86 RT_DEBUG_NOT_IN_INTERRUPT; 87 88 tick = rt_tick_from_millisecond(msec); 89 90 if ((condition) || (tick == 0)) 91 return 0; 92 93 __wait.polling_thread = rt_thread_self(); 94 __wait.key = 0; 95 __wait.wakeup = __wqueue_default_wake; 96 rt_list_init(&__wait.list); 97 98 level = rt_hw_interrupt_disable(); 99 if (queue->flag == RT_WQ_FLAG_WAKEUP) 100 { 101 /* already wakeup */ 102 goto __exit_wakeup; 103 } 104 105 rt_wqueue_add(queue, &__wait); 106 rt_thread_suspend(tid); 107 108 /* start timer */ 109 if (tick != RT_WAITING_FOREVER) 110 { 111 rt_timer_control(tmr, 112 RT_TIMER_CTRL_SET_TIME, 113 &tick); 114 115 rt_timer_start(tmr); 116 } 117 rt_hw_interrupt_enable(level); 118 119 rt_schedule(); 120 121 level = rt_hw_interrupt_disable(); 122 123 __exit_wakeup: 124 queue->flag = 0; 125 rt_hw_interrupt_enable(level); 126 127 rt_wqueue_remove(&__wait); 128 129 return 0; 130 } 131