cpu.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /*
  2. * Copyright (c) 2006-2021, 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_SMP
  13. static struct rt_cpu rt_cpus[RT_CPUS_NR];
  14. rt_hw_spinlock_t _cpus_lock;
  15. /*
  16. * disable scheduler
  17. */
  18. static void rt_preempt_disable(void)
  19. {
  20. register rt_base_t level;
  21. struct rt_thread *current_thread;
  22. /* disable interrupt */
  23. level = rt_hw_local_irq_disable();
  24. current_thread = rt_thread_self();
  25. if (!current_thread)
  26. {
  27. rt_hw_local_irq_enable(level);
  28. return;
  29. }
  30. /* lock scheduler for local cpu */
  31. current_thread->scheduler_lock_nest ++;
  32. /* enable interrupt */
  33. rt_hw_local_irq_enable(level);
  34. }
  35. /*
  36. * enable scheduler
  37. */
  38. static void rt_preempt_enable(void)
  39. {
  40. register rt_base_t level;
  41. struct rt_thread *current_thread;
  42. /* disable interrupt */
  43. level = rt_hw_local_irq_disable();
  44. current_thread = rt_thread_self();
  45. if (!current_thread)
  46. {
  47. rt_hw_local_irq_enable(level);
  48. return;
  49. }
  50. /* unlock scheduler for local cpu */
  51. current_thread->scheduler_lock_nest --;
  52. rt_schedule();
  53. /* enable interrupt */
  54. rt_hw_local_irq_enable(level);
  55. }
  56. void rt_spin_lock_init(struct rt_spinlock *lock)
  57. {
  58. rt_hw_spin_lock_init(&lock->lock);
  59. }
  60. RTM_EXPORT(rt_spin_lock_init)
  61. void rt_spin_lock(struct rt_spinlock *lock)
  62. {
  63. rt_preempt_disable();
  64. rt_hw_spin_lock(&lock->lock);
  65. }
  66. RTM_EXPORT(rt_spin_lock)
  67. void rt_spin_unlock(struct rt_spinlock *lock)
  68. {
  69. rt_hw_spin_unlock(&lock->lock);
  70. rt_preempt_enable();
  71. }
  72. RTM_EXPORT(rt_spin_unlock)
  73. rt_base_t rt_spin_lock_irqsave(struct rt_spinlock *lock)
  74. {
  75. unsigned long level;
  76. rt_preempt_disable();
  77. level = rt_hw_local_irq_disable();
  78. rt_hw_spin_lock(&lock->lock);
  79. return level;
  80. }
  81. RTM_EXPORT(rt_spin_lock_irqsave)
  82. void rt_spin_unlock_irqrestore(struct rt_spinlock *lock, rt_base_t level)
  83. {
  84. rt_hw_spin_unlock(&lock->lock);
  85. rt_hw_local_irq_enable(level);
  86. rt_preempt_enable();
  87. }
  88. RTM_EXPORT(rt_spin_unlock_irqrestore)
  89. /**
  90. * This fucntion will return current cpu.
  91. */
  92. struct rt_cpu *rt_cpu_self(void)
  93. {
  94. return &rt_cpus[rt_hw_cpu_id()];
  95. }
  96. struct rt_cpu *rt_cpu_index(int index)
  97. {
  98. return &rt_cpus[index];
  99. }
  100. /**
  101. * This function will lock all cpus's scheduler and disable local irq.
  102. */
  103. rt_base_t rt_cpus_lock(void)
  104. {
  105. rt_base_t level;
  106. struct rt_cpu* pcpu;
  107. level = rt_hw_local_irq_disable();
  108. pcpu = rt_cpu_self();
  109. if (pcpu->current_thread != RT_NULL)
  110. {
  111. register rt_ubase_t lock_nest = pcpu->current_thread->cpus_lock_nest;
  112. pcpu->current_thread->cpus_lock_nest++;
  113. if (lock_nest == 0)
  114. {
  115. pcpu->current_thread->scheduler_lock_nest++;
  116. rt_hw_spin_lock(&_cpus_lock);
  117. }
  118. }
  119. return level;
  120. }
  121. RTM_EXPORT(rt_cpus_lock);
  122. /**
  123. * This function will restore all cpus's scheduler and restore local irq.
  124. */
  125. void rt_cpus_unlock(rt_base_t level)
  126. {
  127. struct rt_cpu* pcpu = rt_cpu_self();
  128. if (pcpu->current_thread != RT_NULL)
  129. {
  130. pcpu->current_thread->cpus_lock_nest--;
  131. if (pcpu->current_thread->cpus_lock_nest == 0)
  132. {
  133. pcpu->current_thread->scheduler_lock_nest--;
  134. rt_hw_spin_unlock(&_cpus_lock);
  135. }
  136. }
  137. rt_hw_local_irq_enable(level);
  138. }
  139. RTM_EXPORT(rt_cpus_unlock);
  140. /**
  141. * This function is invoked by scheduler.
  142. * It will restore the lock state to whatever the thread's counter expects.
  143. * If target thread not locked the cpus then unlock the cpus lock.
  144. */
  145. void rt_cpus_lock_status_restore(struct rt_thread *thread)
  146. {
  147. struct rt_cpu* pcpu = rt_cpu_self();
  148. pcpu->current_thread = thread;
  149. if (!thread->cpus_lock_nest)
  150. {
  151. rt_hw_spin_unlock(&_cpus_lock);
  152. }
  153. }
  154. RTM_EXPORT(rt_cpus_lock_status_restore);
  155. #endif /* RT_USING_SMP */