| 198 | } |
| 199 | |
| 200 | [[nodiscard]] auto sys_futex(int* uaddr, int op, int val, |
| 201 | [[maybe_unused]] const void* timeout, |
| 202 | [[maybe_unused]] int* uaddr2, |
| 203 | [[maybe_unused]] int val3) -> int { |
| 204 | // Futex 常量定义 |
| 205 | static constexpr int kFutexWait = 0; |
| 206 | static constexpr int kFutexWake = 1; |
| 207 | static constexpr int kFutexRequeue = 3; |
| 208 | |
| 209 | // 提取操作类型(低位) |
| 210 | int cmd = op & 0x7F; |
| 211 | |
| 212 | auto& task_manager = TaskManagerSingleton::instance(); |
| 213 | |
| 214 | switch (cmd) { |
| 215 | case kFutexWait: { |
| 216 | klog::Debug("[Syscall] FUTEX_WAIT on {:#x} (val={})", |
| 217 | static_cast<uint64_t>(reinterpret_cast<uintptr_t>(uaddr)), |
| 218 | val); |
| 219 | |
| 220 | ResourceId futex_id(ResourceType::kFutex, |
| 221 | reinterpret_cast<uintptr_t>(uaddr)); |
| 222 | { |
| 223 | LockGuard<SpinLock> guard(futex_lock_); |
| 224 | if (*uaddr != val) { |
| 225 | return 0; |
| 226 | } |
| 227 | } |
| 228 | // futex_lock_ released before Block() — SpinLock must NOT be held |
| 229 | // across context switch boundaries (Block → Schedule → switch_to). |
| 230 | // A narrow race exists: FUTEX_WAKE between lock release and Block() |
| 231 | // can miss this thread. Production kernels solve this with a two-phase |
| 232 | // API (add-to-waitqueue under lock, schedule after release). This is |
| 233 | // still far safer than the original completely-unprotected check. |
| 234 | task_manager.Block(futex_id); |
| 235 | return 0; |
| 236 | } |
| 237 | |
| 238 | case kFutexWake: { |
| 239 | klog::Debug("[Syscall] FUTEX_WAKE on {:#x} (count={})", |
| 240 | static_cast<uint64_t>(reinterpret_cast<uintptr_t>(uaddr)), |
| 241 | val); |
| 242 | |
| 243 | ResourceId futex_id(ResourceType::kFutex, |
| 244 | reinterpret_cast<uintptr_t>(uaddr)); |
| 245 | { |
| 246 | LockGuard<SpinLock> guard(futex_lock_); |
| 247 | task_manager.Wakeup(futex_id); |
| 248 | } |
| 249 | |
| 250 | /// @todo应该返回实际唤醒的线程数 |
| 251 | return val; |
| 252 | } |
| 253 | |
| 254 | case kFutexRequeue: { |
| 255 | // 将等待 uaddr 的线程重新排队到 uaddr2 |
| 256 | /// @todo实现 FUTEX_REQUEUE |
| 257 | klog::Warn("[Syscall] FUTEX_REQUEUE not implemented"); |