cpu.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  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-10-30 Bernard The first version
  9. */
  10. #include <rthw.h>
  11. #include <rtthread.h>
  12. #ifdef RT_USING_USERSPACE
  13. #include <lwp.h>
  14. #endif
  15. #ifdef RT_USING_SMP
  16. static struct rt_cpu rt_cpus[RT_CPUS_NR];
  17. rt_hw_spinlock_t _cpus_lock;
  18. /*
  19. * disable scheduler
  20. */
  21. static void rt_preempt_disable(void)
  22. {
  23. register rt_base_t level;
  24. struct rt_thread *current_thread;
  25. /* disable interrupt */
  26. level = rt_hw_local_irq_disable();
  27. current_thread = rt_thread_self();
  28. if (!current_thread)
  29. {
  30. rt_hw_local_irq_enable(level);
  31. return;
  32. }
  33. /* lock scheduler for local cpu */
  34. current_thread->scheduler_lock_nest ++;
  35. /* enable interrupt */
  36. rt_hw_local_irq_enable(level);
  37. }
  38. /*
  39. * enable scheduler
  40. */
  41. static void rt_preempt_enable(void)
  42. {
  43. register rt_base_t level;
  44. struct rt_thread *current_thread;
  45. /* disable interrupt */
  46. level = rt_hw_local_irq_disable();
  47. current_thread = rt_thread_self();
  48. if (!current_thread)
  49. {
  50. rt_hw_local_irq_enable(level);
  51. return;
  52. }
  53. /* unlock scheduler for local cpu */
  54. current_thread->scheduler_lock_nest --;
  55. rt_schedule();
  56. /* enable interrupt */
  57. rt_hw_local_irq_enable(level);
  58. }
  59. #endif /* end of RT_USING_SMP */
  60. void rt_spin_lock_init(struct rt_spinlock *lock)
  61. {
  62. #ifdef RT_USING_SMP
  63. rt_hw_spin_lock_init(&lock->lock);
  64. #endif
  65. }
  66. RTM_EXPORT(rt_spin_lock_init)
  67. void rt_spin_lock(struct rt_spinlock *lock)
  68. {
  69. #ifdef RT_USING_SMP
  70. rt_preempt_disable();
  71. rt_hw_spin_lock(&lock->lock);
  72. #else
  73. rt_enter_critical();
  74. #endif
  75. }
  76. RTM_EXPORT(rt_spin_lock)
  77. void rt_spin_unlock(struct rt_spinlock *lock)
  78. {
  79. #ifdef RT_USING_SMP
  80. rt_hw_spin_unlock(&lock->lock);
  81. rt_preempt_enable();
  82. #else
  83. rt_exit_critical();
  84. #endif
  85. }
  86. RTM_EXPORT(rt_spin_unlock)
  87. rt_base_t rt_spin_lock_irqsave(struct rt_spinlock *lock)
  88. {
  89. #ifdef RT_USING_SMP
  90. unsigned long level;
  91. rt_preempt_disable();
  92. level = rt_hw_local_irq_disable();
  93. rt_hw_spin_lock(&lock->lock);
  94. return level;
  95. #else
  96. return rt_hw_interrupt_disable();
  97. #endif
  98. }
  99. RTM_EXPORT(rt_spin_lock_irqsave)
  100. void rt_spin_unlock_irqrestore(struct rt_spinlock *lock, rt_base_t level)
  101. {
  102. #ifdef RT_USING_SMP
  103. rt_hw_spin_unlock(&lock->lock);
  104. rt_hw_local_irq_enable(level);
  105. rt_preempt_enable();
  106. #else
  107. rt_hw_interrupt_enable(level);
  108. #endif
  109. }
  110. RTM_EXPORT(rt_spin_unlock_irqrestore)
  111. /**
  112. * This function will return current cpu.
  113. */
  114. struct rt_cpu *rt_cpu_self(void)
  115. {
  116. return &rt_cpus[rt_hw_cpu_id()];
  117. }
  118. struct rt_cpu *rt_cpu_index(int index)
  119. {
  120. return &rt_cpus[index];
  121. }
  122. /**
  123. * This function will lock all cpus's scheduler and disable local irq.
  124. */
  125. rt_base_t rt_cpus_lock(void)
  126. {
  127. rt_base_t level;
  128. struct rt_cpu* pcpu;
  129. level = rt_hw_local_irq_disable();
  130. pcpu = rt_cpu_self();
  131. if (pcpu->current_thread != RT_NULL)
  132. {
  133. register rt_ubase_t lock_nest = pcpu->current_thread->cpus_lock_nest;
  134. pcpu->current_thread->cpus_lock_nest++;
  135. if (lock_nest == 0)
  136. {
  137. pcpu->current_thread->scheduler_lock_nest++;
  138. rt_hw_spin_lock(&_cpus_lock);
  139. }
  140. }
  141. return level;
  142. }
  143. RTM_EXPORT(rt_cpus_lock);
  144. /**
  145. * This function will restore all cpus's scheduler and restore local irq.
  146. */
  147. void rt_cpus_unlock(rt_base_t level)
  148. {
  149. struct rt_cpu* pcpu = rt_cpu_self();
  150. if (pcpu->current_thread != RT_NULL)
  151. {
  152. pcpu->current_thread->cpus_lock_nest--;
  153. if (pcpu->current_thread->cpus_lock_nest == 0)
  154. {
  155. pcpu->current_thread->scheduler_lock_nest--;
  156. rt_hw_spin_unlock(&_cpus_lock);
  157. }
  158. }
  159. rt_hw_local_irq_enable(level);
  160. }
  161. RTM_EXPORT(rt_cpus_unlock);
  162. /**
  163. * This function is invoked by scheduler.
  164. * It will restore the lock state to whatever the thread's counter expects.
  165. * If target thread not locked the cpus then unlock the cpus lock.
  166. */
  167. void rt_cpus_lock_status_restore(struct rt_thread *thread)
  168. {
  169. struct rt_cpu* pcpu = rt_cpu_self();
  170. #ifdef RT_USING_USERSPACE
  171. if (pcpu->current_thread)
  172. {
  173. pcpu->current_thread->thread_idr = rt_cpu_get_thread_idr();
  174. }
  175. lwp_mmu_switch(thread);
  176. rt_cpu_set_thread_idr(thread->thread_idr);
  177. #endif
  178. pcpu->current_thread = thread;
  179. if (!thread->cpus_lock_nest)
  180. {
  181. rt_hw_spin_unlock(&_cpus_lock);
  182. }
  183. }
  184. RTM_EXPORT(rt_cpus_lock_status_restore);