Skip to main content

strat9_kernel/syscall/
semaphore.rs

1//! Semaphore syscall handlers.
2//!
3//! Provides capability-enforced semaphore operations: create, wait, try_wait,
4//! post, close.
5
6use super::error::SyscallError;
7use crate::{
8    capability::{get_capability_manager, CapId, CapPermissions, ResourceType},
9    ipc::semaphore::{self, SemId},
10    process::current_task_clone,
11};
12
13fn resolve_sem(handle: u64, require_write: bool) -> Result<SemId, SyscallError> {
14    crate::silo::enforce_cap_for_current_task(handle)?;
15    let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
16    let caps = unsafe { &*task.process.capabilities.get() };
17    let required = if require_write {
18        CapPermissions {
19            read: false,
20            write: true,
21            execute: false,
22            grant: false,
23            revoke: false,
24        }
25    } else {
26        CapPermissions {
27            read: true,
28            write: false,
29            execute: false,
30            grant: false,
31            revoke: false,
32        }
33    };
34    let cap = caps
35        .get_with_permissions(CapId::from_raw(handle), required)
36        .ok_or(SyscallError::PermissionDenied)?;
37    if cap.resource_type != ResourceType::Semaphore {
38        return Err(SyscallError::BadHandle);
39    }
40    let sem_id = SemId::from_u64(cap.resource as u64);
41    if semaphore::get_semaphore(sem_id).is_none() {
42        return Err(SyscallError::BadHandle);
43    }
44    Ok(sem_id)
45}
46
47/// SYS_SEM_CREATE: create a semaphore with an initial count.
48pub fn sys_sem_create(initial: u64) -> Result<u64, SyscallError> {
49    let initial = u32::try_from(initial).map_err(|_| SyscallError::InvalidArgument)?;
50    let sem_id = semaphore::create_semaphore(initial).map_err(|e| match e {
51        semaphore::SemaphoreError::InvalidValue => SyscallError::InvalidArgument,
52        semaphore::SemaphoreError::WouldBlock => SyscallError::Again,
53        semaphore::SemaphoreError::Destroyed => SyscallError::Pipe,
54        semaphore::SemaphoreError::NotFound => SyscallError::NotFound,
55    })?;
56
57    let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
58    let cap = get_capability_manager().create_capability(
59        ResourceType::Semaphore,
60        sem_id.as_u64() as usize,
61        CapPermissions {
62            read: true,
63            write: true,
64            execute: false,
65            grant: true,
66            revoke: true,
67        },
68    );
69    let cap_id = unsafe { (&mut *task.process.capabilities.get()).insert(cap) };
70    Ok(cap_id.as_u64())
71}
72
73/// SYS_SEM_WAIT: decrement the semaphore (blocking if zero).
74pub fn sys_sem_wait(handle: u64) -> Result<u64, SyscallError> {
75    let sem_id = resolve_sem(handle, true)?;
76    semaphore::get_semaphore(sem_id)
77        .ok_or(SyscallError::BadHandle)?
78        .wait()
79        .map_err(|e| match e {
80            semaphore::SemaphoreError::WouldBlock => SyscallError::Again,
81            semaphore::SemaphoreError::Destroyed => SyscallError::Pipe,
82            _ => SyscallError::IoError,
83        })?;
84    Ok(0)
85}
86
87/// SYS_SEM_TRYWAIT: non-blocking decrement.
88pub fn sys_sem_trywait(handle: u64) -> Result<u64, SyscallError> {
89    let sem_id = resolve_sem(handle, true)?;
90    match semaphore::get_semaphore(sem_id)
91        .ok_or(SyscallError::BadHandle)?
92        .try_wait()
93    {
94        Ok(()) => Ok(0),
95        Err(semaphore::SemaphoreError::WouldBlock) => Err(SyscallError::Again),
96        Err(_) => Err(SyscallError::IoError),
97    }
98}
99
100/// SYS_SEM_POST: increment the semaphore (wake a waiter).
101pub fn sys_sem_post(handle: u64) -> Result<u64, SyscallError> {
102    let sem_id = resolve_sem(handle, true)?;
103    semaphore::get_semaphore(sem_id)
104        .ok_or(SyscallError::BadHandle)?
105        .post()
106        .map_err(|e| match e {
107            semaphore::SemaphoreError::WouldBlock => SyscallError::Again,
108            semaphore::SemaphoreError::Destroyed => SyscallError::Pipe,
109            _ => SyscallError::IoError,
110        })?;
111    Ok(0)
112}
113
114/// SYS_SEM_CLOSE: destroy a semaphore.
115pub fn sys_sem_close(handle: u64) -> Result<u64, SyscallError> {
116    crate::silo::enforce_cap_for_current_task(handle)?;
117    let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
118    let caps = unsafe { &mut *task.process.capabilities.get() };
119    let cap = caps
120        .get(CapId::from_raw(handle))
121        .ok_or(SyscallError::BadHandle)?;
122    if cap.resource_type != ResourceType::Semaphore {
123        return Err(SyscallError::BadHandle);
124    }
125    let sem_id = SemId::from_u64(cap.resource as u64);
126
127    let cap = caps
128        .remove(CapId::from_raw(handle))
129        .ok_or(SyscallError::BadHandle)?;
130
131    crate::capability::release_capability(&cap, Some(task.id));
132    let _ = semaphore::destroy_semaphore(sem_id);
133    Ok(0)
134}