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        semaphore::SemaphoreError::Interrupted => SyscallError::Interrupted,
56    })?;
57
58    let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
59    let cap = get_capability_manager().create_capability(
60        ResourceType::Semaphore,
61        sem_id.as_u64() as usize,
62        CapPermissions {
63            read: true,
64            write: true,
65            execute: false,
66            grant: true,
67            revoke: true,
68        },
69    );
70    let cap_id = unsafe { (&mut *task.process.capabilities.get()).insert(cap) };
71    Ok(cap_id.as_u64())
72}
73
74/// SYS_SEM_WAIT: decrement the semaphore (blocking if zero).
75pub fn sys_sem_wait(handle: u64) -> Result<u64, SyscallError> {
76    let sem_id = resolve_sem(handle, true)?;
77    semaphore::get_semaphore(sem_id)
78        .ok_or(SyscallError::BadHandle)?
79        .wait()
80        .map_err(|e| match e {
81            semaphore::SemaphoreError::WouldBlock => SyscallError::Again,
82            semaphore::SemaphoreError::Destroyed => SyscallError::Pipe,
83            semaphore::SemaphoreError::Interrupted => SyscallError::Interrupted,
84            _ => SyscallError::IoError,
85        })?;
86    Ok(0)
87}
88
89/// SYS_SEM_TRYWAIT: non-blocking decrement.
90pub fn sys_sem_trywait(handle: u64) -> Result<u64, SyscallError> {
91    let sem_id = resolve_sem(handle, true)?;
92    match semaphore::get_semaphore(sem_id)
93        .ok_or(SyscallError::BadHandle)?
94        .try_wait()
95    {
96        Ok(()) => Ok(0),
97        Err(semaphore::SemaphoreError::WouldBlock) => Err(SyscallError::Again),
98        Err(_) => Err(SyscallError::IoError),
99    }
100}
101
102/// SYS_SEM_POST: increment the semaphore (wake a waiter).
103pub fn sys_sem_post(handle: u64) -> Result<u64, SyscallError> {
104    let sem_id = resolve_sem(handle, true)?;
105    semaphore::get_semaphore(sem_id)
106        .ok_or(SyscallError::BadHandle)?
107        .post()
108        .map_err(|e| match e {
109            semaphore::SemaphoreError::WouldBlock => SyscallError::Again,
110            semaphore::SemaphoreError::Destroyed => SyscallError::Pipe,
111            _ => SyscallError::IoError,
112        })?;
113    Ok(0)
114}
115
116/// SYS_SEM_CLOSE: destroy a semaphore.
117pub fn sys_sem_close(handle: u64) -> Result<u64, SyscallError> {
118    crate::silo::enforce_cap_for_current_task(handle)?;
119    let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
120    let caps = unsafe { &mut *task.process.capabilities.get() };
121    let cap = caps
122        .get(CapId::from_raw(handle))
123        .ok_or(SyscallError::BadHandle)?;
124    if cap.resource_type != ResourceType::Semaphore {
125        return Err(SyscallError::BadHandle);
126    }
127    let sem_id = SemId::from_u64(cap.resource as u64);
128
129    let cap = caps
130        .remove(CapId::from_raw(handle))
131        .ok_or(SyscallError::BadHandle)?;
132
133    crate::capability::release_capability(&cap, Some(task.id));
134    let _ = semaphore::destroy_semaphore(sem_id);
135    Ok(0)
136}