use super::UPIntrFreeCell;
use alloc::collections::VecDeque;
use tg_task_manage::ThreadId;

// 教程说明：
// `count` 含义采用经典信号量语义：
// - count >= 0：可用资源数；
// - count < 0：有 `-count` 个线程在等待队列中。

/// Semaphore
pub struct Semaphore {
    /// UPIntrFreeCell<SemaphoreInner>
    pub inner: UPIntrFreeCell<SemaphoreInner>,
}

/// SemaphoreInner
pub struct SemaphoreInner {
    pub count: isize,
    pub wait_queue: VecDeque<ThreadId>,
}

impl Semaphore {
    /// 创建一个新的信号量，初始资源计数为 `res_count`。
    pub fn new(res_count: usize) -> Self {
        Self {
            // SAFETY: 此信号量仅在单处理器内核环境中使用
            inner: unsafe {
                UPIntrFreeCell::new(SemaphoreInner {
                    count: res_count as isize,
                    wait_queue: VecDeque::new(),
                })
            },
        }
    }
    /// 当前线程释放信号量表示的一个资源，并唤醒一个阻塞的线程
    pub fn up(&self) -> Option<ThreadId> {
        let mut inner = self.inner.exclusive_access();
        inner.count += 1;
        // 若有等待者，交由调度器唤醒队首线程。
        inner.wait_queue.pop_front()
    }
    /// 当前线程试图获取信号量表示的资源，并返回结果
    pub fn down(&self, tid: ThreadId) -> bool {
        let mut inner = self.inner.exclusive_access();
        inner.count -= 1;
        if inner.count < 0 {
            // 资源不足：当前线程进入等待队列。
            inner.wait_queue.push_back(tid);
            drop(inner);
            false
        } else {
            true
        }
    }
}
